TerraformとKustomizeによる効率的なGKE運用
GKE(k8s)クラスタとその上で動くアプリケーションの管理は、多くのエンジニアにとって終わりの見えない戦いになりつつあります。ノードプール、アドオン、Ingressコントローラ、SSL証明書マネージャ、アプリケーションのロールアウトとそれに伴う設定など、多岐にわたる要素を正確に管理する作業は、多くの現場で大きな負担となっています。マイクロサービスや多数のコンポーネントから成るイベント駆動型アーキテクチャの広がりにより、この課題はさらに身近なものになっています。
GKE(K8S)クラスタの管理
GKE / K8Sクラスタのセットアップは複雑なプロセスです。作成部分をIaCの成果物として自動化するのが有効なアプローチです。本記事では、IaCツールとしてTerraformを使用します。
IaCのセットアップ
環境の一貫性(パリティ)を保つ鍵は、すべてのリソースについてパラメータや属性を備えたモジュールを作成することです。本リポジトリでは3つのモジュールを用意します。1. 2つのノードプールを持つGKEクラスタモジュール。2. helm chartプロビジョナを利用したnginx Ingressコントローラモジュール。3. パブリックエンドポイント向けのkcert Let's Encrypt SSL証明書プロバイダモジュール。
以下に挙げるすべてのモジュールのコードは、こちらのリポジトリで公開しています: https://github.com/agileguru/gke_nginx_kcert_quick_start
- 複数のノードプールを持つGKEクラスタのプロビジョニング
このモジュールには、GKEクラスタのプロビジョニング、パラメータ化、再利用可能なメタデータをそれぞれ担うmain.tf、variables.tf、outputs.tfが含まれています。

GKE Terraform IaCモジュールのスクリーンショット
- nginx Ingressコントローラのインストール このモジュールには、nginxコントローラのプロビジョニングおよびパラメータ化を行うmain.tf、variables.tf、そしてオプション(空)のoutputs.tfが含まれます。

NGINX Terraform IaCプロビジョナのmain.tfのスクリーンショット
- kcert Let's Encrypt SSLマネージャのインストール このモジュールには、kcert SSLコントローラのプロビジョニングおよびパラメータ化を行うmain.tf、variables.tf、そしてオプション(空)のoutputs.tfが含まれます。

kcert Terraform IaCプロビジョナのmain.tfのスクリーンショット
- すべてを連携させる
3つのモジュールが揃ったら、「devops」モジュールを作成して「devops」k8s環境を構築します。このモジュールはmain / rootから呼び出され、すべての要素を一つにまとめます。

Devops k8s環境モジュールのスクリーンショット

ルートからDevopsモジュールをオーケストレーションするスクリーンショット
- Terraformでクラスタとコントローラをプロビジョニング\* variables.tf内のproject / region / zoneの値を変更します
\* GCPコンソールでバケットを作成したうえで、backend.tf内のバケット名を変更します
\* 以下のコマンドを実行します
terraform init
terraform plan -var-file=sample.tfvars(必要に応じてsample.tfvarsを編集)
terraform apply -var-file=sample.tfvars(必要に応じてsample.tfvarsを編集)

- Terraformコマンドの実行後、ドメイン登録に使うLoadBalancerのIPアドレスが取得できます。
- kubectlのconfigは次のコマンドで取得できます。
gcloud container clusters get-credentials
— zone — project
Kustomizeによるデプロイ管理
これでクラスタはワークロードをデプロイする準備が整いました。デプロイをよりシンプルに管理するため、Kustomizeプラグインを使用します。本記事ではシンプルなユースケースを取り上げます。
- tutum/hello-worldイメージをベースにした2つのアプリ、api-1とapi-2を用意します。
- DEVおよびSIT環境に対応する2つのk8sネームスペースも用意します。
- サービスをデプロイし、それぞれの設定、Deployment、Service、Ingressマッピングを使ってhttps(SSL)で公開します。
- これらをリポジトリで管理します。デモ用の構成は https://github.com/agileguru/kustomize_quickstart_demo に格納しています。
ステップ1:フォルダ構造の作成

コンポーネントと設定のベースフォルダ
ステップ2:オーバーレイで各環境をカスタマイズ

kustomize.yamlによるpatch / merge設定を用いた環境別オーバーレイフォルダ
ステップ3:Ingressのホスト名マッピングを変更
dev-ingress-patch.jsonとsit-ingress-patch.jsonのホスト名を、有効なホストまたはドメインに書き換えます。コードは以下のようになります。
[\
{\
"op": "replace",\
"path": "/spec/rules/0/host",\
"value": "dev.agileguru.org"\
},\
{\
"op": "replace",\
"path": "/spec/tls/0/hosts/0",\
"value": "dev.agileguru.org"\
}\
]
[\
{\
"op": "replace",\
"path": "/spec/rules/0/host",\
"value": "sit.agileguru.org"\
},\
{\
"op": "replace",\
"path": "/spec/tls/0/hosts/0",\
"value": "sit.agileguru.org"\
}\
]
ステップ4:アプリケーションのデプロイ
$ kubectl apply -k overlays/dev
namespace/dev created
configmap/config-map-api-1 created
configmap/config-map-api-2 created
service/api-1-service created
service/api-2-service created
deployment.apps/api-1-deployment created
deployment.apps/api-2-deployment created
ステップ5:アプリケーションの撤去
$ kubectl delete -k overlays/dev
namespace "dev" deleted
configmap "config-map-api-1" deleted
configmap "config-map-api-2" deleted
service "api-1-service" deleted
service "api-2-service" deleted
deployment.apps "api-1-deployment" deleted
deployment.apps "api-2-deployment" deleted
ingress.networking.k8s.io "app-ingress" deleted
Kustomizeのベストプラクティス
やるべきこと
— ベース設定ではレプリカ数を0にしておく
— オーバーレイのkustomization.yamlでは必ずネームスペースを明示する
— 正確性を担保するため、yaml出力でのドライランを必ず行う
— フォルダ名やマニフェストファイル名には適切な命名規則を採用する
— Ingressマッピングは専用フォルダに切り出す
— 各コンポーネントには必ずoverride.yamlを用意する 2. やってはいけないこと
— _ベース設定にネームスペースをハードコーディングする_
— 設定とアプリケーションコードを同じフォルダに混在させる
— 環境設定をGitブランチで管理する(いわゆるパリティドリフト)
参考資料
- GKE Nginx Kcertスタートガイドリポジトリ: https://github.com/agileguru/gke_nginx_kcert_quick_start
- Kustomizeクイックスタートリポジトリ: https://github.com/agileguru/kustomize_quickstart_demo
- Kustomizeドキュメント: https://kustomize.io/
- Kcert GitHub: https://github.com/nabsul/kcert
- Nginxコントローラ: https://kubernetes.github.io/ingress-nginx/
- Let's Encrypt: https://letsencrypt.org/
以上の手順により、次の2点が実現します。1. nginxとkcert SSL証明書マネージャを組み合わせ、パブリックエンドポイントのSSL証明書を自前で管理する必要のない、運用とアップグレードが容易なk8s環境。2. IaC / DevOps / DRYの原則に沿って、セキュアなWebエンドポイントを管理するための仕組みとフレームワーク。