Docker ビルドがプライベート依存に届かないときの確認手順
ホスト側で取得できるプライベートパッケージでも、ビルド内では失敗することがあります。ビルダーを特定し、経路を証明し、トークンはビルドシークレットとしてマウントします。
自分のマシンでは問題なく解決できるプライベートパッケージが、ビルドの内部では 404 やタイムアウトで失敗することがあります。原因は Dockerfile ではないことがほとんどです。ビルドのステップは別のネットワーク名前空間で動いており、テストしたシェルとは DNS の見え方も資格情報の保管場所も異なります。以下の確認を順番に行い、最初に失敗したところで止めてください。後続の確認は、その前の確認が通ったことを前提にしているからです。各手順には、決着をつけるコマンドを示します。
まず Dockerfile ではなくビルダーを特定する
BuildKit はローカル、コンテナ内、別マシンのいずれでも動作し、それぞれに既定のネットワークがあります。まず docker buildx ls を実行し、何かを変更する前にアスタリスクの付いたノードを読んでください。ある docker-container ドライバーやクラウドビルダーが、そこでコマンドを入力したというだけでお使いのノート PC のプライベート経路を共有するわけではありません。有効なビルダーがリモートなら、残りの確認はすべてワークステーションではなくそのホストに対して実行する必要があります。
ビルダーは独自の リゾルバー設定とプロキシ変数も持ちます。どちらもビルド時に読み込まれ、ビルドを開始した端末から継承されるものではありません。
ビルドステップの内側からネットワーク経路を証明する
依存先のホストを名前解決し、そこへの接続を開く使い捨てのステージを書きます。ビルダーの側で問いに答えるのは、このテストだけです。
FROM alpine:3.20
RUN apk add --no-cache curl bind-tools && getent hosts registry.example.internal && curl -sS -o /dev/null -w "%{http_code}
" https://registry.example.internal/simple/
実際のビルドと同じビルダー、ネットワークモード、シークレットマウントでそのファイルをビルドします。 docker buildx build --builder remote0 -f Dockerfile.probe --progress=plain .。もし getent が何も出力しなければ、失敗は名前解決にあり、資格情報では直りません。名前は解決できても curl がタイムアウトを報告するなら、障害は経路かレジストリ手前の外向きポリシーです。
答えが出たらプローブは削除してください。診断用のステージであり、タグ付けやプッシュをしてよいものではありません。
資格情報はコピーせずマウントする
経路が通ったら、次に失敗するのは認証です。BuildKit のシークレットマウントは、一つの RUN ステップにだけファイルを渡し、レイヤーには書き込みません。依存ツールが必要とし、イメージが残してはならないものです。
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci --omit=dev
シークレットは Dockerfile の外から渡す必要があります。 docker buildx build --secret id=npmrc,src=/home/me/.npmrc .。ファイルはクライアント側に残り、イメージの履歴には入りません。 ARG または ENV に同じトークンを持たせてもこの役割は果たせません。どちらもイメージの設定に記録されるからです。
root 以外のイメージには独自のターゲットパスが必要です。たとえば /home/app/.npmrc や、pip、Maven、Cargo の同等ファイルです。マウント先はコマンドを実行するユーザーと一致していなければなりません。そうでないと、実際には存在する設定ファイルが無いとツールが報告します。
依存ツールがイメージに残すものを監査する
一時的なマウントは資格情報をレイヤーの外に保ちますが、ツールが別のものを書き込むのを止めはしません。パッケージマネージャーはロックファイル、キャッシュディレクトリ、ときには解決済みのレジストリ URL を残します。
Dockerfile を信じるのではなく、出来上がったファイルシステムを読みます。 docker history --no-trunc image:tag はレイヤーのコマンドをすべて一覧し、 docker run --rm image:tag sh -c "ls -a /root" は実行中のコンテナに何が残ったかを示します。ファイルをマウントしただけでも、ログ行に書き出されたトークンは npm ci の間も漏洩のままです。
ビルドログも読んでください。 --progress=plain はコマンドの出力をそのまま表示します。トークンがそこに現れたら、何よりも先にローテーションし、ツールが静かに読むファイル経由で渡してください。
実行時のイメージにプライベート経路が不要になったことを確認する
ビルドと実行中のアプリは同じ依存の別々の利用者であり、プライベート経路が必要なのは前者だけです。完成したイメージは、ビルド時の資格情報なしで起動し、実行時の依存を解決し、トラフィックを処理できるべきです。
プライベートレジストリに到達できない場所で試すか、単にコンテナを --network none で起動して、マウントしたシークレットなしで起動することを確認します。ビルドシークレットがあるときだけ起動するコンテナは、まだビルド環境に結合しています。
コンテナが実行時に本当にレジストリを必要とするなら、それは別個のアクセス判断であり、ビルドではなくオーケストレーターのシークレットストアに置くべきです。二つの経路を別々に文書化し、実行時の取得をビルドフラグで直そうとする人が出ないようにしてください。五つの確認がすべて通れば、元の症状は各層で名前の付いた原因を持ち、Docker のネットワークに関する推測ではなくなります。