Kekeの日記

エンジニア、読書なんでも

Cloud BuildでPrivate RepoをContinuous Integrationをする

f:id:bobchan1915:20181004225650p:plain

本記事

本記事はGoogle Cloud PlatformのCloud Buildを使ってGithubにあるPrivateリポジトリのソースコードの変更をトリガーに、コンテナイメージをビルドしてみようと思います。

また、何かしらの理由で一つのリポジトリに複数のプロジェクトがディレクトリ分けして存在しているケースがあります。そのようなときに、Cloud Buildをそれぞれで使い分けできるのかを試してみようと思います。

Github Marketから連携できるようになってから以下のyamlfだけでbuildできるようになったので注意です。

steps:
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'asia.gcr.io/$PROJECT_ID/test-cloud-build-project-1:latest', '-f', './project1/Dockerfile', '.']

images: ['asia.gcr.io/$PROJECT_ID/test-cloud-build-project-1:latest']

目次

目的

主にはContinuous Integrationです。

以前、私はSpinnaker、Kubernetes、Cloud Container Registry、CircleCIを使った宣言的継続的デプロイメント(DCD: Declartive Continuous Deployment)を提案しました。

www.1915keke.com

今回はDCDも見据えて、Githubのトリガーで簡単にコンテナイメージを更新できCIをすることができるCloud Buildを使ってみます。

注意点

Cloud BuildでCIをするには2つの方法があります。

Dockfileだけで行う方法 ビルドリクエストを作成する方法

今回はCIだけですが、ビルドリクエストはCircleCIでいうWorkflowのような感じで柔軟に拡張性の高いビルドを構築できるので、今回はビルドリクエストを作成する方向で進めます。

ビルドリクエストも同様にDockfileも必要になります。

ワークフロー

以下のようにワークフローはなっています。

f:id:bobchan1915:20181004225650p:plain

設定方法

Cloud BuildとGithubの連携する

以下のようにCloud Buildの「トリガーを作成」から作成します。

まず、ソースを選択でGithubを選択します。

f:id:bobchan1915:20181004212324p:plain

次に認証を済ませます。

f:id:bobchan1915:20181004212844p:plain

トリガーを作成する

以下のようにリポジトリ一覧が出るので選択します。

f:id:bobchan1915:20181004212952p:plain

設定を次のようにします。

f:id:bobchan1915:20181004214455p:plain

今回はmasterにmergeされたときをしたいので次のような設定をにしました。

  • ブランチ: master
  • cloudbuild.yaml

これらのファイルも用意しました。

  • cloudbuild.yaml
  • Dockerfile

なお、何もソースがなければトリガーは作成できません

Dockerfileの注意点

Cloud Buildはビルド時間によって課金されるためイメージは容量が小さくします。

www.1915keke.com

cloudbuild.yamlを定義する

以下のようにCloud Key Management Serviceから暗号化し、復号化をしていきます。

KeyによってSSH認証鍵を暗号化

Keyringを作成し、Keyを作成します。

gcloud kms keyrings create my-keyring --location=global

gcloud kms keys create github-key \
--location=global --keyring=my-keyring \
--purpose=encryption

そしてgithubのSSH認証鍵を暗号化します。

gcloud kms encrypt --plaintext-file=~/sshkey/id_rsa \
--ciphertext-file=./id_rsa.enc \
--location=global --keyring=my-keyring --key=github-key

ssh-keyscan -t rsa github.com > known_hosts

ここでCloud Buildのサービスアカウントに復号化の権限を渡します。

@cloudbuild.gserviceaccount.comがついているIAMに権限を付与します。

f:id:bobchan1915:20181004221713p:plain

Cloud Buildで復号化してGit Cloneする

次のドキュメントをcloudbuild.yamlに書きます。

非公開 GitHub レポジトリへのアクセス  |  Cloud Build のドキュメント  |  Google Cloud

これにdocker buildの項目とGoogle Container Registryへのpushを定義します。

- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'asia.gcr.io/$PROJECT_ID/test-cloud-build:latest', '.']

images: ['asia.gcr.io/$PROJECT_ID/test-cloud-build:latest']

テストで手動で動かしてみる

以下のようにしてテストで動かしてみます。

gcloud builds submit --config=cloudbuild.yaml 

すると成功していました。

f:id:bobchan1915:20181004222654p:plain

実際にCIしてみる

git pushする

まずはmasterに直接pushしてトリガーが動くのを確認します。

git push origin master

ビルドされていました。

f:id:bobchan1915:20181004224013p:plain

次は変更をcommitしてPRを出します。

git push origin test-trigger-branch

PRを出した段階では何もありません。

これをmergeすると以下のようになります。

f:id:bobchan1915:20181004230422p:plain

これをCloud Buildの管理画面で確認するとビルドが走っていました。

f:id:bobchan1915:20181004224505p:plain

一つのリポジトリで同時に複数のアプリケーションがディレクトリ分けで同時に存在するとき

以下のような構成です。

.
├── project1
│   ├── Dockerfile
│   └── cloudbuild.yaml
└── project2
    ├── Dockerfile
    └── cloudbuild.yaml

試しに

  • triggerを/project1/cloudbuild.yamlとして
- name: 'gcr.io/cloud-builders/git'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    ls

をすると

README.md
index.js
package-lock.json
package.json
project1
project2

と返ってきました。**これをみる感じ、CheckAPI導入後のものはgit cloneが必要ないらしいです。

また今回の大きな検証ポイントとしてcloudbuild.yamlの以下の項目がどのように走るかが問題です。

- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'asia.gcr.io/$PROJECT_ID/test-cloud-build:latest', '.']

ここはDockerによると

Path to the Dockerfile to use. If the path is a relative path then it must be relative to the current directory.

でなければならないのはずなので

- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'asia.gcr.io/$PROJECT_ID/test-cloud-build:latest', './project1/']

と書き換えます。逆も同様です。**これがなぜか上手くいきません...

- name: 'gcr.io/cloud-builders/docker'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    ls

やっても

README.md
index.js
package-lock.json
package.json
project1
project2

と返ってくるのに、、、

しかし、以下のように指定すると上手くいきました!

- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'asia.gcr.io/$PROJECT_ID/test-cloud-build-project-1:latest', '-f', './project1/Dockerfile', '.']

これを見つけるのに、かなり能力を使いました、、、

f:id:bobchan1915:20181017035132p:plain

しかし、注意点があります。

それは

  • triggerを/project1/cloudbuild.yamlのように指定しても一回は.で探すので必ず失敗します。

毎度、セットになっている理由がそうです。

f:id:bobchan1915:20181017035132p:plain

  • docker bulid-fでDockerfileを指定しないとうまくいかない

これは今回のように一つのリポジトリのときだけです

まとめ

これによって、常に最新バージョンのコンテナイメージを作成することができました。