GitHub Actions から Docker イメージを Artifact Registry に push する

GitHub リポジトリで管理している Docker イメージをビルドし、 GCP の Artifact Registry にプッシュする GitHub Actions を作成します。
GitHub Actions ではワークフローの実行トリガにタグやリリースの作成、PR の作成・更新などを選べ、開発の各フェーズに即した形でイメージをプッシュできます。

作成の大きな流れとしては以下の通りです。

1. GitHub Actions から Artifact Registry を操作するための Service Account を作成
1. 作成した Service Account に Artifact Registry への push 権限を付与
1. 前段で作成した Service Account の JSON 鍵を取得し、リポジトリの Secret に追加
1. setup-gcloud アクションを利用して、ビルドしたイメージを Artifact Registry へプッシュするワークフローを作成する

前提として、Artifact Registry にプッシュ対象のリポジトリは作成済みとします。

## GitHub Actions で利用する Service Account を作成する

```shell-session
$ gcloud iam service-accounts create docker-image-ci --display-name="Docker Image CI" --project=my-project
Created service account [docker-image-ci].
```

## Service Account に権限を与える

最小権限にする場合は、`artifactregistry.repositories.uploadArtifacts` だけを持ったカスタムロールを作成し、付与します。

```shell-session
$ gcloud iam roles create artifactRegistryCIRole --project=my-project \
  --title="Docker image CI Role" --description="Push docker image via CI" \
  --permissions=artifactregistry.repositories.uploadArtifacts --stage=BETA
Created role [artifactRegistryCIRole].
description: Push docker image via CI
etag: ***
includedPermissions:
- artifactregistry.repositories.uploadArtifacts
name: projects/my-project/roles/artifactRegistryCIRole
stage: BETA
title: Docker image CI Role

$ gcloud projects add-iam-policy-binding my-project \
--member=serviceAccount:docker-image-ci@my-project.iam.gserviceaccount.com \
--role=projects/my-project/roles/artifactRegistryCIRole
Updated IAM policy for project [my-project].
```

既存のロールで対応する場合は `roles/artifactregistry.writer` あたりが適切かと思います。

```shell-session
$ gcloud projects add-iam-policy-binding my-project \
--member=serviceAccount:docker-image-ci@my-project.iam.gserviceaccount.com \
--role=roles/artifactregistry.writer
Updated IAM policy for project [my-project].
```

## Service Account の JSON 鍵を取得する

```shell-session
$ gcloud iam service-accounts keys create key.json \
--iam-account=docker-image-ci@my-project.iam.gserviceaccount.com \
--project=my-project
created key [***] of type [json] as [key.json] for [docker-image-ci@my-project.iam.gserviceaccount.com]
```

## リポジトリの Secret に JSON 鍵を追加する

ダウンロードされた JSON 鍵を対象の GitHub リポジトリの Secret に登録します。

平文でも登録できますが、念のため Base64 エンコードしておきます。

```bash
cat key.json | base64
cat key.json | base64 | pbcopy # クリップボードにコピー(mac)
cat key.json | base64 | xclip -selection c # クリップボードにコピー(linux)
```

今回は、`GCLOUD_AUTH` という名称で Secret を登録します。
Secret は、リポジトリの Settings > Secrets から登録できます。
![blur.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66988/767a7774-931f-fbed-e384-0011c489053a.png)
Add secret で登録完了です。

## ワークフローを作成する

Artifact Registry へ docker push を行うため、`gcloud auth configure-docker {region}-docker.pkg.dev` を実行できるようにします。
`google-github-actions/setup-gcloud` アクションを利用すると、前段でリポジトリの Secret に登録した JSON 鍵を利用して gcloud cli のセットアップができます。

https://github.com/google-github-actions/setup-gcloud

というわけでワークフローが以下の通りです。
今回は tag の push をトリガーとして、タグ名をそのままイメージのタグにしています。

```yaml:build-push.yaml
name: Build and Push Image

on:
  push:
    tags:
    - "*"

jobs:
  build-and-publish:
    name: Build and Push docker image
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v2
      with:
        ref: ${{ github.ref }}

    - name: Setup Google Cloud
      uses: google-github-actions/setup-gcloud@master
      with:
        service_account_key: ${{ secrets.GCLOUD_AUTH }}
        project_id: my-project

    - name: Configure docker for artifact registry
      run: |
        gcloud auth configure-docker asia-docker.pkg.dev
    
    - name: set TAG
      run: |
        echo "TAG=$(echo $GITHUB_REF | awk -F/ '{print $NF}')" >> $GITHUB_ENV
    
    - name: Build
      run: |
        docker build -t asia-docker.pkg.dev/my-project/sample-repository/example:${{ env.TAG }} ./

    - name: Push
      run: |
        docker push asia-docker.pkg.dev/my-project/sample-repository/example:${{ env.TAG }}
```

ワークフローの各ステップでは、以下の順序で処理を実行しています。

1. タグの切られたコミットでチェックアウト
1. gcloud cli のセットアップ
1. Artifact Registry へプッシュできるよう Docker を構成
1. タグ名の取得と環境変数への登録
1. Docker イメージのビルド
1. ビルドされたイメージを Artifact Registry へプッシュ

以上、Docker イメージを Artifact Registry へプッシュする GitHub Actions の紹介でした。

## refs

https://cloud.google.com/artifact-registry/docs/docker/quickstart

https://github.com/google-github-actions/setup-gcloud

https://acaird.github.io/computers/2020/02/11/github-google-container-cloud-run