GitHub Container Registry でパブリックイメージを公開する

[Docker Hub](https://hub.docker.com/) が無料プランでの制限を強化する[^dockerhub]一方、GitHub Container Registry が発表された[^ghcr]。
2019年から提供されるようになった GitHub Package Registry[^ghpr] でも Docker Image は扱えたのだけど、GitHub Container Registry として独立させることで、ユーザ体験とパフォーマンスの向上を目指すとのこと。

[^dockerhub]: https://www.docker.com/pricing/resource-consumption-updates
[^ghcr]: https://github.blog/2020-09-01-introducing-github-container-registry/
[^ghpr]: https://github.blog/2019-05-10-introducing-github-package-registry/

GitHub Container Registry(以下 ghcr.io)は2020/09/06時点ではまだ、Public Beta だけど、Github自身が公開しているGithub Action [Super\-Linter](https://github.com/marketplace/actions/super-linter)のDocker Imageはすでに ghcr.io のパブリック・イメージとして公開されている。スター5.5k の Github Action のイメージに使用しようとしているのでそれなりに安定稼働が期待できるのかな？[^super_linter]

- [Package super\-linter](https://github.com/orgs/github/packages/container/super-linter/32030)

[^super_linter]: リポジトリを調べてみると、2020/09/06時点ではmasterではghcr.ioからイメージをpullするように変更されているものの、Actionとして公開されているものはまだ、DockerHubかpullするようになっている様子。

利用料金については次の様になっている。

- パブリック・イメージの公開は無料
- GAまでの間はプライベートイメージも無料<br>
  （GAしたら GitHub Packages の一部として同様のプライスモデルで課金）

## パブリック・イメージを公開してみた

[Prontoを実行するGithub Actionを作った](https://qiita.com/HeRo/items/a8c67a4327ed8321657f)で紹介したGithub Action [Pronto Action](https://github.com/marketplace/actions/pronto-action)で利用している Docker Image は元々、Docker Hub でイメージを公開していた。ところが、Pullの回数にも制限がかかるとの発表があったので、パブリックイメージなら無料な ghcr.io に移行してみた。

Docker Hubの場合には、Docker Hubの自動ビルド機能を利用して、masterへのPushやタグをプッシュしたときにイメージをビルドするようにしていた。
ghcr.io で公開するイメージは Github Action でビルドするのが手軽。

公開の手順は次の通り。

1. ghcr.io アクセス用の Personal Access Token を作る
2. イメージをビルドする（Dockerfile を含む）リポジトリに Github Workflow を追加する
3. パッケージをパブリックに設定変更する

一度、仕組みを作ってしまえば、後は自動でビルド、自動で公開してくれる。

### ghcr.io アクセス用の Personal Access Token を作る
GHCRが公開された当初はワークフローでデフォルトで利用できる `GITHUB_TOKEN` では GHCR に Push できなかったが、その後のアップデートでできるようになった。
なので、以下はわざわざ Private Access Token を利用する場合の方法についての記述である。

[Pushing and pulling Docker images](https://docs.github.com/en/packages/managing-container-images-with-github-container-registry/pushing-and-pulling-docker-images)に ghcr.io への読み書きについて基本的なことが書いてある。
それによると、パスワードの代わりに Personal Access Token(以下PAT）を使うと書いてある。
もちろん、パブリック・イメージをPullするだけならログインする必要はないのだけど、Pushしたいので用意する必要がある。
Github Workflow でPushするなら、`secrets.GITHUB_TOKEN`が使えるでは？と思うかもしれないが、ドキュメントにダメって書いてある[^use_pat]。

[^use_pat]: https://docs.github.com/en/packages/getting-started-with-github-container-registry/migrating-to-github-container-registry-for-docker-images#updating-your-github-actions-workflow

ghcr.io で読み書きするためには[New personal access token](https://github.com/settings/tokens/new)にアクセスして、 `write:packages` を許可したPATを作成する。
下のスクリーンショットでは `write:packages` 以外も有効にしているが、`write:packages` を有効にしたら自動的に他も有効になる。セットで必要なようだ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32533/22d74a2f-d477-584b-de6d-507eed59d61e.png)

作成したPATは、イメージをビルドするリポジトリの Settings > Secrets にアクセスして、後でWorkflow内で参照できるように登録しておく。
このエントリでは `GHCR_TOKEN`というキーで登録したという体で説明する。

### イメージをビルドする（Dockerfile を含む）リポジトリに Github Workflow を追加する

[Introducing GitHub Container Registry](https://github.blog/2020-09-01-introducing-github-container-registry/)では、[starter\-workflows/docker\-publish\.yml](https://github.com/actions/starter-workflows/blob/188a1b09954720a23d484ebd4d825160cc174c6f/ci/docker-publish.yml)の利用が紹介されているのだけど、Github Actionのドキュメント[Publishing Docker images](https://docs.github.com/en/actions/language-and-framework-guides/publishing-docker-images)で紹介されているDocker社謹製の [Build and push Docker images](https://github.com/marketplace/actions/build-and-push-docker-images)のほうが、ビルドしたイメージのタグをよしなに調整してくれたり便利なのでこちらを使った。

で、Docker Image をビルドして ghcr.io に Push する Workflow は次の通り。

```yaml
name: Publish Docker image
on:
  push:
    branches:
      - master
      - develop
    tags:
      - '[0-9]+.[0-9]+.[0-9]+'
jobs:
  push_to_registry:
    name: Push Docker image to GitHub Container Registry
    runs-on: ubuntu-latest
    steps:
      - name: Check out the repo
        uses: actions/checkout@v2
      - name: Push to GitHub Container Registry
        uses: docker/build-push-action@v1
        with:
          username: ${{ github.actor }}
          password: ${{ secrets.GHCR_TOKEN }}
          registry: ghcr.io
          repository: heromo/pronto-action
          tag_with_ref: true
```

`master`ブランチまたは`develop`ブランチにpushした場合、あるいは[フィルターパターン](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet)`'[0-9]+.[0-9]+.[0-9]+'`にマッチするGitのタグ（例:`1.0.0`,`1.4.0`）をpushした時に実行される。
`master`ブランチまたは`develop`ブランチにpushした場合というのは、これらのブランチにコミットが追加された時というのと同意なので、プルリクエストをマージした場合にも実行される。

`registry` には `ghcr.io` を指定する。
`password` には先程、 Secrets に登録したキー`GHCR_TOKEN`への参照を設定する。
`repository` には *オーナー名/イメージ名* の形式でPush先を指定する。これはすべて小文字である必要がある（私はGithubのオーナー名に大文字を使っているのでそのまま大文字で設定したらエラーになった）。
`tag_with_ref: true`を設定していると、ビルドした Docker Image のタグを次の様によしなに設定してくれる[^tag_with_ref]。

- ブランチ`master` -> `latest`
- ブランチ`develop` -> `develop`
- タグ`1.4.0` -> `1.4.0`

[^tag_with_ref]: https://github.com/docker/build-push-action#tag_with_ref

### パッケージをパブリックに設定変更する

Pushされたイメージは、リポジトリには紐付いておらず、自分のGithubプロファイルページの Packages を開くと見つけることができる。できたばかりのパッケージはプライベートとなっている。

[Configuring visibility of container images for your personal account](https://docs.github.com/en/packages/managing-container-images-with-github-container-registry/configuring-access-control-and-visibility-for-container-images#configuring-visibility-of-container-images-for-your-personal-account)に書いてあるとおり、ページの右上の *Edit package* プルダウンで、*Package Setting* を選択すると設定ページが開く。
後は、Danger Zone の *Make public* ボタンをクリックすればパブリックになる。一度、パブリックにするとプライベートには戻せないので注意。

Github Action で利用するイメージであればパブリックにする必要がある。そうしないと、Workflowを実行した時にpullできなくてエラーとなる。

自分のための自分しか使わないイメージならプライベートにしておいても構わないのだけど、**GAになったら課金される**ことに注意が必要。

### まとめ

今回、Docker Hub で公開していたイメージを ghcr.io で公開してみた。
Github Actionで利用しているイメージを公開する場合、Github内ですべて閉じるので ghcr.io を使ったほうが手間が少ないと感じた。
パブリックだと無料で、回数制限もなさそうなのもよい。