docker compose restartではenvironmentの変更が反映されない

  • Docker
  • OpenTelemetry

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

何が起きたか

compose.ymlのenvironmentを書き換えてdocker compose restart <service>したのに、コンテナの中身が変わってなかった。

結論

docker compose restartは既存コンテナのプロセスを止めて起動し直すだけで、compose.ymlの変更は一切読み込まない。反映されないのはenvironmentだけじゃなくて、env_file ports volumes command healthcheck labels restartあたりも全部同じ。

反映したいなら、コンテナ自体を作り直す必要がある。

ターミナル
docker compose up -d --force-recreate --no-deps <service>

Dockerfileを変えたときはビルドも挟む。

ターミナル
docker compose up -d --build --no-deps <service>

新しいイメージタグをpushしただけなら、pullしてからup。

ターミナル
docker compose pull <service>
docker compose up -d --no-deps <service>

--no-depsをつけておくと、依存してる他のサービス(DBとかキャッシュとか)を巻き込まずに対象のサービスだけ作り直せる。

反映の判断フロー

flowchart TD
    A[設定を変えた] --> B{何を変えた?}
    B -->|environment/ports/volumes等| C["up -d --force-recreate --no-deps"]
    B -->|Dockerfile| D["up -d --build --no-deps"]
    B -->|イメージタグの更新| E["pull → up -d --no-deps"]
    A2[プロセスだけ再起動したい] --> F["restart(設定は反映されない)"]

中に入って確認しようとしたらshがなかった

OTelのコレクター(distroless系のイメージ)に対してdocker compose exec <service> envしたら、こう言われた。

OCI runtime exec failed: exec failed: unable to start container process: exec: "env": executable file not found in $PATH: unknown

envはおろか/bin/shも入ってない最小イメージだった。この場合はコンテナに入らずに、ホスト側からdocker inspectで見るしかない。

ターミナル
CID=$(docker compose ps -q <service>)
docker inspect "$CID" --format '{{range .Config.Env}}{{println .}}{{end}}'

特定のプレフィックスだけ見たいならgrepで絞る。

ターミナル
docker inspect "$CID" --format '{{range .Config.Env}}{{println .}}{{end}}' | grep '^OTEL_'

起動中コンテナへの環境変数の後付けはできない

「起動したまま中の環境変数だけ変える」というのは基本できない。docker compose exec -e FOO=bar <service> <cmd>は、execで新しく起動するプロセスにだけ効くもので、メインプロセス自体の環境は変わらない。

docker updateでも環境変数は更新できない。結局のところ、環境変数を変えたいなら--force-recreateでコンテナを作り直すのが唯一の方法だった。

親シェルのexportは引き継がれるのか

これは条件付きだった。export FOO=barしてからdocker compose up -d --force-recreate --no-deps <service>すれば新しいコンテナに値が渡る、というのは合ってるけど、それはcompose.ymlのenvironment:の書き方次第。

  • FOO=${FOO}のように明示的に参照している場合 → 親シェルの値が展開されて入る
  • FOOとだけキーだけ書いている場合(これもComposeの仕様上OK) → 実行時のシェル環境変数がそのまま渡る
  • environment:自体に何も書いてなければ、いくらexportしても渡らない

「exportすれば引き継がれる」と単純に覚えると、compose.yml側の書き方によっては反映されないケースにハマる。実機で確認する場合はdocker inspectの.Config.Envを見るのが確実。