Dock Stay
GitHub Actions でコンテナをビルドする
CI/CD

GitHub Actions でコンテナをビルドする

GitHub Actions で Docker イメージをビルドして GHCR にプッシュするまでの最小構成と、実務で押さえるべき主要ポイント。

GitHub Actions でコンテナをビルドする diagram

全体像

GitHub Actions でコンテナをビルドする最小構成は次の 4 ステップです。

  1. リポジトリをチェックアウトactions/checkout
  2. Buildx をセットアップdocker/setup-buildx-action。マルチアーキとキャッシュのため必須)
  3. レジストリにログインdocker/login-action
  4. ビルド + プッシュdocker/build-push-action

新規で組むときは「まずデフォルトブランチで docker/build-push-action が動くところまで」→「タグ戦略とキャッシュを足す」→「脆弱性スキャンを足す」の順で拡張するのが安全です。

最小構成のワークフロー

main ブランチへのプッシュで GHCR にイメージを push する例。

GITHUB_TOKEN だけで GHCR にアクセスできるので追加のシークレット設定は不要です。

bash
# .github/workflows/build.yml
name: build

on:
  push:
    branches: [main]

permissions:
  contents: read
  packages: write

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

metadata-action でタグを自動生成する

docker/metadata-action を使うと、ブランチ名・タグ名・SHA・セマンティックバージョンを組み合わせたタグとラベルを自動生成してくれます。

手書きで if github.ref == を並べるより保守性が高く、標準的な org.opencontainers.image.* ラベルも自動で付きます。

bash
      - id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,prefix=sha-,format=short
            type=raw,value=latest,enable={{is_default_branch}}

      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

PR ではプッシュしない運用

PR に対しては「ビルドが通るか」と「スキャン結果」だけを確認し、レジストリには載せない運用が無難です。

push: ${{ github.event_name != 'pull_request' }} のように条件化するか、PR 用に別ワークフローを組みます。

Fork PR の場合、GITHUB_TOKENpackages:write が付かないので、そもそもプッシュしようとすると失敗します。

pull_request_target を使う手はありますが、fork からの悪意あるコード混入リスク があるため、よく理解した上で使ってください。

実務で最低限入れたいもの

最小構成にプラスして、以下はほぼ必須です。

詳細は続くガイドで順に扱います。

  • ビルドキャッシュ: GHA キャッシュまたはレジストリキャッシュ(cicd-buildx-cache-strategy
  • マルチアーキビルド: amd64 / arm64 両対応(cicd-multi-arch-build
  • 脆弱性スキャン: Trivy / Grype と Dockerfile の lint(cicd-security-scan
  • 安全なレジストリ認証: ECR などは長期キーを避けて OIDC(cicd-registry-push-practice
  • タグ戦略の明文化: latest を本番で参照しない、デプロイ対象は shasemver 固定
  • Concurrency 制限: concurrency: { group: build-${{ github.ref }}, cancel-in-progress: true } で古い PR ビルドを自動キャンセル