- Published on
ハンズオンメモ Google Cloud Kubernetes Engine (GKE)
はじめに
この記事は以下書籍の勉強メモです。
知ったことメモ
自動モードVPCネットワークの有効化設定
resource "google_compute_network" "vpc" {
name = "gke-network"
auto_create_subnetworks = false # これ
}
- この設定により、サブネットを自動で作るか手動で作るかを決定する。
- trueにした時(=自動で作る)の挙動
- 全リージョンにサブネットを自動作成する。
- 各サブネットにはGoogleがあらかじめ定義した10.128.0.0/9 ブロック内のIPは荷が自動的に割り当てられる。
- 自動モード→カスタムモード(falseにした時)へ変更できるが、逆はできない。
- これ勉強以外で自動モードにする場面ってあるのか?
プライベートGoogleアクセス
resource "google_compute_subnetwork" "subnet" {
name = "gke-subnet"
region = "asia-northeast1"
network = google_compute_network.vpc.id
ip_cidr_range = "10.0.0.0/24"
private_ip_google_access = true # これ
}
- プライベートGoogleアクセスは、外部IPアドレスを持たないVM・GKEノードが、Googleのパブリックサービス(Cloud Storage, Big Query, Artifact Registryなど)のAPIエンドポイントにアクセスできるようにするために必要な設定。
- コンテナイメージのプル、ロギング、モニタリングなどにつかう
- NATはインターネット全般の出口を提供するが、プライベートGoogleアクセスはGoogle APIへの専用ルートを提供する。
GKSコントロールプレーン関連の定義まとめ
後述するソースのうち
ブロックの中で気になったところのみ触れる。
resource "google_container_cluster" "primary"ブロックの中身がわからなかったので、理解のために分解して整理してみる。ブロックの中で気になったところのみ触れる。
name = "cookbook-cluster"
location = "asia-northeast1"
locationにasia-northeast1を指定しており、Regional Clusterとなる。
コントロールプレーンが3つのゾーンに分散され、高い可用性が確保される。
コントロールプレーンが3つのゾーンに分散され、高い可用性が確保される。
# デフォルトノードプールを削除し、カスタムノードプールを使用する(推奨)
remove_default_node_pool = true
initial_node_count = 1
GKEは、クラスター作成時に自動的にデフォルトのノードプールを作成するが、
(感想) VPCの自動モードもそうだが、GCPはデフォルトで何かしら作る思想のリソースがあるのはなぜなのだろうか。
remove_default_node_poolでこれを即座に削除する。(感想) VPCの自動モードもそうだが、GCPはデフォルトで何かしら作る思想のリソースがあるのはなぜなのだろうか。
また、削除する場合も初期ノード数の定義が必要なためここでは1を設定している。
このハンズオンではgoogle_container_node_poolで別途ノードを定義している。
このハンズオンではgoogle_container_node_poolで別途ノードを定義している。
# VPC-native traffic routing (Alias IP)
networking_mode = "VPC_NATIVE"
ip_allocation_policy {
cluster_ipv4_cidr_block = "/16"
services_ipv4_cidr_block = "/22"
}
networking_modePod(コンテナ)に、VPCネットワーク内の正規のIPアドレスを直接割り当てる方式を指定する。
静的ルートテーブルを用いるルートベース方式よりも拡張性が高い。
ip_allocation_policyPod(/16)と Service(/22)に割り当てる IP アドレスの範囲(CIDR)を定義する。
これにより、PodがVPC内の正規のIPをもつことができ、他のVPCリソースとの通信がスムーズになる。
# Workload Identity (Azure AD Pod Identity / Workload Identity)
# GSAとKSAを連携させるための設定
workload_identity_config {
workload_pool = "cookbook-251226.svc.id.goog"
}
k8s上のサービスアカウント(KSA)にGoogle Cloudのサービスアカウント(GSA)の権限を安全に借用させるための機能。
基本情報と
やったこと
※書籍の該当章に書かれている内容を1つのハンズオンで確認できるようにGeminiでまとめ直したものです。
Chapter 6: Google Cloud Kubernetes Engine (GKE) Hands-on
このハンズオンでは、Google Cloud Kubernetes Engine (GKE) を使用して、スケーラブルでセキュアなコンテナ基盤を構築し、アプリケーションをデプロイする手順を学習します。
書籍にある「Zonal/Regional Cluster」「Autoscaling」「Application Deployment」のエッセンスを統合し、本番環境を意識した構成(Regional Cluster, Private Nodes, Autoscaling)を Terraform で構築します。
書籍にある「Zonal/Regional Cluster」「Autoscaling」「Application Deployment」のエッセンスを統合し、本番環境を意識した構成(Regional Cluster, Private Nodes, Autoscaling)を Terraform で構築します。
構成図
本ハンズオンで構築するリソース構成です。
組織ポリシー(外部 IP 禁止)に準拠するため、GKE ノードはプライベート IP のみを持ち、外部への通信は Cloud NAT を経由します。
組織ポリシー(外部 IP 禁止)に準拠するため、GKE ノードはプライベート IP のみを持ち、外部への通信は Cloud NAT を経由します。

前提条件
- Region:
asia-northeast1 - Tools: Windows Terminal (PowerShell), Cursor, Terraform, gcloud SDK
- Policy:
constraints/compute.vmExternalIpAccess(ノードへの外部 IP 付与禁止) が有効
作業ステップ
Step 0: 認証と初期設定
作業を開始する前に、Google Cloud への認証を行います。
- PowerShell を開き、以下のコマンドを実行します。
# ユーザー認証
gcloud auth login
# アプリケーションのデフォルト認証情報(ADC)の取得
# TerraformがGoogle Cloud APIを操作するために必要です
gcloud auth application-default login
- 作業用ディレクトリを作成します。
# 作業ディレクトリの作成
mkdir terraform
mkdir app
Step 1: Terraform ファイルの作成 (Network & GKE)
概要:
GKE クラスタとそれを支えるネットワークリソースを定義します。
書籍では Zonal と Regional を別々に扱っていますが、本番環境での可用性を考慮し、Regional Cluster (Azure AKS の Availability Zones 構成に相当) を採用します。また、組織ポリシーに従い、ノードに外部 IP を持たせないPrivate Cluster構成とします。
GKE クラスタとそれを支えるネットワークリソースを定義します。
書籍では Zonal と Regional を別々に扱っていますが、本番環境での可用性を考慮し、Regional Cluster (Azure AKS の Availability Zones 構成に相当) を採用します。また、組織ポリシーに従い、ノードに外部 IP を持たせないPrivate Cluster構成とします。
作成ファイル:
terraform/main.tfterraform {
required_version = ">= 1.0"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
provider "google" {
project = "cookbook-251226"
region = "asia-northeast1"
}
# ------------------------------------------------------------------------------
# Network Resources
# ------------------------------------------------------------------------------
# VPC Network (Azure VNet)
# default VPCは削除済みのため新規作成
resource "google_compute_network" "vpc" {
name = "gke-network"
auto_create_subnetworks = false
}
# Subnet
# Private Google Accessを有効にし、NATなしでもGoogle API (GCR等) へアクセス可能にする
resource "google_compute_subnetwork" "subnet" {
name = "gke-subnet"
region = "asia-northeast1"
network = google_compute_network.vpc.id
ip_cidr_range = "10.0.0.0/24"
private_ip_google_access = true
}
# Cloud Router & NAT (Azure NAT Gateway)
# Private Nodeがインターネット(Docker Hub等)へアクセスするために必要
resource "google_compute_router" "router" {
name = "gke-router"
region = "asia-northeast1"
network = google_compute_network.vpc.id
}
resource "google_compute_router_nat" "nat" {
name = "gke-nat"
router = google_compute_router.router.name
region = "asia-northeast1"
nat_ip_allocate_option = "AUTO_ONLY"
source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
log_config {
enable = true
filter = "ERRORS_ONLY"
}
}
# ------------------------------------------------------------------------------
# GKE Cluster Resources (Azure Kubernetes Service)
# ------------------------------------------------------------------------------
# Service Account for Nodes
# 最小権限の原則に従い、デフォルトのCompute Engine SAではなく専用SAを使用
resource "google_service_account" "gke_sa" {
account_id = "gke-node-sa"
display_name = "GKE Node Service Account"
}
# 必要な権限付与 (Monitoring, Logging, Artifact Registry Reader)
resource "google_project_iam_member" "gke_sa_roles" {
for_each = toset([
"roles/logging.logWriter",
"roles/monitoring.metricWriter",
"roles/monitoring.viewer",
"roles/artifactregistry.reader"
])
project = "cookbook-251226"
role = each.key
member = "serviceAccount:${google_service_account.gke_sa.email}"
}
# GKE Regional Cluster
# 書籍 6.2 Regional Cluster に相当
resource "google_container_cluster" "primary" {
name = "cookbook-cluster"
location = "asia-northeast1" # Regional Cluster (高可用性)
# 削除保護の無効化(ハンズオン環境のためfalseに設定)
deletion_protection = false
# デフォルトノードプールを削除し、カスタムノードプールを使用する(推奨)
remove_default_node_pool = true
initial_node_count = 1
network = google_compute_network.vpc.id
subnetwork = google_compute_subnetwork.subnet.id
# VPC-native traffic routing (Alias IP)
networking_mode = "VPC_NATIVE"
ip_allocation_policy {
cluster_ipv4_cidr_block = "/16"
services_ipv4_cidr_block = "/22"
}
# Private Cluster Config (組織ポリシー対応)
# ノードに外部IPを付与しない
private_cluster_config {
enable_private_nodes = true
enable_private_endpoint = false # コントロールプレーンにはパブリックアクセス可能とする(学習用)
master_ipv4_cidr_block = "172.16.0.0/28"
}
# Workload Identity (Azure AD Pod Identity / Workload Identity)
# GSAとKSAを連携させるための設定
workload_identity_config {
workload_pool = "cookbook-251226.svc.id.goog"
}
}
# Node Pool
# 書籍 6.3 Resizing a Cluster (Autoscaling) に相当
resource "google_container_node_pool" "primary_nodes" {
name = "primary-node-pool"
location = "asia-northeast1"
cluster = google_container_cluster.primary.name
# Autoscaling 設定
autoscaling {
min_node_count = 1
max_node_count = 3
}
# 初期ノード数(Autoscaling有効時は無視される場合があるが定義推奨)
node_count = 1
node_config {
# コスト最適化のため e2-medium (2 vCPU, 4GB) を使用
# 本番Javaアプリでは e2-standard-2 以上を推奨
machine_type = "e2-medium"
# 組織ポリシー constraints/compute.requireShieldedVm 対応
shielded_instance_config {
enable_secure_boot = true
enable_integrity_monitoring = true
}
# Google APIへのアクセススコープ
oauth_scopes = [
"https://www.googleapis.com/auth/cloud-platform"
]
service_account = google_service_account.gke_sa.email
# メタデータ保護
workload_metadata_config {
mode = "GKE_METADATA"
}
}
}
Tips:
Pod と Service の IP 帯域:
- Pod: アプリが動く最小単位。GKE では各 Pod に VPC 内で有効な IP が付与されるため、大量の Pod 作成に備えて広い帯域(
/16など)を割り当てます。- Service: 複数の Pod を束ねる仮想 IP(ロードバランサ)。Pod の IP が変わっても、Service の IP は固定されるため、安定した通信先として機能します。
- VPC ネイティブ: Pod の IP が VPC の正規の IP として扱われるため、VPC 内の他のリソース(VM や DB)から Pod へ直接ルーティングが可能になり、パフォーマンスと可視性が向上します。
Regional vs Zonal: Regional クラスタはコントロールプレーンとノードが複数ゾーンに分散されるため、単一ゾーン障害に耐えられます(SLA も向上)。ただし、ゾーン間通信コストが発生する可能性があります。 Standard vs Autopilot: 今回は書籍の内容(ノード管理、リサイズ)を学ぶため Standard モードを使用していますが、ノード管理不要な Autopilot (書籍 6.7) が現在のデフォルト推奨です。 Best Practice: GKE のセキュリティの概要
Step 2: リソースの作成
概要:
Terraform を使用して Google Cloud 上にリソースを展開します。API の有効化(Kubernetes Engine API)も Terraform の構成に含まれており、依存関係を考慮して順次作成されます。
Terraform を使用して Google Cloud 上にリソースを展開します。API の有効化(Kubernetes Engine API)も Terraform の構成に含まれており、依存関係を考慮して順次作成されます。
- Terraform ディレクトリに移動し、初期化と適用を行います。
# APIの有効化を確実にするため、事前にgcloudでも実行しておくとスムーズです
gcloud services enable container.googleapis.com
cd terraform
terraform init
terraform apply -auto-approve
Note: GKE クラスタの作成には 10 分〜15 分程度かかります。
Step 3: アプリケーションのデプロイ準備
概要:
クラスタ構築後、
クラスタ構築後、
kubectl コマンドを使用してクラスタへの接続設定を行います。- クラスタの認証情報を取得します。
# クラスタ認証情報の取得 (kubeconfigの更新)
gcloud container clusters get-credentials cookbook-cluster --region asia-northeast1
- ノードの状態を確認します。Regional クラスタのため、3 つのゾーンにノードが分散されている(または Autoscaler により調整されている)ことを確認します。
kubectl get nodes
Step 4: Java アプリケーションのデプロイ
概要:
書籍 6.5「Deploying a Spring Boot Java Application」に基づき、Java アプリケーションをデプロイします。
書籍では
書籍 6.5「Deploying a Spring Boot Java Application」に基づき、Java アプリケーションをデプロイします。
書籍では
Jib を使ってソースからビルドしていますが、ここではインフラ構築に焦点を当てるため、Google が提供するサンプルコンテナイメージを使用します。作成ファイル:
app/deployment.yaml# app/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-java
labels:
app: hello-java
spec:
replicas: 3
selector:
matchLabels:
app: hello-java
template:
metadata:
labels:
app: hello-java
spec:
containers:
- name: hello-java
# 書籍のSpring Bootアプリの代わりに軽量なサンプルを使用
image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "128Mi"
---
apiVersion: v1
kind: Service
metadata:
name: hello-java-lb
spec:
type: LoadBalancer # 外部ロードバランサを作成 (Azure Load Balancer相当)
selector:
app: hello-java
ports:
- port: 80
targetPort: 8080
protocol: TCP
- マニフェストを適用します。
cd ../app
kubectl apply -f deployment.yaml
CE 向け Tips:
- LoadBalancer Service: GKE で
type: LoadBalancerを指定すると、Google Cloud Load Balancer (L4) が自動的にプロビジョニングされます。- Multi-Cluster Ingress (MCI): 書籍 6.4 で紹介されている MCI は、複数のクラスタ(リージョン跨ぎなど)に対して単一の IP でルーティングを行う高度な機能です(Azure Front Door + AKS に近い構成)。これには GKE Enterprise (Anthos) の有効化が必要です。
Step 5: 動作確認
概要:
デプロイしたアプリケーションが正常に稼働し、外部からアクセスできることを確認します。
デプロイしたアプリケーションが正常に稼働し、外部からアクセスできることを確認します。
- Service の外部 IP アドレスが割り当てられるまで待ちます(数分かかる場合があります)。
# External-IP が表示されるまで監視
kubectl get service hello-java-lb --watch
- IP アドレス(例:
34.x.x.x)が表示されたら、Ctrl+Cで抜け、ブラウザまたは curl でアクセスします。
$serviceIp = kubectl get service hello-java-lb -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
Write-Host "Accessing http://$serviceIp"
Invoke-WebRequest -Uri "http://$serviceIp" -UseBasicParsing
期待される出力:
Hello, world! やホスト名などが含まれる HTML レスポンスが返ってくれば成功です。- Autoscaling の動作確認(オプション):
負荷をかけるか、Deployment のレプリカ数を増やしてノードが増えるか観察できますが、今回はリソース削除を優先します。
Step 6: リソースの削除
概要:
課金を防ぐため、作成したすべてのリソースを削除します。
課金を防ぐため、作成したすべてのリソースを削除します。
- Kubernetes リソース(Service/LoadBalancer)を削除します。
Terraform destroy だけでも消えますが、K8s 側で作られた LB リソースが残留するリスクを防ぐため、明示的に削除することを推奨します。
kubectl delete -f deployment.yaml
- Terraform でインフラを削除します。
Set-Location "d:\30.開発\20251229_GCP_Cookbook\Chapter6\terraform"
terraform destroy -auto-approve
エラーメモ
terraform apply
Error: Error waiting for creating GKE cluster:
│ - Not all instances running in IGM after 10.122220596s. Expected 1, running 0, transitioning 1. Current errors: [CONDITION_NOT_MET]: Instance 'gke-cookbook-cluster-default-pool-fafffcff-h5kv' creation failed: Constraint constraints/compute.requireShieldedVm violated for project projects/cookbook-251226. Secure Boot is not enabled in the 'shielded_instance_config' field. See https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints for more information
│ - Not all instances running in IGM after 14.501550931s. Expected 1, running 0, transitioning 1. Current errors: [CONDITION_NOT_MET]: Instance 'gke-cookbook-cluster-default-pool-d2cddbcc-mlfk' creation failed: Constraint constraints/compute.requireShieldedVm violated for project projects/cookbook-251226. Secure Boot is not enabled in the 'shielded_instance_config' field. See https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints for more information
│ - Not all instances running in IGM after 18.293067562s. Expected 1, running 0, transitioning 1. Current errors: [CONDITION_NOT_MET]: Instance 'gke-cookbook-cluster-default-pool-5fa00056-6qc2' creation failed: Constraint constraints/compute.requireShieldedVm violated for project projects/cookbook-251226. Secure Boot is not enabled in the 'shielded_instance_config' field. See https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints for more information.
│
│ with google_container_cluster.primary,
│ on main.tf line 90, in resource "google_container_cluster" "primary":
│ 90: resource "google_container_cluster" "primary" {
│
╵
組織ポリシー constraints/compute.requireShieldedVm が有効な環境において、GKE クラスタ作成時に**一時的に作成されるデフォルトのノードプールが Secure Boot 設定を満たしていないために発生している。
google_container_cluster 内に以下を追加して解消。 node_config {
shielded_instance_config {
enable_secure_boot = true
}
}