GHCR (GitHub Container Registry) とは — Docker Hub との違い、使い方、料金
CI のログや docker-compose.yml で、ghcr.io/... で始まるイメージ名を見かけることが増えてきました。GHCR (GitHub Container Registry) は GitHub が運営するコンテナイメージのレジストリです。コードが GitHub にあるならイメージも同じ場所に置く、という流れが標準のように定着していて、その中心にあるサービスです。
この記事は GHCR に初めて触れる方を想定して、四つの質問に答えます。
- GHCR とは正確には何か
- Docker Hub と何が違うのか
- 料金はいくらか
- どう使うのか (push/pull、GitHub Actions)
push/pull コマンド自体が初めてなら、先に Docker 基礎 #5 レジストリ を読むのがおすすめです。この記事はその中の GHCR を正面から掘り下げます。
GHCR とは #
GHCR は、GitHub Packages というパッケージホスティングサービスのコンテナ部門です。アドレスは ghcr.io で、OCI (Open Container Initiative) 標準に従うレジストリなので、Docker から見れば Docker Hub とまったく同じように動きます。docker login、docker push、docker pull の流れがそのまま使えて、podman や Helm チャート (OCI アーティファクト) のような他のツールでも利用できます。
イメージ名はこの形です。
ghcr.io/OWNER/IMAGE_NAME:TAG
ghcr.io/curtis/hello-docker:1.0
───── ──────────── ───
アカウント/組織 イメージ名 タグOWNER は GitHub のアカウント名または組織名で、すべて小文字である必要があります。GitHub アカウントが MyName なら、イメージのパスは ghcr.io/myname/... になります。
一つだけ概念を押さえておくと、残りが楽になります。GHCR に上がったイメージは、GitHub 上ではパッケージ (package) という独立した単位で管理されます。コードリポジトリに従属するのではなくアカウント/組織の下に存在し、必要なら特定のリポジトリと紐付けられます。公開範囲 (public/private) もリポジトリではなくパッケージ単位で決めます。
Docker Hub と何が違うのか #
Docker を学ぶとき最初に出会うレジストリは、たいてい Docker Hub です。しかし実務で自分のサービスのイメージを置く場所を選ぶ段階になると、GHCR が先に検討されることが多くなります。違いを表にまとめるとこうなります。
| Docker Hub | GHCR | |
|---|---|---|
| 運営主体 | Docker | GitHub |
公式イメージ (python, nginx など) | あり | なし |
| pull 回数制限 | 未認証 100 回/6 時間 (IP 単位)、無料アカウント 200 回/6 時間 | 公表された回数制限なし |
| 権限モデル | Docker Hub の別アカウントと組織 | GitHub のアカウント、組織、チーム権限をそのまま利用 |
| private リポジトリ | 無料プランは 1 個、それ以上は有料プラン | 個数制限なし、現在無料 (下の料金の節を参照) |
| GitHub Actions 連携 | 別途シークレット登録が必要 | GITHUB_TOKEN で即認証 |
実務の感覚で要約するとこうなります。
ベースイメージは Docker Hub から来ます。 python:3.14-slim や nginx:1.27 のような公式イメージは Docker Hub にしかありません。GHCR をメインのレジストリにしても、Dockerfile の FROM は Docker Hub を向いているケースがほとんどです。
pull 制限は CI で体感します。 Docker Hub は未認証の状態では IP あたり 6 時間に 100 回で pull を制限します。問題は、CI 環境 (GitHub Actions、GitLab CI など) が IP を他のユーザーと共有している点です。自分は数回しか pull していなくても、同じ IP の別のビルドが上限を使い切って toomanyrequests エラーに遭遇することがあります。GHCR は公式ドキュメントに公表された pull 回数制限がないため、自分のサービスのイメージを GHCR に置けばこの問題から抜け出せます。
権限管理が一つにまとまります。 Docker Hub を使うと、メンバーのアカウントと権限を GitHub と Docker Hub の二箇所で管理することになります。GHCR は GitHub の組織とチーム権限をそのまま使うので、リポジトリへのアクセス権を持つ人にイメージへのアクセス権を与える作業が、設定一回で済みます。
料金 — 今は無料 #
GHCR の検索でよく出てくる質問なので、独立した節にします。結論から言うと、コンテナレジストリのストレージと帯域は現在無料です。 public イメージでも private イメージでも同じです。GitHub の公式ドキュメントが「currently free」と明記していて、課金を始める場合は最低 1 か月前に告知するとしています。
課金が始まった場合の基準もドキュメントにあります。GitHub Packages の一般的な料金体系は、private パッケージに対してプランごとの無料枠を設ける方式です。
| プラン | ストレージ | 月間転送量 (ダウンロード) |
|---|---|---|
| Free | 500MB | 1GB |
| Pro | 2GB | 10GB |
| Team | 2GB | 10GB |
| Enterprise Cloud | 50GB | 100GB |
二つのケースは課金対象から外れます。public パッケージは無条件で無料、そして GitHub Actions の中で GITHUB_TOKEN を使って受け取る転送量も課金されません。 つまりビルドとデプロイが GitHub Actions の中で回る構成なら、課金が始まっても負担が大きくならないように設計されています。
数字は 2026 年 7 月のドキュメント基準です。料金ポリシーは変わる可能性があるので、判断の前に GitHub Packages billing のドキュメントを一度確認してください。
使い方 — トークン発行から pull まで #
1. PAT (classic) を作る #
GHCR の認証には GitHub のパスワードではなく PAT (Personal Access Token) を使います。ここで注意点が一つ。GitHub には新型の fine-grained PAT と旧型の classic PAT がありますが、レジストリの認証にはまだ classic PAT しか使えません。
GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) でトークンを作り、権限にチェックを入れます。
- push までするなら
write:packages - pull だけなら
read:packages - パッケージの削除もするなら
delete:packages
2. ログイン #
export CR_PAT=ghp_xxxxxxxxxxxxxxxxxx
echo $CR_PAT | docker login ghcr.io -u curtis --password-stdin
# Login Succeededトークンを --password-stdin で渡せば、シェルの履歴に残りません。
3. タグを付けて push #
イメージ名に ghcr.io/アカウント名 が入っていて初めて、Docker は送り先が分かります。
docker tag hello-docker ghcr.io/curtis/hello-docker:1.0
docker push ghcr.io/curtis/hello-docker:1.04. 公開範囲を変える #
最初に push したパッケージはデフォルトで private です。公開するには、GitHub の該当パッケージページ → Package settings → Change package visibility で public に変えます。public になれば、誰でもログインなしで pull できます。
docker pull ghcr.io/curtis/hello-docker:1.05. リポジトリと紐付ける #
Dockerfile にラベルを一行入れると、イメージがコードリポジトリと紐付きます。
LABEL org.opencontainers.image.source=https://github.com/curtis/hello-docker紐付けるとリポジトリページのサイドバーにパッケージが表示され、リポジトリの README がパッケージページに載ります。リポジトリの権限をパッケージに継承させる起点にもなるので、実務では入れるのを基本にしておけばよいです。
GitHub Actions では — PAT なしで #
GHCR を選ぶ最大の理由がこの部分です。GitHub Actions の中ではワークフローごとに自動発行される GITHUB_TOKEN があるので、PAT を作ってシークレットに登録する手順が丸ごと不要になります。
permissions:
contents: read
packages: write
steps:
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/${{ github.repository_owner }}/myapp:${{ github.sha }}permissions に packages: write を明示することだけ忘れなければ大丈夫です。タグをコミット SHA で打つ理由と :latest だけに頼ってはいけない理由は、Docker 実戦 #5 タグ戦略 で詳しく扱いました。
運用のコツ二つ #
古いバージョンの整理。 CI がコミットごとにイメージを push すると、untagged のバージョンが溜まり続けます。今は無料なので放置してもコストはかかりませんが、パッケージページが散らかり、課金開始時の負担にもなります。actions/delete-package-versions アクションで古いバージョンを定期的に消すワークフローを一つ入れておくときれいに保てます。
ダイジェストでの固定。 タグは同じ名前で再 push される可能性があります。再現性が重要なデプロイなら、ghcr.io/curtis/myapp@sha256:... 形式のダイジェスト参照を使ってください。これは GHCR に限った話ではなく、すべてのレジストリに共通です。
まとめ — どのレジストリを選ぶか #
- コードが GitHub にあり、GitHub Actions でビルドする — GHCR がデフォルトの選択です。認証、権限、料金のすべてで摩擦が最も少なくなります。
- 公式ベースイメージ — Docker Hub から取得します。選択の問題ではなく、そこにしかありません。
- AWS にデプロイする (ECS、EKS) — 同じネットワークの中にある ECR も併せて検討する価値があります。転送の遅延とコストで有利な場合があります。
GHCR は「GitHub を使っているなら迷う理由があまりない」レジストリです。無料で、pull 制限がなく、権限管理が GitHub に統合されています。レジストリの概念自体に馴染みがなければ Docker 基礎 #5 から、CI パイプライン全体が気になるなら Docker 実戦シリーズ へ進んでください。