【GKE】「絶対にお金をかけたくない」個人のための、ケチケチ完全自動MLパイプライン構築術
はじめに
個人で金融市場(暗号資産)の分析や機械学習モデルの学習を行っています。
個人開発者にとって最大の敵は 「クラウド破産」 です。
GKE(Kubernetes)は便利ですが、常時起動しておけば何もしなくても月に数千円〜数万円が飛びます。
「定期的に学習は回したい。でも、1円たりとも無駄な金は払いたくない」
そんなケチケチ精神から生まれた、「必要な瞬間だけ存在し、終わったら即座に消滅する」 使い捨て解析パイプラインの構築レシピを紹介します。
全体像とディレクトリ構成
このプロジェクトは、インフラのライフサイクルに合わせて Terraform を「Persistent(永続)」と「Ephemeral(一時的)」の2つに分割しているのが特徴です。
.
├── k8s/
│ └── workflow.yaml # Argo Workflowsの定義
├── src/ # 学習ロジック(Pythonコード)
├── terraform/
│ ├── persistent/ # 初回のみ実行(Service Account, IAM, Bucket)
│ │ └── main.tf
│ └── ephemeral/ # 毎回実行・破棄(GKE, NodePool, Argo, WIF)
│ └── main.tf
├── run_analysis.sh # 全自動実行スクリプト
└── upload_to_gcs.sh # ソースコード同期用
1. Persistent 層 (初回のみ構築)
まずは「消さない」リソースを作ります。ここにはデータ(GCS/BigQuery)と、アイデンティティ(Service Account)が含まれます。
これらは維持費が非常に安い(ストレージ料金のみなど)ため、常時存在させます。
terraform/persistent/main.tf
# --- Google Service Account (GSA) ---
# アプリケーションが使うGCP上のID
resource "google_service_account" "app_sa" {
account_id = "chart-movement-sa"
display_name = "Chart Movement Detection App SA"
}
# --- IAM Roles ---
# GSAに必要な権限を付与
resource "google_project_iam_member" "bq_editor" {
project = var.project_id
role = "roles/bigquery.dataEditor"
member = "serviceAccount:${google_service_account.app_sa.email}"
}
resource "google_storage_bucket_iam_member" "bucket_admin" {
bucket = var.bucket_name
role = "roles/storage.objectAdmin"
member = "serviceAccount:${google_service_account.app_sa.email}"
}
2. Ephemeral 層 (毎回構築・破棄)
ここがコスト削減の肝です。一番お金のかかる Compute Resources (GKE) をここで定義します。
さらに、セキュリティの要である Workload Identity の紐付けもここで行います。
terraform/ephemeral/main.tf
# --- GKE Cluster ---
resource "google_container_cluster" "primary" {
name = var.cluster_name
location = var.zone
# NodePoolは別途定義するためデフォルトは削除
remove_default_node_pool = true
initial_node_count = 1
# Workload Identityの有効化
workload_identity_config {
workload_pool = "${var.project_id}.svc.id.goog"
}
}
# --- Spot Node Pool (コスト削減の要) ---
resource "google_container_node_pool" "spot_nodes" {
name = "spot-node-pool"
# ... (cluster設定) ...
autoscaling {
min_node_count = 0 # 重要:誰も使ってなければ0台にする
max_node_count = 5
}
node_config {
preemptible = true # 重要:Spotインスタンス(格安)
machine_type = "e2-standard-2"
# Workload Identityの設定
workload_metadata_config {
mode = "GKE_METADATA"
}
}
}
# --- Argo Workflows & Workload Identity Binding ---
# 既存のGSAを参照
data "google_service_account" "app_sa" {
account_id = "chart-movement-sa"
}
# Kubernetes上のService Account (KSA) を作成し、GSAと紐付ける
resource "kubernetes_service_account_v1" "workflow_runner" {
metadata {
name = "workflow-runner"
namespace = "argo"
annotations = {
"iam.gke.io/gcp-service-account" = data.google_service_account.app_sa.email
}
}
}
# GSA側からKSAへの権限借用を許可
resource "google_service_account_iam_member" "workload_identity_binding" {
service_account_id = data.google_service_account.app_sa.name
role = "roles/iam.workloadIdentityUser"
member = "serviceAccount:${var.project_id}.svc.id.goog[argo/workflow-runner]"
}
3. Argo Workflow 定義
Kubernetesのマニフェストでは、先ほど作った workflow-runner を指定するだけです。
APIキー(JSONファイル)のマウントは一切不要です。
k8s/workflow.yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: analysis-pipeline-
spec:
entrypoint: main
# 完了後、Podを削除してIPアドレス等のリソースを節約
podGC:
strategy: OnPodCompletion
# Spotインスタンスを活用するためのToleration
tolerations:
- key: "cloud.google.com/gke-spot"
operator: "Equal"
value: "true"
effect: "NoSchedule"
templates:
- name: main
container:
image: gcr.io/your-project/analysis-image:latest
# ここでService Accountを指定するだけでGCP権限が使える
serviceAccountName: workflow-runner
command: ["python", "main.py"]
4. 全自動実行スクリプト
最後に、これらすべてを指揮するシェルスクリプトです。
「インフラ構築 → 実行 → 破壊」を一気通貫で行います。
run_analysis.sh
#!/bin/bash
set -e
echo "--- 1. コードをGCSへアップロード ---"
bash upload_to_gcs.sh
echo "--- 2. Ephemeralインフラ構築(課金開始) ---"
cd terraform/ephemeral
# 自動承認で適用
terraform init
terraform apply -auto-approve
echo "--- 3. ワークフロー実行 ---"
# kubectlの設定取得
gcloud container clusters get-credentials chart-movement-cluster --zone asia-northeast1-a
# ワークフロー投入
WF_NAME=$(kubectl create -f ../../k8s/workflow.yaml -n argo -o jsonpath='{.metadata.name}')
echo "Workflow Launched: $WF_NAME"
# 完了までポーリング待機
echo "Waiting for completion..."
while true; do
PHASE=$(kubectl get workflow $WF_NAME -n argo -o jsonpath='{.status.phase}')
if [[ "$PHASE" == "Succeeded" || "$PHASE" == "Failed" ]]; then
echo "Finished with status: $PHASE"
break
fi
sleep 30
done
echo "--- 4. インフラ破壊(課金停止) ---"
# 成功しても失敗しても、必ずTerraform Destroyで消し去る
terraform destroy -auto-approve
echo "--- 完了 ---"
まとめ
この構成にすることで、以下を実現できました。
-
完全自動化:
bash run_analysis.shを叩いて寝るだけ。 - コスト最小化: 分析が走っている数時間分の Spot VM 料金のみ。待機コストゼロ。
- セキュア: ローカルPCに強い権限の鍵を持たせず、クラウド上で完結。
「たまにしか動かさないけど、動かすときはガッツリ計算リソースが欲しい」という個人開発者の方、ぜひこのPersistent / Ephemeral 分離パターンを試してみてください。