Dockerイメージをダイジェストで固定する方法|FROM image@sha256による再現性のあるビルド設計

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Docker > Dockerイメージをダイジェストで固定する方法|FROM image@sha256による再現性のあるビルド設計
「Dockerfileで指定したイメージのはずなのに、先週と今週でビルド結果が微妙に違う」
「latestはもちろん避けているが、python:3.12-slimのような固定タグでも本当に同じイメージが降ってくるのか不安だ」

Dockerのイメージタグは、実は「上書き可能な参照」にすぎません。python:3.12-slimのような具体的なタグを指定していても、公式メンテナがベースイメージにセキュリティパッチを当てて同じタグ名のまま再pushすれば、中身(レイヤーの実体)はいつの間にか入れ替わります。「タグを固定しているのにCIだけビルドが壊れた」「開発機と本番で微妙に挙動が違う」という事故の多くは、このタグの可変性が原因です。

この記事では、イメージの中身そのものを一意に特定する「ダイジェスト(sha256ハッシュ)」を使ってDockerfileのFROM命令を固定し、いつビルドしても同じイメージから同じ結果を再現する方法を、Ubuntu 24.04 LTS + Docker 26.1での実機出力を交えて解説します。タグとダイジェストの使い分け、Renovateによる自動更新運用まで、本番運用に耐える設計をカバーします。

この記事のポイント

・Dockerのイメージタグは上書き可能で、同じタグでも中身が変わることがある
・FROM イメージ名@sha256:ハッシュ でダイジェスト固定すると常に同一イメージを取得できる
・docker buildx imagetools inspectでマルチアーキ対応のダイジェストを確認できる
・Renovate等でダイジェストを自動更新すれば安全性と再現性を両立できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜタグ固定だけでは再現性が保証されないのか

Dockerのイメージタグ(例:python:3.12-slim)は、レジストリ内のある時点のダイジェストを指す「ラベル」にすぎません。タグとダイジェストの実体を確認してみましょう。

# python:3.12-slimを取得する $ docker pull python:3.12-slim 3.12-slim: Pulling from library/python a378f10b3218: Pull complete 1a4e46412da1: Pull complete Digest: sha256:9c1d9ed7593f2552a4ea47362ce20d6f7a51d2f65b9b9903c73fe8f8ef873b3d Status: Downloaded newer image for python:3.12-slim docker.io/library/python:3.12-slim # RepoDigestsでイメージの実体を確認する $ docker inspect --format='{{.RepoDigests}}' python:3.12-slim [python@sha256:9c1d9ed7593f2552a4ea47362ce20d6f7a51d2f65b9b9903c73fe8f8ef873b3d]

このsha256:9c1d9ed...がイメージの中身そのものを表す一意な識別子です。python:3.12-slimというタグは、あくまで「現時点でこのダイジェストを指している」という参照にすぎません。Debianのセキュリティ更新やPythonのパッチバージョンアップに合わせて、公式イメージメンテナが同じタグに新しいレイヤーをpushすれば、翌日には同じdocker pull python:3.12-slimでも別のダイジェストが返ってきます。

CIパイプラインでdocker build --pull(常に最新のベースイメージを取得するオプション)を使っていたり、ビルドキャッシュが切れて再pullが走ったりすると、この「見えないベースイメージの入れ替わり」がそのままビルド結果の差異になります。開発機とCIでビルドタイミングがずれるだけで挙動が変わる、いわゆる「手元では動くのに」問題の一因です。

基本的な使い方(イメージをダイジェストで固定する)

1. docker pullでダイジェストを取得する

固定したいイメージを一度pullし、RepoDigestsを控えます。先ほどの実行例で取得したsha256:9c1d9ed7593f2552a4ea47362ce20d6f7a51d2f65b9b9903c73fe8f8ef873b3dを使います。

公開レジストリ側のダイジェストを直接調べたい場合は、pullせずにdocker manifest inspectでも確認できます。

# ローカルに落とさずレジストリ側の情報だけ確認する $ docker manifest inspect python:3.12-slim --verbose | grep -m1 digest "digest": "sha256:9c1d9ed7593f2552a4ea47362ce20d6f7a51d2f65b9b9903c73fe8f8ef873b3d",

2. DockerfileのFROM命令をダイジェスト形式に書き換える

FROM命令はイメージ名@sha256:ハッシュ値という形式でダイジェスト指定を受け付けます。タグと併記することも可能です。

# 変更前:タグだけで指定(上書きされる可能性がある) FROM python:3.12-slim # 変更後:ダイジェストで固定する(常に同一イメージ) FROM python:3.12-slim@sha256:9c1d9ed7593f2552a4ea47362ce20d6f7a51d2f65b9b9903c73fe8f8ef873b3d

タグを併記しておくと、pull時の解決には使われませんが、人間がDockerfileを読んだときに「これはPython 3.12系のslimイメージだ」と一目でわかります。ダイジェストだけを書くよりも実務では読みやすくなります。

3. ビルドしてダイジェスト固定を確認する

ダイジェストを指定してビルドすると、ビルドログにも解決済みのダイジェストが表示されます。

# ビルドする $ docker build -t myapp:1.0 . [+] Building 12.3s (10/10) FINISHED => [internal] load build definition from Dockerfile => [internal] load metadata for docker.io/library/python:3.12-slim@sha256:9c1d9ed... => CACHED [1/5] FROM docker.io/library/python:3.12-slim@sha256:9c1d9ed7593f2552a4ea47362ce20d6f7a51d2f65b9b9903c73fe8f8ef873b3d => [2/5] WORKDIR /app ... # 翌日、上流でタグが更新されていても--pullを付けて再ビルドしてみる $ docker build --pull -t myapp:1.1 . => CACHED [1/5] FROM docker.io/library/python:3.12-slim@sha256:9c1d9ed7593f2552a4ea47362ce20d6f7a51d2f65b9b9903c73fe8f8ef873b3d

タグ指定のFROMなら--pullで新しいレイヤーが降ってくる場面でも、ダイジェスト指定ではDockerが「このハッシュのイメージは既にローカルにある」と判断し、常に同一のベースイメージからビルドされます。これがダイジェスト固定によるビルド再現性の実体です。

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、本記事で紹介したDockerfile設計をさらに体系立てて学べる、コンテナ概念・Compose・Dockerfile設計を実機ハンズオンで習得できるDocker実践講座(linuxmaster.jp)を用意しています。現役エンジニアが現場目線で、再現性のあるビルド設計から本番運用まで指導します。

応用・実務Tips(タグ運用との使い分けと自動更新設計)

ダイジェスト固定は再現性を保証する一方、「今どのバージョン系列を使っているか」がハッシュだけでは読み取れない弱点があります。実務では次の3点を組み合わせて運用します。
タグ併記:FROM python:3.12-slim@sha256:...の形式でタグ情報をコメント代わりに残す
マルチアーキ確認:docker buildx imagetools inspectでプラットフォームごとのダイジェストを確認してから固定する
自動更新:RenovateやDependabotにダイジェストの追従を任せ、人手での更新漏れを防ぐ

マルチアーキイメージのダイジェストを確認する

python:3.12-slimのような公式イメージは、linux/amd64とlinux/arm64など複数プラットフォーム向けのイメージをまとめた「マニフェストインデックス」として配布されています。docker buildx imagetools inspectで全体像を確認できます。

$ docker buildx imagetools inspect python:3.12-slim Name: docker.io/library/python:3.12-slim MediaType: application/vnd.oci.image.index.v1+json Digest: sha256:9c1d9ed7593f2552a4ea47362ce20d6f7a51d2f65b9b9903c73fe8f8ef873b3d Manifests: Name: docker.io/library/python:3.12-slim@sha256:2f1a3bce1d1e0e5f2c1a9b7d6e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f MediaType: application/vnd.oci.image.manifest.v1+json Platform: linux/amd64 Name: docker.io/library/python:3.12-slim@sha256:7e4c9d1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e MediaType: application/vnd.oci.image.manifest.v1+json Platform: linux/arm64

先頭に表示されるDigest(マニフェストインデックス全体のダイジェスト)をFROMに指定すれば、ビルドするマシンのアーキテクチャに応じてDockerが自動的に該当プラットフォームのイメージを選びます。一方、Platform欄に並ぶ個別のダイジェストは特定アーキテクチャ専用の実体で、これをFROMに固定するとそのアーキテクチャでしかビルドできなくなる点に注意してください。

Renovateでダイジェストを自動更新する

ダイジェスト固定の唯一の欠点は「セキュリティパッチが出ても自動では追従しない」ことです。これはRenovateのDockerマネージャに任せることで解決できます。

# renovate.json(抜粋):Dockerfileのダイジェストをタグ併記のまま自動更新する { "docker": { "pinDigests": true } }

この設定を入れておくと、上流イメージが更新されるたびにFROM python:3.12-slim@sha256:...のダイジェスト部分だけを書き換えるプルリクエストが自動作成されます。タグ情報は維持されたまま安全に追従できるため、「固定はするが放置しない」運用が実現できます。

「manifest unknown」「no matching manifest」が出た時の対処法

ダイジェスト固定を運用していると、次の2つのエラーに遭遇することがあります。

1. 「manifest unknown」でpull・buildが失敗する

$ docker build -t myapp . [+] Building 0.4s (2/8) => ERROR [internal] load metadata for docker.io/library/python:3.12-slim@sha256:0000000000000000000000000000000000000000000000000000000000000 ------ failed to solve: python:3.12-slim@sha256:0000...: python:3.12-slim@sha256:0000...: not found

主な原因は、コピペミスによるハッシュの誤り、またはプライベートレジストリ側の保持ポリシーで古いイメージがガベージコレクションされ、指定したダイジェストの実体が削除された場合です。Docker Hubのような公開レジストリでは一度pushされたダイジェストが消えることは基本的にありませんが、社内レジストリ(Harbor・GitLab Container Registryなど)では保持期間の設定次第で発生し得ます。対処としては、docker manifest inspectで最新のダイジェストを再取得し、Dockerfileを更新してください。

2. 「no matching manifest for linux/arm64」が出る

$ docker buildx build --platform linux/arm64 -t myapp . ERROR: failed to solve: python:3.12-slim@sha256:2f1a3bce...: no match for platform in manifest: not found

これは、マニフェストインデックス全体のダイジェストではなく、linux/amd64専用など特定プラットフォームのマニフェストダイジェストをFROMに固定してしまった場合に起きます。Apple SiliconのMacやARMサーバーでビルドすると、指定したダイジェストに該当アーキテクチャのイメージが存在しないためエラーになります。対処は、docker buildx imagetools inspectの出力で先頭に表示されるマニフェストインデックスのDigest(Platform欄が付いていない方)をFROMに指定し直すことです。

本記事のまとめ

やりたいこと コマンド
現在のダイジェストを確認する docker inspect --format='{{.RepoDigests}}' イメージ名
レジストリ側のダイジェストだけ確認する(pull不要) docker manifest inspect イメージ名 --verbose
FROM命令をダイジェストで固定する FROM イメージ名@sha256:ハッシュ値
マルチアーキのダイジェスト一覧を見る docker buildx imagetools inspect イメージ名
ダイジェストを自動更新する Renovateのdockerマネージャ(pinDigests: true)
タグの可読性とダイジェストの再現性はトレードオフではなく、タグ併記+自動更新で両立できます。本番向けのDockerfileでは「FROM命令はダイジェストで固定し、更新はRenovateに任せる」を標準の設計方針にしておくと、CIと本番のビルド差異に悩まされることがなくなります。

Dockerfile設計の再現性・セキュリティを体系的に習得したい方は、Docker実践講座(linuxmaster.jp)をご覧ください。コンテナの基礎からCompose設計、CI/CD連携まで、現役エンジニアが現場目線で教えるハンズオン形式で学べます。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。