Docker

Docker Desktop を久しぶりに更新したあと、以前から使っているプロジェクトで docker-compose up -d を実行すると、使えるイメージがあるのに Building が始まることがあります。原因は Compose v2 系でコンテナ名・イメージ名の区切り文字が _ から - に変わり、既存イメージが「無い」と判定されるためです。compose ファイルと同じ場所の .envCOMPOSE_COMPATIBILITY=true を 1 行入れると旧名称のまま動き、ビルドは走りません。

まず止めていい。データは消えない

始まってしまったビルドは Ctrl+C で止めて構いません。完成しても新しい名前のイメージが 1 つ増えるだけで、既存のコンテナやボリュームには何も起きていません。DB のデータが入る名前付きボリュームの命名は v1 も v2 も プロジェクト名_ボリューム名 で変わっていないので、この時点で失われるものはありません。

原因は命名規則の変更

Compose v1 はコンテナを project_service_1build: で作るイメージを project_service と名付けました。v2 系では区切りがハイフンになり project-service-1 / project-service です。image: を書かずに build: だけで定義したサービスは、新しい Compose が project-service というイメージを探し、見つからないのでビルドに入ります。

旧 Docker Desktop 付属の docker-compose(v2.2.1)で作られたコンテナはアンダースコア命名でしたが、新しい Desktop では docker-compose も素の v2 として動くため、同じコマンドを実行しているのに命名が変わります。

対処は .env に 1 行

# Compose v2以降でも旧(v1)のアンダースコア命名を使い、既存コンテナ・イメージを再利用する
COMPOSE_COMPATIBILITY=true

compose ファイルと同じディレクトリの .env に追記します。無ければ作ります。毎回 docker-compose --compatibility up -d と付けても同じですが、忘れた瞬間にビルドが走るので固定する方が安全です。.env を新設したプロジェクトが Git 管理下なら、.git/info/exclude.env を書いておくとリポジトリを汚しません。

入れるプロジェクトと入れないプロジェクトの見分け方

全部に入れてはいけません。既にハイフン命名で作られているプロジェクトに入れると、今度はアンダースコアのイメージが無いと判定されて逆方向にビルドが走ります。判断材料は既存コンテナの名前です。

docker ps -a --format '{{.Names}}'

project_db_1 なら入れる、project-db-1 なら入れない、これだけです。私の環境では約 30 プロジェクトのうち 12 がアンダースコア、13 がハイフンで、ビルドが始まったのはアンダースコア側だけでした。container_name: を明示したサービスは命名規則の影響を受けません。1 つのプロジェクト内で両方が混在している場合は、どちらに寄せても片方のコンテナが作り直しになるので、次に触る時まで保留にしました。

実行前に –dry-run で読む

docker-compose --dry-run up -d

出力に Image project-service Building が無ければイメージは再利用されています。Container feae3382f32e_project_db_1 Starting のようにハッシュが前に付いた名前が出たら、既存コンテナを一時的にリネームして作り直す印です。Compose のバージョンが変わると設定ハッシュも変わるため、この再作成はほぼ必ず起きます。名前付きボリュームのデータは引き継がれるので、再作成自体は許容して構いません。