「このモデルを動かす環境、もう一回作れますか?」——AIエンジニアが最も困る質問の一つだ。手作業で構築した環境は再現が難しく、開発・ステージング・本番で微妙に差が出る。IaC(Infrastructure as Code)でAI実行環境を管理することが、MLOpsの第一歩だ。
なぜAI環境にIaCが必要か
機械学習の実行環境は複雑だ。GPUドライバーのバージョン、CUDAのバージョン、Pythonライブラリの依存関係、ストレージの設定——これらが1つでも違えば、PoC環境で動いていたコードが本番で動かないことがある。
Terraformでインフラをコード化することで得られる利点は以下の通りだ。
- 再現性: 同じコードから何度でも同一環境を構築できる
- 差分管理:
terraform planで変更内容を事前確認できる - チームコラボレーション: Gitで環境定義を管理し、レビューが可能
- コスト管理: 不要になった環境を
terraform destroyで確実に削除できる
プロジェクト構成
terraform/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ └── prod/
│ ├── main.tf
│ ├── variables.tf
│ └── terraform.tfvars
└── modules/
├── sagemaker/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── s3/
└── iam/
環境(dev/prod)とモジュール(再利用可能なリソース定義)を分離することで、開発環境で試したコードをそのまま本番に適用できる。
AWS SageMakerのTerraform定義例
S3バケット(データ・モデル格納用)
# modules/s3/main.tf
resource "aws_s3_bucket" "ml_data" {
bucket = "${var.project_name}-ml-data-${var.environment}"
tags = {
Project = var.project_name
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket_versioning" "ml_data" {
bucket = aws_s3_bucket.ml_data.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "ml_data" {
bucket = aws_s3_bucket.ml_data.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
SageMaker Studio ドメイン
# modules/sagemaker/main.tf
resource "aws_sagemaker_domain" "ml_domain" {
domain_name = "${var.project_name}-${var.environment}"
auth_mode = "IAM"
vpc_id = var.vpc_id
subnet_ids = var.subnet_ids
default_user_settings {
execution_role = aws_iam_role.sagemaker_execution.arn
jupyter_server_app_settings {
default_resource_spec {
instance_type = "system"
}
}
kernel_gateway_app_settings {
default_resource_spec {
instance_type = var.kernel_instance_type
sagemaker_image_arn = var.sagemaker_image_arn
}
}
}
}
IAMロール(最小権限の原則)
# modules/iam/main.tf
resource "aws_iam_role" "sagemaker_execution" {
name = "${var.project_name}-sagemaker-execution-${var.environment}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "sagemaker.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy" "sagemaker_s3_access" {
name = "s3-access"
role = aws_iam_role.sagemaker_execution.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"]
Resource = "${aws_s3_bucket.ml_data.arn}/*"
},
{
Effect = "Allow"
Action = "s3:ListBucket"
Resource = aws_s3_bucket.ml_data.arn
}
]
})
}
Terraformのstate管理
チームで使う場合、terraform.tfstate をS3+DynamoDBで管理することが必須だ。
# backend.tf
terraform {
backend "s3" {
bucket = "your-terraform-state-bucket"
key = "ml-platform/terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
DynamoDBのロックテーブルにより、複数人が同時に terraform apply を実行してstateが壊れる問題を防げる。
CI/CDとの統合
GitHub ActionsでTerraformを自動実行する構成が増えている。PRをマージすると自動でステージング環境に適用され、承認後に本番に適用するフローが標準的だ。
# .github/workflows/terraform.yml
name: Terraform Apply
on:
push:
branches: [main]
paths: ['terraform/**']
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.7.0"
- name: Terraform Init
run: terraform init
working-directory: terraform/environments/prod
- name: Terraform Plan
run: terraform plan -out=tfplan
working-directory: terraform/environments/prod
- name: Terraform Apply
run: terraform apply tfplan
working-directory: terraform/environments/prod
IaCで管理されたML環境は、「誰かしか知らない環境」から「コードが知っている環境」に変わる。新メンバーの環境構築、本番トラブル時の環境再現、コスト最適化——すべてがコードで制御できるようになることが、MLOpsの土台だ。