G-gen の佐々木です。当記事では Google Cloud ( 旧称 GCP ) の代表的サービスである Google Kubernetes Engine ( GKE ) の限定公開クラスタを、Terraform を使用して作成していきます。
前提知識
Google Kubernetes Engine とは
Google Kubernetes Engine (以下、GKE ) は、Google Cloud のインフラストラクチャ上に構築された マネージドな Kubernetes クラスタ を利用することができるサービスです。
サービスの詳細は以下の記事で解説しています。
Terraform とは
Terraform は Infrastructure as Code (IaC) を実現するオープンソースのツールです。
Terraform の概要は以下の記事で解説しています。
なぜ 検証用の GKE クラスタを Terraform で作成するのか
GKE クラスタを作成する際、設定できるパラメータの項目数は非常に多く、検証のたびに 同じ構成でクラスタを作成するのは非常に煩雑な作業 になります。
クラスタのパラメータ以外にも、クラスタを配置する VPC とサブネットの作成が必要となり、限定公開クラスタを使用したい場合は、以下のリソースも追加で必要となる場合があります。
- コントロールプレーンにプライベート IP で接続するための 踏み台 VM
- クラスタからインターネットにアクセスするための Cloud NAT
このように GKE クラスタ以外のリソースが増えてくると、環境の構築手順が煩雑になり、またクラスタが不要になった際に、リソースの削除漏れ が起こりやすくなります。
リソースの管理に Terraform を使用することによって、コマンド 1 つで すべてのリソースを一括で作成/削除する ことができます。
また、GKE では、Standard モードのクラスタであれば、ノードとして起動される Commpute Engine インスタンスの料金が常に発生します。
そして Standard モード、Autopilot モードのどちらであっても、クラスタ管理手数料 として $74.40 / 月
の料金が発生します (最初の 1 クラスタのみ条件を満たせば無料枠あり)。
簡単な検証目的の利用であれば、料金節約のためにこまめにクラスタを削除することが望ましいでしょう。
構成図
当記事では、限定公開の GKE クラスタを Autopilot モードで作成していきます。
GKE ノードが配置される VPC に踏み台 VM を作成し、踏み台から Kubernetes の管理操作を行えるようにします。
また、クラスタからインターネットにアクセスできるように、Cloud NAT を作成します。
Terraform のディレクトリ構成
ファイルを environments/
ディレクトリと modules/
ディレクトリに分けています。
root/ ├ environments/ │ └ test/ │ ├ main.tf │ ├ terraform.tfvars │ └ variables.tf └ modules/ ├ bastion.tf ├ gke.tf ├ nat.tf ├ outputs.tf ├ variables.tf └ vpc.tf
各 Google Cloud リソースを定義するモジュールを modules/
ディレクトリに集約し、environments/
ディレクトリ配下にある test/main.tf
から各モジュールを呼び出します。
同一構成の環境を異なる設定値で作成したい場合は、environments/
配下の test/
ディレクトリを複製し、terraform.tfvars
に記述されている設定値を書き換えます。
Terraform 詳細
environments/test/main.tf
terraform.tfvars
から変数を受け取り、modules/
配下にあるモジュールを呼び出して各リソースを作成します。
リソースの作成後、modules/outputs.tf
から受け取った出力を元に、作成した GKE クラスタに接続するためのコマンドをターミナルに出力します。
terraform { required_providers { google = { source = "hashicorp/google" version = ">= 4.0.0" } } required_version = ">= 1.3.0" backend "gcs" { # tfstate ファイルの保存先となる GCS バケット bucket = "tfstate" prefix = "gke-test" } } provider "google" {} module "modules" { source = "../../modules" # 変数を modules に渡す common = var.common vpc = var.vpc gke = var.gke bastion = var.bastion } # 全リソース作成後、GKE クラスタの接続コマンドを出力 output "command_to_connect_cluster" { value = "\n$ gcloud container clusters get-credentials ${module.modules.cluster_name} --region ${module.modules.cluster_location} --project ${module.modules.cluster_project}\n" }
environments/test/variables.tf および modules/variables.tf
変数を宣言するファイルで、変数の受け渡しのために environments/
側と modules/
側で同一のファイルを配置します。
変数をオブジェクト型で設定することで、リソースの種類ごとにパラメータをグループ分けすることができ、どのリソースに関するパラメータなのかが明瞭になります。
variable "common" { type = object ({ prefix = string # 固有のプレフィクス (任意の文字列) env = string # 環境名 ( dev、prod など) project = string # プロジェクト region = string # リージョン zone = string # ゾーン }) description = "リソース共通の設定値" } variable "vpc" { type = object ({ subnet_cidr = string # サブネットの CIDR 範囲 ( GKE ノード、踏み台ホストが使用する IP 範囲) }) description = "VPC の設定値" } variable "gke" { type = object ({ cluster_cidr = string # GKE Pod が使用する IP 範囲 service_cidr = string # GKE Service が使用する IP 範囲 master_cidr = string # コントロールプレーンが使用する IP 範囲 }) description = "GKE の設定値" } variable "bastion" { type = object ({ machine_type = string # 踏み台 VM のマシンタイプ ssh_sourcerange = string # 踏み台 VM に SSH アクセスできるソース IP 範囲 }) description = "踏み台 VM の設定値" }
environments/test/terraform.tfvars
variables.tf
で宣言した変数にパラメータを代入します。
同一の構成で別のクラスタを作成したい場合は、test/
ディレクトリを複製し、このファイルのパラメータを修正するだけで実現できるようにします。
common = { prefix = "ggen" env = "test" project = "myproject" region = "asia-northeast1" zone = "asia-northeast1-b" } vpc = { subnet_cidr = "192.168.100.0/24" } gke = { cluster_cidr = "172.16.0.0/16" service_cidr = "172.31.0.0/16" master_cidr = "192.168.200.0/28" } bastion = { machine_type = "e2-small" ssh_sourcerange = "35.235.240.0/20" # IAP の IP 範囲 }
modules/vpc.tf
GKE クラスタを配置する VPC リソースを作成します。
# GKE クラスタを作成する VPC resource "google_compute_network" "vpc_network" { project = var.common.project name = "vpc-${var.common.prefix}-${var.common.env}" auto_create_subnetworks = false } # GKE クラスタを作成するサブネット resource "google_compute_subnetwork" "subnet_asia_ne1" { project = var.common.project name = "subnet-${var.common.prefix}-${var.common.env}" ip_cidr_range = var.vpc.subnet_cidr region = var.common.region network = google_compute_network.vpc_network.id private_ip_google_access = true }
modules/gke.tf
限定公開の GKE クラスタを Autopilot モードで作成します。
resource "google_container_cluster" "primary" { project = var.common.project name = "cluster-${var.common.prefix}-${var.common.env}-autopilot" enable_autopilot = true # Autopilot モードでクラスタを作成 location = var.common.region network = google_compute_network.vpc_network.id subnetwork = google_compute_subnetwork.subnet_asia_ne1.id ip_allocation_policy { cluster_ipv4_cidr_block = var.gke.cluster_cidr services_ipv4_cidr_block = var.gke.service_cidr } # 限定公開クラスタの設定 private_cluster_config { enable_private_nodes = true enable_private_endpoint = true master_ipv4_cidr_block = var.gke.master_cidr } master_authorized_networks_config { # コントロールプレーンへのアクセスを許可する IP 範囲 cidr_blocks { cidr_block = var.vpc.subnet_cidr # ノードと踏み台が作られるサブネットからのアクセスを許可 } } }
modules/bastion.tf
コントロールプレーンに接続する踏み台 VM を作成します。
起動スクリプトを使用して、Kubernetes の管理操作に必要なコマンドと GKE のプラグインをインストールしています。
# 踏み台 VM が使用するサービスアカウント resource "google_service_account" "bastion" { project = var.common.project account_id = "sa-${var.common.prefix}-${var.common.env}" display_name = "Service Account for bastion-${var.common.prefix}-${var.common.env}" } # サービスアカウントにロールを付与 resource "google_project_iam_member" "bastion" { project = var.common.project role = "roles/container.developer" # Kubernetes Engine デベロッパー ロール member = "serviceAccount:${google_service_account.bastion.email}" } # 踏み台 VM resource "google_compute_instance" "bastion" { project = var.common.project name = "bastion-${var.common.prefix}-${var.common.env}" machine_type = var.bastion.machine_type zone = var.common.zone tags = ["ssh"] # ネットワークタグ boot_disk { initialize_params { image = "debian-cloud/debian-11" # OS イメージ } } network_interface { subnetwork_project = var.common.project network = google_compute_network.vpc_network.name # VPC subnetwork = google_compute_subnetwork.subnet_asia_ne1.name # サブネット access_config {} # パブリック IP を付与 } metadata = { enable-oslogin = "true" # OS Login を有効化 } # 起動スクリプトで kubectl と GKE のプラグインをインストール metadata_startup_script = <<EOF #!/bin/bash sudo apt update sudo apt install kubectl sudo apt install google-cloud-sdk-gke-gcloud-auth-plugin EOF service_account { email = google_service_account.bastion.email scopes = ["cloud-platform"] } } resource "google_compute_firewall" "ssh" { project = var.common.project name = "vpc-${var.common.prefix}-${var.common.env}-ssh-allow" network = google_compute_network.vpc_network.name allow { protocol = "tcp" ports = ["22"] } source_ranges = [ var.bastion.ssh_sourcerange ] target_tags = ["ssh"] }
modules/nat.tf
クラスタからインターネットアクセスするための Cloud NAT を作成します。
Cloud NAT を使用するためには Cloud Router が必要になるため、このモジュールで一緒に作成します、
# Cloud Router resource "google_compute_router" "router" { project = var.common.project name = "router-${var.common.prefix}-${var.common.env}" region = var.common.region network = google_compute_network.vpc_network.id } # Cloud NAT resource "google_compute_router_nat" "nat" { project = var.common.project name = "nat-${var.common.prefix}-${var.common.env}" router = google_compute_router.router.name region = google_compute_router.router.region nat_ip_allocate_option = "AUTO_ONLY" source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES" log_config { enable = true filter = "ERRORS_ONLY" } }
modules/outputs.tf
GKE クラスタの接続コマンドを出力するために必要なリソース情報を main.tf
に返します。
output "cluster_name" { value = google_container_cluster.primary.name } output "cluster_location" { value = google_container_cluster.primary.location } output "cluster_project" { value = google_container_cluster.primary.project }
Terraform の実行
terraform apply
コマンドは environments/test/
ディレクトリで実行します。
実行が完了すると、ターミナルに以下のような文字列が出力されます。
Apply complete! Resources: 9 added, 0 changed, 0 destroyed. Outputs: command_to_connect_cluster = <<EOT $ gcloud container clusters get-credentials cluster-ggen-test-autopilot --region asia-northeast1 --project myproject EOT
ここで出力された gcloud container clusters get-credentials
コマンドを踏み台 VM で実行することで、作成した GKE クラスタに接続することができます。
佐々木 駿太 (記事一覧)
G-gen最北端、北海道在住のクラウドソリューション部エンジニア
2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2024に選出。好きなGoogle CloudプロダクトはCloud Run。
趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。
Follow @sasashun0805