🐺

GitHub Container Registryを使ってDockerイメージを管理する

に公開

はじめに

GitHub Container Registry(ghcr.io)使用したDockerイメージ管理とActionsの組み込みについて触れている記事です。

本記事では、手動でのイメージ管理から GitHub Actions での自動化まで段階的に進めていきます。

GitHub Container Registry

GitHubの公式ドキュメントによると、GitHub Container Registry(以下GHCR)は以下のように定義されています

The Container registry stores container images within your organization or personal account, and allows you to associate an image with a repository.

つまり、GHCRは個人アカウントまたは組織内でコンテナイメージを保存・管理できるサービスです。

https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-container-registry

主な特徴:

  • URL: ghcr.io
  • 認証: Personal Access Token (PAT) または GitHub Actions の GITHUB_TOKEN
  • 権限管理: リポジトリと連携、または独立した権限設定が可能
  • 料金: パブリックイメージは無料、プライベートは GitHub Packages の料金体系に従う

手動で push してみる

まずは手動でイメージをpushして、基本的な流れを掴みます。

Personal Access Token (PAT) の作成

  1. Personal Access Token (PAT) の作成
  2. 必要な権限を選択:
    write:packages(自動的に read:packages も選択される)

レジストリへのログインとpush

公式の手順より参照

# トークンを環境変数に設定
export CR_PAT=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# GitHub Container Registry にログイン
echo $CR_PAT | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin

# イメージをビルド
docker build -t my-app:latest .

# GHCRの命名規則に従ってタグ付け
docker tag my-app:latest ghcr.io/YOUR_USERNAME/my-app:latest

# イメージをpush
docker push ghcr.io/YOUR_USERNAME/my-app:latest

https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-container-registry#pushing-container-images

pushしたイメージの確認

今回は組織で実施しているためhttps://github.com/orgs/your-org/packagesで確認できます。

GitHub Actions で push してみる

ローカルで実施した手順を Actions 上で実施できるようにします。

最初の自動化ワークフロー

dockerが提供しているcomposite actionがあるのでそちらを利用していきます。

https://github.com/docker/login-action

https://github.com/docker/build-push-action

name: Docker Build and Push

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true  # 重要:これがないとpushされません!
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

より実践的なタグ管理

latest タグだけでなく、バージョン管理もしたい場合はdocker/metadata-action を使うと、Gitの情報から自動的に適切なタグを生成できます。

https://github.com/docker/metadata-action

name: Docker Build and Push with Tags

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,prefix={{date 'YYYYMMDD'}}-

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

別のワークフローから実行

ビルドしたイメージを定期的に実行します

name: Run Container

on:
  workflow_dispatch:

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  run:
    runs-on: ubuntu-latest
    permissions:
      packages: read  # 読み取り権限のみ

    steps:
      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Run container
        run: |
          docker run --rm \
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
            npm start

トラブル

進める中でいくつか困りポイントあったので備忘録的に記載しています。

手動でpushしたいケース

docker loginができていれば自前でpushすることも可能です。

  - name: Build and push Docker image
    run: |
        docker buildx build . \
        --push \
        --platform linux/amd64 \
        -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
        -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}

docker image 名は lower のみ

docker image は 基本的にlowerケースのみを期待しているのでリポジトリ名などで利用する場合は気をつける

${{ github.repository }} CamelCaseなど入ってくる可能性がある

platform問題

ローカル環境では、それぞれのOSでbuildされるが、github actions上ではubuntu上で実行されるため、プラットフォームlinux/amd64の指定を忘れない

https://docs.github.com/ja/enterprise-cloud@latest/actions/use-cases-and-examples/publishing-packages/publishing-docker-images

もしくはマルチプラットフォームに対応する

https://docs.docker.com/build/ci/github-actions/multi-platform/

Actions上の名前解決

actions上ではlocalhostと接続ができないので--add-host=host.docker.internal:host-gatewayによる接続できるようオプションを追加する

こちら参考にさせていただきました。

https://gotohayato.com/content/561/

jarファイルの取り扱い

dockerfile内でgraldewのtaskなどでjarファイルを生成しCOPYしても期待通り動かない場合は
dockerfile外で生成したjarファイルをARGで渡すと期待通り読み込まれます。

こちら参考にさせていただきました。

https://www.tempmail.us.com/ja/yaml-dockerfile/docker-および-github-アクションの-jar-ファイルの問題の修正

Discussion