GoogleCloudマネージドサービスのみでCI/CDパイプラインを構築しCloudRunにデプロイする

# はじめに

皆さんCI/CDしてますか？
今回はGoogle Cloudのマネージドサービスのみを使ってCI/CDパイプラインを構築し、アプリをCloud Runにデプロイしてみたいと思います。使うサービスは下記イラストの通りです。

![スクリーンショット 2024-03-16 19.34.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/284119d9-1f61-406a-89b6-2323fe7c8c09.png)

※2024年3月時点での画面や機能となっており、プレビュー機能に関する記述も含みます

:::note warn
無料枠でCloud Buildを使用する場合は、以下のリージョンでしか使用できません。記事内では東京リージョンで作成していますが、台湾リージョンで作り直しています。

- us-central1
- us-west2
- europe-west1
- asia-east1
- australia-southeast1
- southamerica-east1
:::

https://cloud.google.com/build/docs/locations?hl=ja#restricted_regions_for_some_projects

# Google Cloudサービスの設定

## Artifact Registry

まずはArtifact Registry APIを有効にしましょう
![スクリーンショット 2024-03-16 15.12.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/7e92b52a-14ed-24cd-32ee-aa1790e73302.png)

APIを有効にしてコンソール画面にアクセスすると、このような画面が表示されるはずです。オプションを有効にするとイメージあたり$0.26で脆弱性スキャンをしてくれます。今回は省略しますが、必要に応じて有効化してよいでしょう。
![スクリーンショット 2024-03-16 15.15.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/43abbbe2-9588-98b8-9454-2b2f5b178df2.png)

「＋リポジトリを作成」ボタンを押下し、今回は以下のように設定し、画面左下部の「＋作成」ボタンを押下してリポジトリの作成をしていきます。

| 項目 | 設定値 |
|:-----------|:------------|
| 名前 | 任意の名前 |
| 形式 | Docker | 
| モード | 標準 |
| リージョン | 任意のリージョン |
| 暗号化 | Google が管理する暗号鍵 |

`不変のイメージタグ`
このオプションを有効にすると、タグ付きイメージを削除したり、タグをイメージから削除するといったことができなくなります。今回は不要な設定なのでオフにします。

`クリーンアップポリシー`
このオプションを有効にすると、アーティファクトバージョンを削除するポリシーを設定することができます。例えば、アップロードから30日経過したアーティファクトバージョンを自動的に削除するといったことができるようになります。今回は特に設定しません。

これでリポジトリの作成は完了です。

![スクリーンショット 2024-03-16 15.45.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/03ad34b5-9bd3-37ba-b020-38764951ec13.png)

## Cloud Source Repositories

コンソール上部から「Cloud Source Repositories」と検索して画面遷移すると、見慣れたコンソール画面とは少し違う画面に遷移します。早速「開始」>「リポジトリを作成」という順に押していきます。

![スクリーンショット 2024-03-16 15.54.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/dd4314e0-7c09-5ec3-9e22-ebe1cd2734fb.png)

「新しいリポジトリを作成」を選択し、「続行」を押下します。

![スクリーンショット 2024-03-16 15.56.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/ff5d31db-6a3a-6c30-21c8-88980713e46e.png)

任意のリポジトリ名とプロジェクトIDを設定し、「作成」を押下します。

![スクリーンショット 2024-03-16 15.57.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/57ae36ec-19fa-3c1c-ac6b-7a0a0a673b97.png)

今回はクローンを作成する手順で、認証方法はGoogle Cloud SDKで進めていきます。
Google Cloud SDKを使用して認証を行った後、画面のコマンドに従って操作していきます。pushが完了したらブラウザを再起動してみます。

![スクリーンショット 2024-03-16 16.05.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/a0f932cd-ed9b-b39c-4f1c-e8f96cacbf36.png)

適当にpushしたREADME.mdのコミットが反映されていることが分かります。

![スクリーンショット 2024-03-16 16.15.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/4b37f2a8-b305-8727-60bd-ce520e44d1da.png)

次にCloud Buildの設定に移ります。

## Cloud Build

Artifact Registryと同じようにCloud Build APIを有効にします。

![スクリーンショット 2024-03-16 16.19.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/216077c0-0fef-68df-1439-b91142ad1a97.png)

次にCloud Buildのトリガーを作成していきます。
「＋トリガーを作成」を押下します。

![スクリーンショット 2024-03-16 16.23.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/63d2db5e-837c-1e44-b31c-f57a2e106e1b.png)

以下のように設定をして画面左下の「作成」を押下します。

| 項目 | 設定値 |
|:-----------|:------------|
| 名前 | 任意の名前 |
| リージョン | 任意のリージョン |
| イベント | ブランチにpushする |
| ソース | 第1世代 |
| リポジトリ | 作成したリポジトリを選択 |
| ブランチ | ^main$ |
| 構成 | Cloud Build 構成ファイル（yaml または json） |
| ロケーション | 作成したリポジトリを選択 |
| Cloud Build 構成ファイルの場所 | cloudbuild.yaml |

![スクリーンショット 2024-03-16 16.27.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/bebf52fa-10ae-007b-555c-6cb85e9336bf.png)

※Cloud Source Repositories からリポジトリを接続できるのは、`Cloud Build リポジトリ（第１世代）`のみです。

### 権限設定

Cloud Buildトリガーを使用してCloud Runにデプロイするためには、Cloud Buildのサービスアカウント権限から`Cloud Run 管理者`と`サービス アカウント ユーザー`を有効にする必要があります。
この設定をしないと、トリガーを使用したデプロイ時に以下のようなエラーが出てデプロイすることができません。
`ERROR: (gcloud.run.deploy) PERMISSION_DENIED: Permission 'run.services.get' denied on resource 'namespaces/{project名}/services/{service名}' (or resource may not exist).`


![スクリーンショット 2024-03-16 18.17.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/cde4c022-6e24-7c37-7964-e5a3ab1a9d36.png)


### cloudbuild.yamlの作成

今回作成したファイルは以下です。
substitutionsを変更するだけでそのまま使えると思います。
`--allow-unauthenticated`を設定すると、未認証の呼び出しが許可できます。今回は簡単のために設定します。

```yaml:cloudbuild.yaml
steps:
# コンテナイメージのビルド
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', '${_REGION}-docker.pkg.dev/${_PROJECT_ID}/${_REPOSITORY}/${_IMAGE_NAME}:$COMMIT_SHA', '.']
# コンテナイメージをArtifact Registryにプッシュ
- name: 'gcr.io/cloud-builders/docker'
  args: ['push', '${_REGION}-docker.pkg.dev/${_PROJECT_ID}/${_REPOSITORY}/${_IMAGE_NAME}:$COMMIT_SHA']
# コンテナイメージをCloud Runにデプロイ
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
  entrypoint: gcloud
  args:
  - 'run'
  - 'deploy'
  - '${_SERVICE_NAME}'
  - '--image'
  - '${_REGION}-docker.pkg.dev/${_PROJECT_ID}/${_REPOSITORY}/${_IMAGE_NAME}:$COMMIT_SHA'
  - '--region'
  - '${_REGION}'
  - '--allow-unauthenticated'

substitutions:
  _REGION: {リージョン}
  _PROJECT_ID: {プロジェクトID}
  _REPOSITORY: {ArtifactRegistryのリポジトリ}
  _IMAGE_NAME: {イメージ名}
  _SERVICE_NAME: {CloudRunサービス名}
```

# サンプルアプリ作成

簡単なHTTPサーバーを作成し、ルートパスにアクセスすると"Hello, World!"と表示するGoアプリケーションをデプロイしたいと思います。

```md:ファイル構造
.
├── cloudbuild.yaml
├── Dockerfile
├── main.go
├── go.mod
└── README.md
```


```go:main.go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "Hello, World!")
	})

	fmt.Println("Server started on http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}
```

```dockerfile:Dockerfile
FROM golang:1.21
WORKDIR /app
COPY go.mod ./
RUN go mod download
COPY . .
RUN go build -o main
EXPOSE 8080
CMD ["./main"]
```

# いざ実行

Cloud Source Repositoriesにpushします😎
`git push origin main`

Cloud Buildの履歴画面を見ると、作成したCloud Buildトリガーによってビルドが行われています👏

![スクリーンショット 2024-03-16 19.06.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/94587315-5b19-7af0-804c-a65213af018a.png)

ArtifactRegistryにもイメージが格納されていますね！

![スクリーンショット 2024-03-16 19.08.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/c1f4758b-8bd3-4bcb-4d0b-6008eb9b02bb.png)

Cloud Runの画面を見に行くと、たしかにデプロイされています💪

![スクリーンショット 2024-03-16 19.11.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/5cf17c20-058b-186d-9c03-a8671d824baa.png)

デプロイしたサービス名を押下し、URLをコピーしてcurlを叩くと...

![スクリーンショット 2024-03-16 19.13.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1857740/ebfc0238-70d7-59cd-f914-501a5019ee70.png)

```bash
❯ curl https://matsuidev-service-hello-2vpsyoh4ca-de.a.run.app/
Hello, World!
```

無事に表示されました👏👏👏

# おわりに

いかがでしたでしょうか。
今回はGoogleCloudのマネージドサービスである「Artifact Registry」「Cloud Source Repositories」「Cloud Build」を組み合わせ、mainブランチにpushするとCloud RunへのデプロイまでしてくれるCI/CDパイプラインを作成してみました。
今回はCloud Runにデプロイしましたが、`cloudbuild.yaml`を書き換えることで GKE や Cloud Functions などにもデプロイすることが可能です！
最後まで読んでいただきありがとうございました😸