CircleCI Orbsを使ってGKEにデプロイする


こんにちは、 [@jnamix](https://qiita.com/jnamix) です。

今年、業務でCircleCI Orbsを使ってGoogle Kubernetes Engine（GKE）にWebアプリをデプロイする機会がありました。
Orbは、 `run` 等でコマンドを忠実に記述していくよりも簡潔に書くことができる点で便利です。
今回はその実装例を紹介します。

# 使用するOrb
- `circleci/gcp-gcr@0.15.0`
- `circleci/kubernetes@1.3.1`

GKEへのデプロイには `circleci/gcp-gke` が利用可能ですが、マニフェストファイルを使用する場合は、代わりに `circleci/kubernetes` を利用するのが便利です[^1]。

# デプロイまでの手順
今回は下記の手順で行います。
1. 環境変数を定義する
2. Container Registry（GCR）にビルドしたDockerイメージをpushする
3. GCRへpushしたイメージをGKEにデプロイする

## 1. 環境変数を登録する
環境変数はCircleCIのProject Settingsや、config.yml上で定義します。
利用するOrbがパラメータとしてデフォルトで参照する環境変数があるので、変数名を合わせて定義しておくと便利です。
例えばOrb `circleci/gcp-gcr` の `gcr-auth` というコマンドでは、下記のパラメータが環境変数を参照しています。

|パラメータ             |環境変数              |
|---------------------|---------------------|
|gcloud-service-key   |GCLOUD_SERVICE_KEY   |
|google-compute-region|GOOGLE_COMPUTE_REGION|
|google-compute-zone  |GOOGLE_COMPUTE_ZONE  |
|google-project-id    |GOOGLE_PROJECT_ID    |

その他、使用するコマンドがどの環境変数を使用しているかは公式ドキュメントで都度確認する必要があります。

- https://circleci.com/developer/orbs/orb/circleci/gcp-gcr
- https://circleci.com/developer/orbs/orb/circleci/kubernetes

## 2. GCRにビルドしたDockerイメージをpushする
ここではOrb `circleci/gcp-gcr` を使用してDockerイメージをbuild、pushします。
新たに値の指定が必要なパラメータはコマンド名に続けて記述します。

※一部簡略化しています

```yaml:.circleci/config.yml
orbs:
  gcp-gcr: circleci/gcp-gcr@0.15.0

jobs:
  build-deploy:
    steps:
      - attach_workspace:
          at: /tmp/workspace
      # 略
      ​- gcp-gcr/gcr-auth
      - gcp-gcr/build-image:
          dockerfile: deploy/Dockerfile
          registry-url: asia.gcr.io
          image: ${CIRCLE_PROJECT_REPONAME}
          tag: latest,${CIRCLE_SHA1}-${CIRCLE_BUILD_NUM}
      - gcp-gcr/push-image:
          registry-url: asia.gcr.io
          image: ${CIRCLE_PROJECT_REPONAME}
          tag: latest,${CIRCLE_SHA1}-${CIRCLE_BUILD_NUM}
```

## 3. GCRへpushしたイメージをGKEにデプロイする
Orb `circleci/kubernetes` を使用してデプロイします。

先程と同じジョブに続けて記述します。
`circleci/kubernetes` は内部的に `kubectl` を実行しているので、GKEの場合は下記コマンドでクラスタを利用可能にしておく必要があります。

```sh
gcloud container clusters get-credentials <cluster-name>
```

そして、デプロイに `create-or-update-resource` コマンドを使用します。
ここで、パラメータ `resource-file-path` にマニフェストファイルのパスを指定します。
また、マニフェストファイル内で、コンテナが使用するイメージとして前のステップでGCRにpushしたイメージを指定します。

※一部簡略化しています

```yaml:.circleci/config.yml
orbs:
  gcp-gcr: circleci/gcp-gcr@0.15.0
  k8s: circleci/kubernetes@1.3.1

jobs:
  build-deploy:
    steps:
      - attach_workspace:
          at: /tmp/workspace
      # 略
      ​- gcp-gcr/gcr-auth
      - k8s/install-kubectl
      - gcp-gcr/build-image:
          dockerfile: deploy/app/Dockerfile
          registry-url: asia.gcr.io
          image: ${CIRCLE_PROJECT_REPONAME}
          tag: latest,${CIRCLE_SHA1}-${CIRCLE_BUILD_NUM}
      - gcp-gcr/push-image:
          registry-url: asia.gcr.io
          image: ${CIRCLE_PROJECT_REPONAME}
          tag: latest,${CIRCLE_SHA1}-${CIRCLE_BUILD_NUM}
      - run:
          command: gcloud container clusters get-credentials ${GKE_CLUSTER_NAME} --region ${GKE_COMPUTE_REGION} --project ${GOOGLE_PROJECT_ID}
      - k8s/create-or-update-resource:
          envsubst: true
          get-rollout-status: true
          watch-timeout: 3m
          resource-name: deployment/${CIRCLE_PROJECT_REPONAME}
          resource-file-path: ./deploy/k8s/manifest.yaml
```

```yaml:deploy/k8s/manifest.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: # 略
spec:
  # 略
  template:
    # 略
    spec:
      containers:
        - name: # 略
          image: asia.gcr.io/${GOOGLE_PROJECT_ID}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_SHA1}-${CIRCLE_BUILD_NUM}
          # 略
```

# 終わりに
実際はさらに、環境（検証、本番等）ごとにパラメータを切り替えたりなどの実装が必要となりますが、ベースとなる処理は変わらないと思いますので、同様の実装を検討している方の参考になれば幸いです。
個人的には、Orb `circleci/gcp-gke` の機能がより拡充されると良いなと思います（特にマニフェストの反映など）。
ここまで読んでいただきありがとうございました。


[^1]: 2022年12月現在、Orb `circleci/gcp-gke` ではマニフェストを反映する機能が実装されていないようです。GitHub上でも [Issue](https://github.com/CircleCI-Public/gcp-gke-orb/issues/50) が立てられています。