CICDを体験する。

## はじめに

この記事は、
　[Serverless is simple. Do I need CI/CD?](https://www.youtube.com/watch?v=i3epeCk8ldc)
という動画を視聴し『実際にやってみた』という記事になります。

## CI/CD の PipeLine は何をする？
`code`を`repository`に、`commit`した瞬間から、
これらの変更が`User`に表示されるまでに、
少なくとも、いくつかの手順を実行する必要がある。

たとえば、保存された`Artifact`を構築し、`deploy`するなど。
![SoftwareSupplyChain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/1169953b-61c2-ceb8-c7ad-35d9067ba958.png)　

## Google Cloud API を有効化
このCI/CDを構築したいGCPプロジェクトのコンソールへ接続。

`Cloud Build API`
`Artifact Registry API`
`Cloud Run Admin API`

これらのAPIを有効化。
その他、APIの有効化は、必要に応じて、適宜行う事。

## sample code を copy しよう。
https://github.com/GoogleCloudPlatform/cloud-code-samples/tree/v1

今回は、Forkを使うことで、元のprojectに影響を与えないようにします。
![github-fork1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/3c7bc906-97ff-fc9b-a382-a4d0b6de204f.png)
↓
![github-fork2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/7d5e7590-f930-2c6d-4385-946b1810df17.png)

## プログラミング言語を選択しよう。
sample code は様々なプログラミング言語を利用可能。
自分の好みで選択してください。

この記事では、今回は、`Golang`を選択しまして、
[cloud-code-samples/golang/go-cloud-run-hello-world](https://github.com/GoogleCloudPlatform/cloud-code-samples/tree/v1/golang/go-cloud-run-hello-world)
というディレクトリを操作します。

![sample-gengo-go.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/f8371be5-5b01-6b28-ed5e-ef6cb69c66d1.png)


## Artifact Registry に コンテナイメージ を作成する準備をしよう。
`コンテナイメージ`を保存するための`repository`を`Artifact Registry`に`deploy`する。

repositoryの名前：`自由に名前をつけてください。`
形式：`Docker`
region：`最寄りのリージョンを選択`
他の項目は、デフォルトで設定。

![artifact-repo-create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/e62eedb7-2399-4c0b-0cf4-64e2582f06b1.png)


## cloud build trigger を作成しよう。
`CloudBuild` はCICDパイプラインを作成できる `サーバレスプラットフォーム` です。

triggerの名前：`Hello-Cloud-Run-Pipline`
region：`最寄りのリージョンを選択`
event：`ブランチに push する`
repository：`github.account/cloud-code-samples`
※ repository が選択画面にない場合は、`新しいリポジトリに接続`を行うこと。
branch：　`v1`（今回は、`default`branchを選択します）
形式：`cloudbuild構成ファイル`
ロケーション：`リポジトリ`
cloudbuild構成ファイルの場所：下記の画面スクショを参考にしてください。

基本、trigger の作成は、動画の説明通りに進めて問題ないですが、
この記事では、`Cloud Build 構成ファイルの場所` のみ変えています。

この記事では、`cloudbuild.yaml`を 
`golang/go-cloud-run-hello-world`内で作成する為です。

![cloudbuild-trigger6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/bf385310-5c6f-ff3c-a0a9-f4753a80ebb9.png)

## cloudbuild.yamlを作成

`vscode`などを開いて、`cloudbuild.yaml`を作成。
このyamlファイルは、`asia-northeast1`リージョンを選択している為、
最寄りのリージョンに合わせて適宜、修正を行ってください。

また、`Golang`を選択していますので、他のプログラミング言語を
選択した場合も、同じく修正を行う必要があります。

```
steps:
  # Build app
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-f', 'golang/go-cloud-run-hello-world/Dockerfile', '-t', 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/my-repo/hello:$COMMIT_SHA', './golang/go-cloud-run-hello-world']
    id: BUILD

  # Storage of the image
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/my-repo/hello:$COMMIT_SHA']
    id: STORAGE

  # Deploy app
  - name: 'gcr.io/cloud-builders/gcloud'
    args: ['run', 'deploy', 'hello-site', 
        '--image', 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/my-repo/hello:$COMMIT_SHA',
        '--region', 'asia-northeast1',
        '--platform', 'managed',
        '--allow-unauthenticated']
    id: DEPLOY
```

この記事では、`cloudbuid.yaml`はこちらのディレクトリの階層に作成します。
![cicd-cloudbuild.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/10e9c639-bc71-ca03-15b3-62699442d228.png)

## error を解消しよう。
動画内では、`error`が起こりませんが、実際に試してみると、
`APIの有効化の不足`や`サービスアカウント権限不足`で`error`になることがあります。

`APIの有効化`については、この記事の冒頭で説明を挟んでいますが、
`cloud build triigger`を実行した際に、`サービスアカウント権限`が
不足していると、下記の`error`が出力され、`trigger`は`異常終了`してしまいます。

```
Step #2: ERROR: (gcloud.run.deploy) PERMISSION_DENIED: Permission 'run.services.get' denied on resource ...
```

これを解決するには、
Cloud Build サービスアカウント（`<PROJECT_NUMBER>@cloudbuild.gserviceaccount.com`）
に対して、
- Cloud Run管理者ロール（`run.admin`）
- サービスアカウントユーザーロール（`iam.serviceAccountUser`）

を割り当てなければなりません。

これはGCPコンソール上の操作で設定が可能。
![cloudbuild-serviceaccout.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/e94e454e-0953-8861-c357-672f66e66c2f.png)
詳しくは、[Cloud Buildを使用したCloud Runへのデプロイ](https://cloud.google.com/build/docs/deploying-builds/deploy-cloud-run?hl=ja#required_iam_permissions)を参考にしてください。


## Cloud Run を実行してみよう。
`error`の解消が終わり、`cloud build triigger`が正常終了すると、
いよいよ、`deploy`された`Cloud Run Service`のリンクを実行して、
`Application`が実行されている事を確認することができます。

対象の`Cloud Run Service`の`URL`を実行して下記のスクショが表示されれば成功です。
![cicd-cloudrun0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/7e835a1f-57af-8350-9882-6a6c86372631.png)
↓ Execution Result
![cicd-cloudrun1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/37cb16af-c7f6-7ca7-77fa-d1c0eaf4dc8d.png)

## Cloud Run の Canary Test release を行ってみよう。
最後に`Canary Test release`を実装して、この記事の締めとしたいと思います。

こちらも動画の内容に沿って行いますが、やることは２つです。
- 作成した `cloudbuild.yaml` の `Deploy App step` で、`--no-traffic` を追加する。
- `Canary release step` を追記する。

下記は`Canary Test release`に対応するように修正した`cloudbuid.yaml`です。

```
steps:
  # Build app
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-f', 'golang/go-cloud-run-hello-world/Dockerfile', '-t', 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/my-repo/hello:$COMMIT_SHA', './golang/go-cloud-run-hello-world']
    id: BUILD

  # Storage of the image
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/my-repo/hello:$COMMIT_SHA']
    id: STORAGE

  # Deploy app
  - name: 'gcr.io/cloud-builders/gcloud'
    args: ['run', 'deploy', 'hello-site', 
        '--image', 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/my-repo/hello:$COMMIT_SHA',
        '--region', 'asia-northeast1',
        '--platform', 'managed',
        '--allow-unauthenticated',
        '--no-traffic']
    id: DEPLOY

  # Canary release
  - name: 'gcr.io/cloud-builders/gcloud'
    args: ['run', 'services', 'update-traffic', 'hello-site',
        '--region', 'asia-northeast1',
        '--to-revisions=LATEST=50']
    id: CANARY
```

この`cloudbuild.yaml`を`github`へ`push`、`cloud build triigger`が
実行され、正常に終了すると、Cloud Run内のリビジョンのトラフィックが分割され、
`Canary Test release`を実装することができます。

今回の設定では、トラフィックを50％に設定していますので、
２つのリビジョンに対して、トラフィックが50％ずつ流れていれば成功です。
![CanaryTestrelease1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/ab8e71b0-6bda-d94b-a5ce-74e9970af2b6.png)
対象の`Cloud Run Service`の`URL`を何度か`reload`してみてください。
下記のスクショが切り替わり表示されれば、`Canary Test release`は成功になります。

↓ Execution Result
![CanaryTestrelease2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/06981a78-85a1-070e-1f22-1881ccca2a92.png)
↓ Execution Result
![CanaryTestrelease3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952807/48fb90d6-7a8c-565e-10d2-1b5c62a2bac4.png)

## 終わりに
今回の記事は、動画を視聴しまして、
実際に『手を動かしてみた』という内容で書きました。

実際に自分自身でやってみる事で、躓いてしまった部分もありました。

これからCICDのPipeLineに触れてみようと思っている人、
動画を視聴されまして、実際に試しにやってみたが
躓いてみてしまった人は、参考にしていただけると幸いです。

あとで『じっくり読みたい』、『繰り返し読みたい』と
思ってくれましたら、『`ストック`』へ登録、
この記事が読まれている方にとって、
参考になる記事となりましたら、『`いいね`』を
付けていただけますと、励みになりますので、
よろしくお願いします。