6ヶ月運用してわかった — GKE の本番環境での実態
Google Kubernetes Engine で本番ワークロードを運用して約6ヶ月が経った。経験は「嬉しい驚き」と「なぜ誰も教えてくれなかったのか」という瞬間の混在だった。最初のうちは、実際のトレードオフを省いたドキュメントを読みすぎて時間を無駄にしていた。このまとめは、あのとき読みたかった記事だ。
GKE を始める際の核心的な問いはシンプルだ:Autopilot か Standard か?答えは明白ではなく、間違った選択をすると、過剰な費用を払うか、最悪のタイミングで柔軟性を失うことになる。
アプローチ比較:GKE Autopilot vs Standard モード
GKE には根本的に異なる2つの運用モデルがあり、単なる機能の差ではなく、「誰が何を管理するか」という哲学の違いを表している。
Standard モード
ノードプールを自分でプロビジョニングして管理する。マシンタイプ、オートスケーリングのパラメータ、ディスクサイズ、ノード数を自分で決める。Kubernetes は設定通りに動作する。セルフマネージドのクラスターを運用した経験があれば、馴染みのある領域だ。
トレードオフ:ポッドがスケジュールされているかどうかに関わらず、予約したノードの容量分を支払う。e2-standard-4 マシン3台のノードプールは、たとえ深夜2時の実際のワークロードが 6 vCPU しか必要としなくても、24 vCPU と 96GB RAM のコストがかかる。
Autopilot モード
Google が基盤となるノードを完全に管理する。ポッドを定義するだけでよく、ノードプールもマシンタイプの選択も不要だ。課金はポッドの CPU/メモリリクエスト単位で、秒単位で切り上げられる。「自分が所有するノード」が存在しないため、アイドル状態のノード容量に費用はかからない。
トレードオフ:ノードの設定に対するコントロールを失う。一部の DaemonSet は動作せず、特権コンテナは制限され、特定のワークロード(GPU を多用する ML 推論など)は特別な対応が必要になる。
実際の比較数値
典型的な Web バックエンド(3つのマイクロサービス、中程度のトラフィック、ステージング+本番環境)を運用した場合の月額費用はこうなった:
Standard モード(3 × e2-standard-4、常時起動):
ノードコスト: ~$180/月(3ノード × $60)
実際の使用率: ~35-40% 平均 CPU 使用率
使用済み vCPU 時間あたりの実効コスト: ~2.8×
Autopilot モード(同じワークロード):
ポッドリクエスト: ~$110/月(リクエストした分だけ支払い)
節約: ~38%
24/7 で高使用率のワークロードを運用しないチームにとっては、コスト面で Autopilot が優位だ。ノード使用率が継続的に70%以上になった時点で、Standard が再び合理的な選択肢になる。
メリットとデメリット
GKE Autopilot
- メリット:ノード管理のオーバーヘッドなし — パッチ適用不要、キャパシティプランニング不要、「深夜3時になぜこのノードが NotReady なのか」問題もなし
- メリット:ポッド単位の課金でアイドル容量の無駄が解消される
- メリット:セキュリティ強化が組み込み済み(Workload Identity、シールドノード、バイナリ認証)
- デメリット:Autopilot が基盤インフラをプロビジョニングする必要がある場合、ポッドの起動が遅くなることがある(30〜60秒)
- デメリット:特権コンテナが使えない — 一部の監視エージェントやレガシーアプリが動作しない
- デメリット:最低リソースリクエストが強制される(コンテナあたり 0.25 vCPU、0.5GB RAM)— 小さな cronjob がパディングされる
GKE Standard
- メリット:ノード設定の完全なコントロール — GPU、カスタムマシンタイプ、Spot VM が使用可能
- メリット:ポッドのスケジューリングが速い(ノードがすでに起動済み)
- メリット:特権コンテナやカスタム DaemonSet を含む、あらゆるワークロードに対応
- デメリット:使用されていないノードの容量分も支払う
- デメリット:ノードのアップグレード、プール管理、キャパシティプランニングは自分の責任
- デメリット:設定ミスによってセキュリティ上の問題を引き起こしやすい
ほとんどのチームへの推奨セットアップ
実際の経験から言えば、これは習得すべき重要なスキルの一つだ:まず Autopilot から始めて、具体的な制約にぶつかったときだけ Standard に移行する。ほとんどのチームはその制約に到達しない。
典型的な Web アプリケーションチームには、このセットアップを推奨する:
- ステージングと本番の Web ワークロードには Autopilot を使用する
- タイミングが柔軟なバッチ/ML ジョブがある場合は Spot VM を使った Standard を検討する
- リソースリクエストは保守的かつ正確に設定する — Autopilot は実際の使用量ではなくリクエスト分を課金する
- 初日から Workload Identity を有効にする — 後から追加するのははるかに難しい
実装ガイド
ステップ 1:GKE Autopilot クラスターを作成する
# gcloud をインストールして設定する
gcloud init
gcloud auth application-default login
# 必要な API を有効にする
gcloud services enable container.googleapis.com
# Autopilot クラスターを作成する
gcloud container clusters create-auto my-app-cluster \
--location=asia-northeast1 \
--release-channel=regular
# 認証情報を取得する
gcloud container clusters get-credentials my-app-cluster \
--location=asia-northeast1
--release-channel=regular フラグを使うと、手動でアップグレードを管理しなくても安定した Kubernetes バージョンが利用できる。最新機能が欲しい場合は rapid、リスクを避けたい場合は stable を使用する。
ステップ 2:アプリケーションをデプロイする
基本的なデプロイマニフェストを作成する。Autopilot で重要なのは、常にリソースリクエストを設定することだ:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: gcr.io/PROJECT_ID/my-app:latest
ports:
- containerPort: 8080
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "1Gi"
---
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
kubectl apply -f deployment.yaml
kubectl get pods -w
ステップ 3:Cloud Build で CI/CD をセットアップする
Cloud Build は GKE とシームレスに統合でき、IAM の設定も最小限で済む。リポジトリのルートに cloudbuild.yaml を作成する:
# cloudbuild.yaml
steps:
# コンテナイメージをビルドする
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'gcr.io/$PROJECT_ID/my-app:$COMMIT_SHA'
- '.'
# Container Registry にプッシュする
- name: 'gcr.io/cloud-builders/docker'
args:
- 'push'
- 'gcr.io/$PROJECT_ID/my-app:$COMMIT_SHA'
# GKE にデプロイする
- name: 'gcr.io/cloud-builders/kubectl'
args:
- 'set'
- 'image'
- 'deployment/my-app'
- 'my-app=gcr.io/$PROJECT_ID/my-app:$COMMIT_SHA'
env:
- 'CLOUDSDK_COMPUTE_REGION=asia-northeast1'
- 'CLOUDSDK_CONTAINER_CLUSTER=my-app-cluster'
images:
- 'gcr.io/$PROJECT_ID/my-app:$COMMIT_SHA'
Cloud Build トリガーを使って GitHub リポジトリに接続する:
# Cloud Build に GKE へのデプロイ権限を付与する
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$(gcloud projects describe $PROJECT_ID \
--format='value(projectNumber)')@cloudbuild.gserviceaccount.com" \
--role="roles/container.developer"
# トリガーを作成する(またはコンソール UI から行う)
gcloud builds triggers create github \
--repo-name=my-app \
--repo-owner=my-github-username \
--branch-pattern='^main$' \
--build-config=cloudbuild.yaml
main へのプッシュのたびに自動的に再ビルド・再デプロイされる。ビルド、プッシュ、ロールアウトを含むパイプライン全体は、小規模な Go または Node.js サービスなら通常3分以内で完了する。
ステップ 4:コスト最適化 — 重要な数値
クラスターが稼働したら、アプリケーションの動作に影響を与えずに請求額を大幅に削減できる3つの調整がある:
リソースリクエストを適切なサイズに調整する。アプリを1週間負荷をかけて運用した後、実際の使用量を確認する:
# リクエストに対する実際の CPU/メモリ使用量を確認する
kubectl top pods --sort-by=cpu
# GKE 組み込みの Vertical Pod Autoscaler から推奨設定を取得する
kubectl describe vpa my-app
Horizontal Pod Autoscaler を有効にする。オフピーク時間帯に自動でスケールダウンする:
kubectl autoscale deployment my-app \
--cpu-percent=60 \
--min=1 \
--max=10
確約利用割引を活用する。1ヶ月間運用してベースラインの使用量が安定してきたら、1年間の確約利用割引によって Autopilot ポッドのオンデマンド料金を37%削減できる。私の場合、これだけで2ヶ月以内に元が取れた。
やり直すなら変えること
最初から古い Container Registry(gcr.io)ではなく Artifact Registry をセットアップする。より優れた IAM コントロール、リージョナルストレージ、脆弱性スキャンが組み込まれている。後でコンテナイメージの URL を移行するということは、すべてのデプロイマニフェストと CI 設定を更新することを意味する — 難しくはないが、面倒だ。
# Artifact Registry リポジトリを作成する
gcloud artifacts repositories create my-app-repo \
--repository-format=docker \
--location=asia-northeast1
# イメージ URL の形式
# asia-northeast1-docker.pkg.dev/PROJECT_ID/my-app-repo/my-app:tag
次のステップ
上記のセットアップを行えば、午後の半日で動作するコスト最適化済みの GKE デプロイと自動化された CI/CD が手に入る。この基盤から、自然な次のステップは適切な Ingress コントローラーの追加(GKE マネージドのものは Autopilot で良好に動作する)、名前空間ベースの環境分離のセットアップ、アラート用の Cloud Monitoring の組み込みだ。
特に Autopilot は、どれだけ運用オーバーヘッドを排除できるかで驚かされ続けている — 6ヶ月間で、ノードレベルのインシデントはゼロだった。それだけでも、セルフマネージドノードと比べてやや高い vCPU あたりのコストに十分値する。

