0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GKE】絶対にお金をかけたくない人向けの完全自動MLパイプライン構築術

Posted at

【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 "--- 完了 ---"

まとめ

この構成にすることで、以下を実現できました。

  1. 完全自動化: bash run_analysis.sh を叩いて寝るだけ。
  2. コスト最小化: 分析が走っている数時間分の Spot VM 料金のみ。待機コストゼロ。
  3. セキュア: ローカルPCに強い権限の鍵を持たせず、クラウド上で完結。

「たまにしか動かさないけど、動かすときはガッツリ計算リソースが欲しい」という個人開発者の方、ぜひこのPersistent / Ephemeral 分離パターンを試してみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?