背景
最近クラウド上で機械学習のパイプラインを実行するツールを調べていてMetaflowを試していました。
MetaflowをAWSなどクラウドへデプロイすることで、クラウド上でパイプラインの実行ができます。
Metaflowではデプロイ用のコードがいくつか配布されており、AWS Batchを使用するものや、Kubernetesを使う構成など、Metaflowの構成ごとに定義が用意されています。
実験としてAWS Batchを利用する構成を試していたのですが、
2025-11-06現在、安くデプロイしたい場合に特に気を付けておきたい設定があったので、注意点を残しておこうと思います。
前提
この記事では以下のバージョンを使用しています。
- terraform-aws-metaflow: v0.12.1
- Terraform: 1.6.6
- AWS Provider: 5.70.0
また、AWSのリージョンはap-northeast-1を使用しています。
Metaflowとは
Metaflowは、Netflixが開発しオープンソース化した機械学習パイプラインのフレームワークです。Pythonでデータサイエンスのワークフローを記述し、ローカル環境からAWS BatchやKubernetesなどのクラウド環境へシームレスに移行できます。
今回はAWS Batchを使った構成を試しました。
Metaflowのパイプライン
Metaflowではステップという単位でパイプラインをコード上で構築し、各ステップをクラウドまたはローカルのサーバ上でコンテナを使って実行できます。
以下はPythonでパイプラインを記述した例です。
from metaflow import step, FlowSpec
class HelloWorldFlow(FlowSpec):
@step
def start(self):
"""First step"""
print("This is the start step")
self.next(self.hello)
@step
def hello(self):
"""Just saying hi"""
self.my_greet_text = "Hello World!"
print(self.my_greet_text)
self.next(self.end)
@step
def end(self):
"""Finish line"""
print("This is the end step")
if __name__ == '__main__':
HelloWorldFlow()
パイプラインの実行例
$ uv run hello.py run
Metaflow 2.18.13 executing HelloWorldFlow for user:dninomiya
Validating your flow...
The graph looks good!
Running pylint...
Pylint not found, so extra checks are disabled.
2025-11-10 14:04:10.756 Workflow starting (run-id 1762751050751473):
2025-11-10 14:04:10.790 [1762751050751473/start/1 (pid 19416)] Task is starting.
2025-11-10 14:04:11.124 [1762751050751473/start/1 (pid 19416)] This is the start step
2025-11-10 14:04:11.178 [1762751050751473/start/1 (pid 19416)] Task finished successfully.
2025-11-10 14:04:11.194 [1762751050751473/hello/2 (pid 19436)] Task is starting.
2025-11-10 14:04:11.541 [1762751050751473/hello/2 (pid 19436)] Hello World!
2025-11-10 14:04:11.574 [1762751050751473/hello/2 (pid 19436)] Task finished successfully.
2025-11-10 14:04:11.587 [1762751050751473/end/3 (pid 19470)] Task is starting.
2025-11-10 14:04:11.873 [1762751050751473/end/3 (pid 19470)] This is the end step
2025-11-10 14:04:11.907 [1762751050751473/end/3 (pid 19470)] Task finished successfully.
2025-11-10 14:04:11.909 Done!
Terraform を使った Metaflow のデプロイの注意点
ここからはAWS Batchを使った構成で、安い維持費でインスタンスを立てるのにいくつか注意が必要なTerraformの設定を挙げておこうと思います。
要件やサービスのその時の価格によりますが、設定次第ではMetaflowの維持費を$60~70/月程度に抑えることができます。
ここからは特にお金がかかりやすい以下の3つの設定について説明します。
- RDSの設定
- UIの有効化設定
- トレーニングに使用するインスタンスの設定
RDSの設定
RDSはこの構成の中でも費用がかかるため、注意が必要です。
PostgreSQLのバージョン設定
特に、デフォルトで立つPostgreSQLのバージョン11が利用されるため、そのまま上げるとサポート切れバージョン用の追加費用がかかります。
variable "db_engine_version" {
type = string
default = "11" # デフォルトでは11になっている
}
料金を抑えたい場合は サポートのかからないバージョンを設定しましょう。
# バージョンを指定する際は公式のドキュメントを確認し、サポートの範囲に入っているか必ず確認しましょう
db_engine_version = 15
1ヶ月間のRDS PostgreSQL サポート延長料金
| DBインスタンス名 | 単価 | 数量 | 月額 |
|---|---|---|---|
| db.t2.small | $0.12/vCPU/時間 | 1 | $86.40 |
計算式:
- 1 vCPU × $0.12 × 24時間 × 30日 = $86.40
- 最新の料金は公式サイトをご参照ください
PostgreSQLバージョン変更に伴うDocker Imageの変更
また、Postgresのバージョンが15以上の場合、SSLを使った通信を行うようにTerraform内で設定されています。
以下のバージョンのDocker Imageがデフォルトで使われていますが、SSL通信に対応していないため、SSL通信に対応したDocker Imageを選択する必要があります。
locals {
default_metadata_service_container_image = "netflixoss/metaflow_metadata_service:v2.3.0" # v2.3.0ではSSL通信ができず、エラーが起きてしまった
...
}
module "metaflow" {
...
# PostgreSQL 15のSSL接続に対応した最新のメタデータサービスイメージを使用
metadata_service_container_image = "netflixoss/metaflow_metadata_service:v2.4.13"
...
}
RDSのマルチAZの設定
デフォルトではマルチAZ設定がtrueになっています。
可用性が減りますが、モジュールファイルを編集してfalseにすることで料金をさらに減らす事が可能です。
この設定はモジュール内で直接定義されているため、クローンしたモジュールファイルを編集する必要があります。
resource "aws_db_instance" "this" {
# ...
multi_az = true # デフォルトはtrue
# ...
}
コスト削減のため、以下のように変更します。
resource "aws_db_instance" "this" {
# ...
multi_az = false # 開発環境ではfalseに変更してコスト削減
# ...
}
注意: マルチAZを無効化すると、単一のAZに障害が発生した場合にRDSが利用できなくなります。本番環境ではtrueのままにすることを推奨します
UIの有効化設定
パイプラインの図やログをブラウザ上で見られるサーバをデプロイすることができます。
UI自体はオプションで、デプロイしなくてもMetaflowの機能を使うことができます。
デフォルトではUIをデプロイしない設定になっています。
variable "ui_certificate_arn" {
type = string
default = ""
description = "SSL certificate for UI. If set to empty string, UI is disabled. "
}
ui_certificate_arnを設定するとUIのサーバがECSでデプロイされますが、オンデマンド料金がかかるので注意が必要です。
Metaflowを実験として使用する場合、UIは必須ではないため、料金を抑えたい方はUIをオフにすることをお勧めします。
1ヶ月間UIを起動した際のECS Fargateの料金
UIではecs_ui_backendとecs_ui_staticの2つのサービスがデプロイされます。
それぞれ以下のような料金がかかります。
| コンポーネント | vCPU | メモリ(GB) | vCPU料金/月 | メモリ料金/月 | 合計/月 |
|---|---|---|---|---|---|
| ecs_ui_backend | 2.0 | 16 | $72.00 | $57.60 | $129.60 |
| ecs_ui_static | 0.5 | 1 | $18.00 | $3.60 | $21.60 |
計算式:
- vCPU料金 = vCPU数 × $0.05/時間 × 24時間 × 30日
- メモリ料金 = メモリGB × $0.005/時間 × 24時間 × 30日
- 値段が変わっている可能性があるため、詳細は公式サイトを参照してください
トレーニングに使用するインスタンスの設定
AWS Batchで利用するインスタンスの設定ができます。
デフォルトでは常時EC2インスタンスが立ち続けるため、維持費用が嵩みます。
また、AWS Batchで使うインスタンスを指定できます。
デフォルトでは以下のようになっています。
variable "compute_environment_desired_vcpus" {
type = number
description = "Desired Starting VCPUs for Batch Compute Environment [0-16] for EC2 Batch Compute Environment (ignored for Fargate)"
default = 8
}
variable "compute_environment_min_vcpus" {
type = number
description = "Minimum VCPUs for Batch Compute Environment [0-16] for EC2 Batch Compute Environment (ignored for Fargate)"
default = 8
}
variable "compute_environment_instance_types" {
type = list(string)
description = "The instance types for the compute environment"
default = ["c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge"]
}
以下のようにcompute_environment_min_vcpusとcompute_environment_desired_vcpusを0に設定することで、トレーニング時のみインスタンスが起動します。
compute_environment_min_vcpus = 0
compute_environment_desired_vcpus = 0
compute_environment_instance_types = [
"c5.large",
"g4dn.xlarge"
]
GPUのインスタンスの選択の際、機械学習用のコードがNVIDIAのGPU(cuda)を使う設定なら、g4dn.xlargeなどNVIDIAのGPUを積んだインスタンスを選択するといいかと思います。
1ヶ月間常時インスタンスを立てた場合の料金
仮にcompute_environment_min_vcpusとcompute_environment_desired_vcpusを0にせず、c4.2xlargeがデプロイされ続けるとすると、月に以下の料金がかかります。
| インスタンスタイプ | vCPU | メモリ | 時間単価 | 月額(24h×30日) |
|---|---|---|---|---|
| c4.2xlarge | 8 | 15 GB | $0.398 | $286.56 |
計算式:
- インスタンス料金 = $0.398/時間 × 24時間 × 30日
- 料金は変動する可能性があるため、最新の料金はAWS EC2料金ページをご確認ください
最終的なコード
これらのコスト最適化設定を実装したTerraform設定ファイルを以下に示します。
前準備
まず、terraform-aws-metaflowモジュールをクローンします。
git clone https://github.com/outerbounds/terraform-aws-metaflow.git
ディレクトリ構成
.
├── main.tf # メインの設定ファイル
├── variables.tf # 変数定義
├── provider.tf # AWSプロバイダー設定
├── versions.tf # バージョン制約
├── terraform.tfvars # 環境固有の設定値
└── terraform-aws-metaflow/ # Metaflowモジュール(cloneしたリポジトリ)
コード
main.tf
# リソース名の重複を避けるためのランダムなサフィックス
resource "random_string" "suffix" {
length = 8
special = false
upper = false
}
locals {
resource_prefix = "metaflow"
resource_suffix = random_string.suffix.result
}
data "aws_availability_zones" "available" {
}
data "aws_region" "current" {
}
# VPC の作成
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.1.2"
name = "${local.resource_prefix}-${local.resource_suffix}"
cidr = "10.10.0.0/16"
# 最小限の2つのAZ(RDSの要件を満たす最小構成)
# 本番環境ではセキュリティのためprivate_subnetsの使用を推奨
azs = slice(data.aws_availability_zones.available.names, 0, 2)
private_subnets = []
public_subnets = ["10.10.128.0/21", "10.10.136.0/21"]
# Public subnetを使用するため、NAT GatewayとPrivate subnetは不要
enable_nat_gateway = false
single_nat_gateway = false
enable_dns_hostnames = true
map_public_ip_on_launch = true
tags = {
"managedBy" = "terraform"
"project" = "metaflow"
}
}
# コスト最適化設定でMetaflowをデプロイ
module "metaflow" {
source = "./terraform-aws-metaflow"
resource_prefix = local.resource_prefix
resource_suffix = local.resource_suffix
# VPC設定
subnet1_id = module.vpc.public_subnets[0]
subnet2_id = module.vpc.public_subnets[1]
vpc_cidr_blocks = [module.vpc.vpc_cidr_block]
vpc_id = module.vpc.vpc_id
with_public_ip = true
# Step Functionsを無効化
enable_step_functions = false
# UI設定(デフォルトでは無効)
ui_certificate_arn = var.ui_certificate_arn
# PostgreSQL 15のSSL接続に対応した最新のメタデータサービスイメージを使用
metadata_service_container_image = "netflixoss/metaflow_metadata_service:v2.4.13"
# RDS PostgreSQLのバージョン設定
db_engine_version = var.db_engine_version
db_instance_type = var.db_instance_type
# AWS Batch - 必要時のみインスタンス起動
compute_environment_min_vcpus = var.compute_environment_min_vcpus
compute_environment_desired_vcpus = var.compute_environment_desired_vcpus
compute_environment_instance_types = var.compute_environment_instance_types
tags = {
"managedBy" = "terraform"
"environment" = "development"
"project" = "metaflow"
}
}
# Metaflowモジュールの全ての出力をエクスポート
output "metaflow" {
value = module.metaflow
sensitive = true
}
# Metaflow設定ファイルを出力
resource "local_file" "metaflow_config" {
content = module.metaflow.metaflow_profile_json
filename = "${path.module}/metaflow_profile.json"
}
variables.tf
# AWSリージョンの設定
variable "aws_region" {
type = string
description = "AWS region to deploy Metaflow infrastructure"
default = "us-east-1"
}
# RDSの設定
variable "db_engine_version" {
type = string
description = "PostgreSQL version for RDS. Use version 15+ to avoid extended support charges."
default = "15"
}
variable "db_instance_type" {
type = string
description = "RDS instance type. db.t3.micro is suitable for development/testing."
default = "db.t3.micro"
}
# AWS Batchの設定
variable "compute_environment_min_vcpus" {
type = number
description = "Minimum VCPUs. Set to 0 to avoid idle costs."
default = 0
}
variable "compute_environment_desired_vcpus" {
type = number
description = "Desired VCPUs. Set to 0 to avoid idle costs."
default = 0
}
variable "compute_environment_instance_types" {
type = list(string)
description = "Instance types for Batch compute environment. Include GPU instances if needed for ML workloads."
default = [
"c5.large",
"g4dn.xlarge"
]
}
# UI設定
variable "ui_certificate_arn" {
type = string
description = "SSL certificate ARN for UI. Leave empty to disable UI and save ~$151/month."
default = ""
}
provider.tf
provider "aws" {
region = "ap-northeast-1"
}
versions.tf
terraform {
required_version = ">= 0.13"
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.70.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.0"
}
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
}
}
terraform.tfvars
# PostgreSQL 15以上を使用すると、SSL接続が自動的に有効化されます
db_engine_version = "15"
db_instance_type = "db.t3.micro"
compute_environment_min_vcpus = 0
compute_environment_desired_vcpus = 0
compute_environment_instance_types = ["c5.large", "g4dn.xlarge"]
terraform-aws-metaflow/modules/datastore/rds.tf(マルチAZ設定の変更)
クローンしたモジュール内のファイルを編集します。114行目付近のmulti_azをfalseに変更してください。
resource "aws_db_instance" "this" {
...
multi_az = false # デフォルトはtrue、開発環境ではfalseに変更してコスト削減
...
}
デプロイ手順
# 初期化
terraform init
# デプロイ
terraform apply
終わりに
他にも追加で安価にする設定もいくつかありますが、これらの設定のコストが特に高いため、注意が必要です。
クラウド上で機械学習パイプラインを構築する際の参考になれば幸いです。