かなり前 GitHub Packages でコンテナイメージを扱ってました。
その後 Container Registry が登場しました。Packages の時は public なイメージの Pull にも認証が必要でしたが、Container Registry では不要になっています。そして既存の Packages のコンテナイメージは順次 Container Registry に移行されるみたいです。
OSS じゃない開発では private な Container Registry に開発中のアプリのイメージを push し、CI パイプラインで pull して利用するケースが多いと思います。CI で Kubernetes クラスターにデプロイしてテストするケースもあるでしょう。その時の認証情報の 扱いなどが気になったので調べてみました。
まず、手元の PC からの push / pull。
GitHub の Settings / Developer settings で PAT (Personal Access Token) を作成します。この時、write:packages をスコープに含める必要があります。この PAT を環境変数に設定して ghcr.io に docker login します*1。
export CR_PAT=YOUR_TOKEN echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin
この状態で docker build / tag / push するとプライベートなパッケージとしてコンテナが登録されます *2。
docker push ghcr.io/OWNER/IMAGE_NAME:latest
GitHub Actions でイメージをビルドして push するには Container Registry と Actions を実行するリポジトリを接続した上で Container Registry への書き込み権限を付与する必要があります。
手動で push した直後はリポジトリとの関連付けがないので Registry のページには接続用の UI が表示されています。
Actions を実行するリポジトリを追加して、Manage Actions access のセクションでリポジトリの Role を Write に指定します。
これで、GitHub Actions で PAT を使わなくても暗黙に設定される GITHUB_TOKEN を使ってプライベートイメージを扱えるようになります。PAT はセキュリティのため比較的短い期間で expire するのが普通で、長期間 expire しない PAT を GitHub Actions では利用しないことが推奨されています。
イメージをビルドして、push するワークフローの例です。docker コマンドも使えますが、ビルド、タグ付け、push をしてくれる Action を利用しました。
jobs: Build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Build and push container image uses: elgohr/Publish-Docker-Github-Action@master with: name: ghcr.io/kondoumh/gh-container-registry/nodejs-server username: kondoumh password: ${{ secrets.GITHUB_TOKEN }} registry: ghcr.io
GitHub Actions で Minikube や Kind などの Kubernetes 環境にプライベートなコンテナイメージを使ってデプロイするには、事前に Secret を適用しておき、イメージの manifest で Secret を指定します。GitHub Actions のステップでは以下のように GITHUB_TOKEN を docker-password に指定して Secret を作成すれば OK です。
Deploy: needs: [Build] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - run: minikube start - name: Create secret for GitHub container registry run: | kubectl create secret docker-registry regcred \ --docker-server=https://ghcr.io \ --docker-username=kondoumh \ --docker-password=${{ secrets.GITHUB_TOKEN }} - name: Deploy to minikube run: kubectl apply -f manifest.yml
適用している manifest では以下のように imagePullSecrets
で Secret を指定します。
apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: nodejs-api name: nodejs-api spec: replicas: 2 selector: matchLabels: app: nodejs-api template: metadata: labels: app: nodejs-api spec: containers: - image: ghcr.io/kondoumh/gh-container-registry/nodejs-server:latest name: nodejs-server imagePullPolicy: Always imagePullSecrets: - name: regcred
パブリックなイメージを使用する場合は Secret は不要で使えました。やはりこれが Package registry に比べた改善点ですかね。 プライベートなイメージはデータ転送やストレージへの課金が発生するので注意が必要です。GitHub Actions によってトリガーされるデータ転送は無料ですが、GITHUB_TOKEN 使用しているかどうかで判定しているようですので料金の面からも PAT は使わない方がよさそうです。