本記事
本記事は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)を提案しました。
今回はDCDも見据えて、Githubのトリガーで簡単にコンテナイメージを更新できCIをすることができるCloud Buildを使ってみます。
注意点
Cloud BuildでCIをするには2つの方法があります。
Dockfileだけで行う方法 ビルドリクエストを作成する方法
今回はCIだけですが、ビルドリクエストはCircleCIでいうWorkflowのような感じで柔軟に拡張性の高いビルドを構築できるので、今回はビルドリクエストを作成する方向で進めます。
ビルドリクエストも同様にDockfileも必要になります。
ワークフロー
以下のようにワークフローはなっています。
設定方法
Cloud BuildとGithubの連携する
以下のようにCloud Buildの「トリガーを作成」から作成します。
まず、ソースを選択でGithub
を選択します。
次に認証を済ませます。
トリガーを作成する
以下のようにリポジトリ一覧が出るので選択します。
設定を次のようにします。
今回はmasterにmergeされたときをしたいので次のような設定をにしました。
- ブランチ:
master
cloudbuild.yaml
これらのファイルも用意しました。
cloudbuild.yaml
Dockerfile
なお、何もソースがなければトリガーは作成できません。
Dockerfileの注意点
Cloud Buildはビルド時間によって課金されるためイメージは容量が小さくします。
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に権限を付与します。
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
すると成功していました。
実際にCIしてみる
git pushする
まずはmaster
に直接pushしてトリガーが動くのを確認します。
git push origin master
ビルドされていました。
次は変更をcommitしてPRを出します。
git push origin test-trigger-branch
PRを出した段階では何もありません。
これをmergeすると以下のようになります。
これをCloud Buildの管理画面で確認するとビルドが走っていました。
一つのリポジトリで同時に複数のアプリケーションがディレクトリ分けで同時に存在するとき
以下のような構成です。
. ├── 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', '.']
これを見つけるのに、かなり能力を使いました、、、
しかし、注意点があります。
それは
- triggerを
/project1/cloudbuild.yaml
のように指定しても一回は.
で探すので必ず失敗します。
毎度、セットになっている理由がそうです。
docker bulid
は-f
でDockerfileを指定しないとうまくいかない
これは今回のように一つのリポジトリのときだけです。
まとめ
これによって、常に最新バージョンのコンテナイメージを作成することができました。