GitHub Actionsでdocker/build-push-actionを利用してプライベートリポジトリをcloneする

## この記事は

プライベートリポジトリをクローンするためのSSHの秘密鍵をSecretsに登録し、それを [docker/build-pusht-actions](https://github.com/docker/build-push-action) で利用してコンテナをビルド・プッシュする方法です。

## 参考記事

GitHub Actionsのワークフローでプライベートリポジトリをクローンするよう方法やsecretsへの登録は以下の記事を参考にしてください。

1. [GithubActionsでプライベートリポジトリをsubmoduleとして取り込む#ssh方式](https://qiita.com/u_nation/items/8ff79a9831c05f3f1d1d#ssh%E6%96%B9%E5%BC%8F)
2. [docker buildする際にhost側のssh keyを使ってbuildする](https://qiita.com/toyama0919/items/190eb19298e523094ba2)
3. [GitHub Actionsでビルドするコンテナ内でGitHubのprivate repositoryをセキュアに参照する](https://qiita.com/elyunim26/items/02a4f14bdf99874d8c16)

3つ目の記事とやりたいことはほぼ同じですが、docker buildを独自ステップとして実装されています。
今回はこれを `docker/build-push-action` で実現します。

## docker/build-push-action でホストのSSH鍵を利用してプライベートリポジトリにアクセスする

https://github.com/docker/build-push-action#customizing の `ssh: default` を利用します。

```yaml
     - uses: docker/build-push-action@v3
        with:
          push: true
          tags: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest
          ssh: default
```

ただし、このままでは `SSH_AUTH_SOCK` がない旨のエラーになり秘密鍵を共有できません。

事前にSSHエージェントを起動、 `ssh-add` しておき、`docker/build-push-action` から参照できるようにしておく必要があります。
`eval $(ssh-agent -s)` することでSSHエージェントが起動し `SSH_AUTH_SOCK` が設定されます。
これを環境変数に設定(GITHUB_ENVに追加)することで `build-push-action` のステップでも利用できるようにします。

```yaml
      - name: Set ENV for docker build
        env:
          TOKEN: ${{ secrets.TOKEN }}
        run: |
          mkdir -p ~/.ssh
          echo "$TOKEN" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          eval $(ssh-agent -s)
          ssh-add ~/.ssh/id_rsa
          echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" >> $GITHUB_ENV
```

共有された秘密鍵を利用してgit cloneする場合、Dockerfileでは以下のようにします。

```dockerfile
RUN --mount=type=ssh git clone xxx
```

## AWS ECRにCDするGitHub Actionsワークフローサンプル

メインブランチが更新され、CIが成功した場合にECRに向けたCDを走らせる例です。
ビルドキャッシュも利用しています。

ECRにプッシュするため事前にECRログインが必要なので、そのためのAWS CredentialsもSecretsに登録しています。

```yaml
---
name: cd
on:
  workflow_dispatch:
  workflow_run:
    workflows:
      - "ci"
    branches:
      - main
    types:
      - "completed"

env:
  ECR_REPOSITORY: ogawatti/test

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
      - uses: actions/checkout@v3
      - uses: docker/setup-buildx-action@v1
      - uses: actions/cache@v2
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-buildx-
      - name: Set ENV for docker build
        env:
          TOKEN: ${{ secrets.TOKEN }}
        run: |
          mkdir -p ~/.ssh
          echo "$TOKEN" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          eval $(ssh-agent -s)
          ssh-add ~/.ssh/id_rsa
          echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" >> $GITHUB_ENV
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
      - uses: docker/build-push-action@v3
        with:
          push: true
          tags: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:latest
          ssh: default
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
      - name: Move cache
        run: |
          rm -rf /tmp/.buildx-cache
          mv /tmp/.buildx-cache-new /tmp/.buildx-cache

```

## ハマりどころ

ステップ内では `***` のように秘匿してくれますが、これを `ENV` や  `build-args` 等でビルドに渡すことはできません。
正確には、改行付きのSecretsを渡した場合に中身がどうなっているかが分かりませんでした。

ビルド中にコンテナ内で書き出した秘密鍵を `ssh-add` しようとしても `invalid format` になってしまい、 `head` 等で確認しようにも、書き出された値が空だったり秘匿されていたりでデバッグがかなり苦しい。

ローカルでのビルドでは `build-args` を利用していたためそちらの方向で考えていましたが断念し、正攻法(?)で行くことになりました。