Cloud BuildでGKEにデプロイ


Cloud Build はGCP上でアプリケーションを自動でビルド、デプロイできるサービスです。

GitHubと連携してリポジトリへのプッシュをトリガーに発動することができます。
(ブランチや、特定のタグをトリガーとして設定ができます)

ビルドのステップをyamlに記述して構成することができます。

自分の用途でビルド~デプロイまで以下のような流れとなります。

GitHubにプッシュ(トリガーとなるタグ付けをしてプッシュ)
 ↓
CloudBuild が起動(トリガーに設定されたタグにより起動)
 ↓
イメージをビルド
 ↓
ビルドされたイメージを ContainerRepository にプッシュ
 ↓
Unitテスト実行
 ↓
コンテナイメージをGKEにデプロイ

GKE(事前準備)

クラスター、ノードプールなどをあらかじめ設定しておく必要があります
(詳細はこの記事では省略します)

CloudBuildのトリガー設定

対象(連携する)リポジトリ、イベント、構成用yamlの指定などを行います。

イベントはCloudBuildを開始するためのリポジトリ上のアクションで
特定のブランチやタグなどのpushなどを設定できます。

以下の例ではrelease_.{7}としていますが、
release_(コミットhashの短縮版)でタグ付けしたものをトリガーの条件としています。

リポジトリのディレクトリ構成(サンプル)

├── cloud_build
│   ├── cloudbuild.yaml   ・・・ CloudBuild構成用yaml
│   ├── apply.yaml      ・・・ GKEへのデプロイ用yaml(CloudBuild構成用yaml内から呼び出し)
│   └── dockerfile
│   │   ├── nginx
│   │   │   ├── Dockerfile  ・・・ CloudBuild内イメージビルド用
├── laravel           ・・・アプリケーション(laravelプロジェクト)
│   ├── app
│   ├── bootstrap
│   ├── config
・
・
・

上記のように構成用yaml(/cloud_build/cloudbuild.yaml)を配置した場合は
トリガーに以下のように設定します。

構成用yamlの記述

実行するステップの作業を記述します

キー 指定内容
name ビルドの各ステップで利用する一般公開されているDockerイメージを指定します。
CloudBuildではgcr.io/cloud-builders/******のようなイメージが用意されていて、例えばgcr.io/cloud-builders/dockerを利用するとクラウドビルド上でDockerコマンドを実行することができます。
args nameに指定したイメージ実行時に渡す引数を記述します
id ビルドステップの識別子となります
waitFor ビルドステップの順番の制御に利用できます
#######################################################################
# リポジトリ内から .dockerignoreファイルを削除
#######################################################################
steps:
- name: 'ubuntu'
  args:
    - bash
    - -c
    - 'rm -rf .dockerignore'
  id: 'rm-dockerignore'
#######################################################################
# イメージをビルド
# ($TAG_NAMEはGitコミットのタグの値、ビルドしたDockerイメージに同じタグ付け)
#######################################################################
- name: 'gcr.io/cloud-builders/docker'
  args:
    - build
    - -f
    - cloud_build/dockerfile/nginx/Dockerfile
    - --tag
    - asia.gcr.io/$PROJECT_ID/laravel:$TAG_NAME
    - .
  waitFor: ['rm-dockerignore']
#######################################################################
# ビルドしたイメージを container registry にプッシュ
#######################################################################
- name: 'gcr.io/cloud-builders/docker'
  args:
    - push
    - asia.gcr.io/$PROJECT_ID/laravel:$TAG_NAME
#######################################################################
# GKEデプロイ用のyaml内のコンテナイメージのタグを置換
#######################################################################
- name: 'ubuntu'
  args:
    - bash
    - -c
    - 'sed -i.bk s/latest/$TAG_NAME/g cloud_build/apply.yaml'
  id: 'laravel-build-done'
#######################################################################
# テスト実行
#######################################################################
- name: 'gcr.io/cloud-builders/docker'
  args:
    - run
    - --rm
    - --workdir=/var/www/html/laravel
    - --entrypoint=composer
    - asia.gcr.io/$PROJECT_ID/laravel:$TAG_NAME
    - test:coverage
  waitFor: ['laravel-build-done']
  id: 'phpunit-done'
#######################################################################
#gcloud認証
#######################################################################
- name: 'gcr.io/cloud-builders/gcloud'
  args:
  - beta
  - container
  - clusters
  - get-credentials
  - $_CLUSTER_NAME
  - --zone=$_ZONE
  - --project=$PROJECT_ID
  waitFor: ['-']
  id: 'gcloud-get-credentials'
#######################################################################
# アプリのデプロイ設定
#######################################################################
- name: 'gcr.io/cloud-builders/kubectl'
  args:
    - apply
    - --filename=cloud_build/apply.yaml
  env:
    - CLOUDSDK_COMPUTE_ZONE=$_ZONE
    - CLOUDSDK_CONTAINER_CLUSTER=$_CLUSTER_NAME
  waitFor: ['gcloud-get-credentials','phpunit-done']
#######################################################################
timeout: 1000s

yaml内に変数を埋め込んでいますが、CloudBuild実行時に値が置換されます。

$PROJECT_IDはGCPのプロジェクトIDが設定されます。

$TAG_NAMEはトリガーとなったGitリポジトリのタグ名が埋め込まれています。

$_ZONE$_CLUSTER_NAMEはそれぞれGKEのゾーン名、クラスタ名ですが、
CloudBuildのトリガー設定画面で設定しています。

GitHubへのプッシュとトリガーの稼働の実際

トリガー発動のためのタグ付けします
コミットhashを元にタグ付けをしてみます(git rev-parse --shortで短いコミットhashが取得できます)

$ git tag release_$(git rev-parse --short HEAD)
$ git log --oneline
* 459ddf9 (HEAD -> **, tag: release_459ddf9) *****

タグをプッシュします

$ git push origin ** --tags
Enumerating objects: 25, done.
Counting objects: 100% (25/25), done.
Delta compression using up to 6 threads
Compressing objects: 100% (13/13), done.
Writing objects: 100% (14/14), 1.40 KiB | 715.00 KiB/s, done.
Total 14 (delta 10), reused 0 (delta 0)
remote: Resolving deltas: 100% (10/10), completed with 9 local objects.
To github.com:*******/********.git
 * [new tag]         release_459ddf9 -> release_459ddf9

CloudBuildのビルドの詳細でビルドプロセスが確認できます

正常に完了すると全てのステップがグリーンになります

最後のステップでGKEへデプロイを行っています。
kubectl get pods -wでGKEのポッドの状態をウォッチすると
新たにビルドされたイメージがデプロイされることで
元々稼働していたポッドが終了し
新たなポッドが生成されていることがわかります

$ kubectl get pods -w
NAME                                         READY   STATUS    RESTARTS   AGE
*****-******-857db5db5f-pmxkh               1/1     Running   0          3d6h
#元々稼働していたポッドが終了していく
*****-******-857db5db5f-pmxkh               1/1     Terminating   0          3d6h
*****-******-857db5db5f-pmxkh               0/1     Terminating   0          3d6h
*****-******-857db5db5f-pmxkh               0/1     Terminating   0          3d6h
*****-******-857db5db5f-pmxkh               0/1     Terminating   0          3d6h
#新たなポッドが立ち上がり始める
*****-******-857d58675c-gcmgb               0/1     Pending       0          0s
*****-******-857d58675c-gcmgb               0/1     Pending       0          0s
*****-******-857d58675c-gcmgb               0/1     ContainerCreating   0          0s
#新たなポッドが起動完了
*****-******-857d58675c-gcmgb               1/1     Running             0          25s

以下はテストが失敗した場合のパターンです。
テストステップの失敗によりCloudBuildも失敗となり、
アプリケーションのデプロイもされることがありません。