TL;DR
- GKE-autopilot で環境構築をする例
- 一般的なAPI サーバーを構築することを目指し、GKE-autopilot、GCP のマネージド証明書を使ったhttps 化、Cloud SQL との疎通をさせる
- kustomize で複数環境の構築
About
GCP リソース/API は基本的に手作業でやりつつ、GKE 周りは基本的にkustomize でやります。
作業はCloud Shell 上で行います。
version
- gcloud
- 347.0.0
- GKE
- 1.19.9-gke.1900
Repository
サンプルコードは以下
https://github.com/y-ohgi/example-gke-autopilot
構築
GKE Autopilot クラスタの作成
gcloud beta clusters create-auto
コマンドで作成を行えるのですが、GUI からポチポチでクラスタ名とリージョンの変更を行います。
ネットワークはデフォルトのままにしていますが、メンテナンスウィンドウはデフォルトだといつでも実行されてしまうため、適宜変更をオススメします。
設定項目が少ないので、本番でもGUI からでも良いかなと個人的に思っています。
まずはKubernetes Engine API の有効化を行い、クラスタの作成からAutopilot を選択
クラスタの名前は適宜変更してもらい、リージョンは asia-northeast1
(日本) に設定。
今回はリリースチャンネルはRegular に。
ここは本番環境はStable にして、開発環境はRegular にすると良いのかなと。
本番環境の場合は、自動化の「メンテナンスの時間枠」を有効化にチェックを入れ、メンテナンスウィンドウを運用するサービスに応じて変更。
クラスタの作成は5分ほどかかるので待つ。
nginx を立ててhttps で疎通する
Cloud SQL と疎通させる前に、まずはGKE 上に nginx を立ててhttps で受け付けます 。
IP の取得とドメインへ登録
マネージド証明書を取得する前準備です。
IP の取得と、そのIP をCloud DNS へ登録していきます。
ここでは、Cloud DNS にドメインを登録済みの前提で進めます。
まずは静的IP の取得を行います。
ここで静的IP へ付与した名前はmanifest 上で使用するので、控えておきます。
静的IP は環境毎に必要になるので、プレフィックスに prd-
や dev-
などを付けておくと良いでしょう。
$ gcloud compute addresses create ${ADDRESS_NAME} --global $ gcloud compute addresses describe ${ADDRESS_NAME} --global address: 35.190.xxx.xxxx addressType: EXTERNAL creationTimestamp: '2021-07-16T00:59:17.408-07:00' :
取得した静的IP をCloud DNS のA レコードへ登録します。
Cloud DNS もAPI を有効化する必要があったり移譲したりがあると思うので、GUI でポチポチA レコードを登録します。
kustomize の構成
Pull Request を作ったので、実際のコードは以下を参照ください。
https://github.com/y-ohgi/example-gke-autopilot/pull/1
$ tree kustomize/ kustomize/ |-- base | |-- certificate.yaml | |-- deployment.yaml | |-- ingress.yaml | |-- kustomization.yaml | |-- namespace.yaml | `-- service.yaml `-- overlays |-- dev | |-- certificate.yaml | |-- deployment.yaml | |-- ingress.yaml | |-- kustomization.yaml | `-- service.yaml `-- prd `-- kustomization.yaml
GKE マネージド証明書を使ったhttps の設定
GKE マネージド証明書を使用したhttps の構成を構築するには2つポイントがあります。
- ヘルスチェックパスの変更
- Ingress のannotation でマネージド証明書の指定
1. ヘルスチェックパスの変更
GCE のヘルスチェックを使用してTLS 証明書を発行するため、GCE のデフォルトのヘルスチェックである /healthz
を変更する必要があります。
デフォルトのnginx だと /healthz
というエンドポイントにアクセスると404 が返ってきてヘルスチェックが落ちるため、ヘルスチェックのエンドポイントを /
へ変更する必要があります。
GKE のCRD の BackendConfig
でヘルスチェックエンドポイントを設定し、Service のannotation ( beta.cloud.google.com/backend-config
)でそのBackendConfig を参照するようにします。
kustomize/base/service.yaml
apiVersion: cloud.google.com/v1 kind: BackendConfig metadata: name: config-default spec: healthCheck: checkIntervalSec: 10 timeoutSec: 3 requestPath: / --- apiVersion: v1 kind: Service metadata: name: sandbox annotations: cloud.google.com/neg: '{"ingress": true}' beta.cloud.google.com/backend-config: '{"default": "config-default"}' spec: type: NodePort selector: app: sandbox ports: - protocol: TCP port: 80 targetPort: 80
annotations
はkustomize は変更しないため、以下のように環境舞に明示的にkustomize で書き換える必要があります。
kustomize/overlays/dev/service.yaml
apiVersion: v1 kind: Service metadata: name: sandbox annotations: beta.cloud.google.com/backend-config: '{"default": "dev-config-default"}'
2. Ingress のannotation でマネージド証明書の指定
Ingress の annotations
に3つ設定を追加します。
kustomize/base/ingress.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: sandbox annotations: kubernetes.io/ingress.global-static-ip-name: sandbox # gcloud コマンドで取得した静的IP networking.gke.io/managed-certificates: sandbox # certificate.yaml で設定したname kubernetes.io/ingress.class: gce spec: defaultBackend: service: name: sandbox port: number: 80
前項のService と同じくannotations はkustomize は書き換えないため、Ingress でも明示的に書き換えます。
kustomize/overlays/dev/ingress.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: sandbox annotations: kubernetes.io/ingress.global-static-ip-name: dev-sandbox networking.gke.io/managed-certificates: dev-sandbox kubernetes.io/ingress.class: gce
apply する
GKE のクレデンシャルを取得し、apply します。
$ gcloud container clusters get-credentials autopilot-cluster-1 --region asia-northeast1 --project gke-autopilot-blog $ kubectl apply -k kustomize/overlays/dev
証明書の発行に時間がかかるため、15分ほど待つと対象のドメインにhttp/https で接続するとnginx が表示されます。
次はcloudsql-proxy を使用してCloud SQL と疎通させます。
CloudSQL と疎通させる
一気に登場人物が多くなります。
それぞれ概要だけざっくり説明します。
- Cloud IAM
- 後述するcloudsql-proxy とCloud SQL を疎通させるための権限を付与するためのIAM です
- Cloud SQL
- 疎通先のCloud SQL です。今回はPostgreSQL を使用しますが、MySQL でも同じ構成になります。
- Pod
- GCP が提供しているcloudsql-proxy と、pgcli 用にpostgres をpod に入れます
Pull Request は以下です。
https://github.com/y-ohgi/example-gke-autopilot/pull/2
Cloud IAM の設定
Cloud IAM (Service Account。以降GSA) とKubernetes Service Account (以降KSA) の2種類を使用します。
役割としてはGSA にCloud SQL への疎通権限を付与し、KSA からGSA を使用するような形です。
GSA の作成
まずはGSA から作成します。
GCP のプロジェクトid が必要になるので、はじめに取得し、環境変数に入れておきます。
$ gcloud projects list PROJECT_ID NAME PROJECT_NUMBER gke-autopilot-blog gke-autopilot-blog 5555555555555 : $ export PROJECT_ID=gke-autopilot-blog
GSA の作成をします。
$ gcloud iam service-accounts create ${GSA_NAME}
GSA にCloud SQL への接続権限を付与します。
$ gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member serviceAccount:${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \ --role roles/cloudsql.client
roles/cloudsql.client
のAPI を有効化します。
$ gcloud services enable sqladmin.googleapis.com
GSA とKSA の紐付け。
KSA はまだ作成していませんが、先に紐付けだけしてしまいます。
${K8S_NAMESPACE}
はnginx の構築をした際のnamespace で、 ${KSA_NAME}
は今から作成するKSA の名前になります。
個人的に、特にこだわりがなければ GSA_NAME
と KSA_NAME
は同一にして問題ないと思います。
$ gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[${K8S_NAMESPACE}/${KSA_NAME}]" ${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com
KSA の作成とPod へ付与
manifest からKSA を作成します。
deployment へKSA の定義と、Pod へKSA の付与を行います。
<GSA_NAME>
と <PROJECT_ID>
は先程使用した値と同じものです。
kustomize/base/deployment.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: sandbox annotations: iam.gke.io/gcp-service-account: <GSA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: api : spec: serviceAccountName: sandbox :
Service/Ingress と同じくannotations は上書きされないこと、 Deploymentの serviceAccountName
は明示的に宣言する必要があるためkustomize で上書きします。
個人的に、GSA は環境毎にそれぞれ作ると良いと考えています。
kustomize/overlays/dev/deployment.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: sandbox annotations: iam.gke.io/gcp-service-account: <GSA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com --- apiVersion: apps/v1 kind: Deployment metadata: name: api : spec: serviceAccountName: dev-sandbox :
Cloud SQL (PostgreSQL) の立ち上げ
GUI からPostgreSQL 13 をtokyo リージョンに立ち上げます。
このブログでは疎通させることを目的にしているため説明しませんが、インスタンスの設定は適宜行ってください。
ここで生成したパスワードは接続時に使用するので、控えて置いてください(デフォルトユーザーで疎通確認します)。
Pod へpgcli とcloud-sql-proxy の追加
GCP が提供するcloud-sql-proxy と、postgres イメージをPod へ追加します。
cloud-sql-proxy はその名の通りCloud SQL とのプロキシを行ってくれます。
command:
の2つ目の - "-instances=<PROJECT ID>:asia-northeast1:<INSTANCE NAME>=tcp:5432"
で疎通させたいインスタンスの接続名を指定します。
postgres イメージは後述する $ kubectl exec
でコンテナに入り、 $ psql
コマンドで疎通確認をしたいため使用します。起動後は何もさせないよう $ tail -f /dev/null
を実行させておきます。
kustomize/base/deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: sandbox : - name: cloud-sql-proxy image: gcr.io/cloudsql-docker/gce-proxy:1.24.0 command: - "/cloud_sql_proxy" - "-instances=<PROJECT ID>:asia-northeast1:<INSTANCE NAME>=tcp:5432" ports: - containerPort: 5432 - name: pgcli image: postgres:13 command: - "tail" - "-f" - "/dev/null"
Pod からCloud SQL へ疎通確認
Pod に立てたpgcli コンテナに入り、Cloud SQL へ接続できるかを確認します。
Pod NAME を取得し、 $ kubectl exec
でpgcli コンテナに入り、 $ psql -h localhost -p 5432 -U postgres
コマンドでCloud SQL へ接続できることを確認します。
$ kubectl get pod NAME READY STATUS RESTARTS AGE dev-sandbox-844855db4f-6zknf 3/3 Running 0 7m56s $ kubectl exec -it dev-sandbox-844855db4f-6zknf -c pgcli -- bash root@dev-sandbox-844855db4f-6zknf:/# psql -h localhost -p 5432 -U postgres Password for user postgres: psql (13.4 (Debian 13.4-1.pgdg100+1), server 13.3) Type "help" for help. postgres-> \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges ---------------+-------------------+----------+------------+------------+----------------------------------------- cloudsqladmin | cloudsqladmin | UTF8 | en_US.UTF8 | en_US.UTF8 | postgres | cloudsqlsuperuser | UTF8 | en_US.UTF8 | en_US.UTF8 | template0 | cloudsqladmin | UTF8 | en_US.UTF8 | en_US.UTF8 | =c/cloudsqladmin + | | | | | cloudsqladmin=CTc/cloudsqladmin template1 | cloudsqlsuperuser | UTF8 | en_US.UTF8 | en_US.UTF8 | =c/cloudsqlsuperuser + | | | | | cloudsqlsuperuser=CTc/cloudsqlsuperuser (5 rows) postgres->
片付け
kubectl でk8s Object を削除します。
$ kubectl delete -k kustomize/overlays/dev
取得した静的IP を削除します。
$ gcloud compute addresses delete ${ADDRESS_NAME} --global The following global addresses will be deleted: - [dev-sandbox] Do you want to continue (Y/n)? Y
GSA を削除します。
$ gcloud iam service-accounts delete ${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com You are about to delete service account [dev-sandbox@gke-autopilot-blog.iam.gserviceaccount.com]. Do you want to continue (Y/n)? Y
Cloud SQL とCloud DNS をGUI からポチポチ削除します。
所感
GKE Standard のノリで使える制約の少なく運用が楽になる素晴らしいGKE のクラスタータイプだと感じました。
また、GKE-autopilot でもマネージド証明書やWorkload Identity をお手軽に使える点に感動です。
基本的にGKE のノリで使えたのですが、唯一古いNode に当たるとWorkload Identity が動かないことがあったことがハマった点でした。その時(2021/08 前半)はPod のリソースをある程度大きめに設定することで解決できましたが、ブログを書いているときはリソースを設定せずに問題なく動きました。
GKE のクラスターを選定する際は第一の選択肢になりえるのかなとおもいます(GKE-autopilot を使うならCloud Run でも良い気はしますが、Cron Job とか使いたいときとか?)。
とにかく、考えることが減って(CA/NPA etc)、GKE の運用が楽になるのは良いですね。使っていきたいと思います。