🐳 Dockerイメージダイエットの始まり:docker historyでルーツを徹底分析

軽いアプリケーションをデプロイしただけなのに、イメージサイズを確認すると、いつの間にか1GBを超えていることがあります。「あれ、こんなに何も入れてないはずなのに?」と戸惑ってしまうでしょう。そんな時に必要となるのが、イメージの「家系図」を調べる作業です。

Dockerレイヤーダイエット

「一体何を食べてそんなに大きくなったの?」

Dockerイメージは、何層にも重なった玉ねぎの皮(レイヤー)のようなものです。docker historyは、この皮を一枚ずつ剥がし、肥大化の原因となっている「犯人」を特定するためのX線のようなコマンドです。

基本的な使い方は非常にシンプルです。

# 基本的な使い方
docker history [オプション] <イメージ名:タグ>

# 例:自分のアプリの履歴を確認
docker history my-app:latest

コマンドを実行すると、イメージの最新レイヤーからベースイメージまで、逆順に表示されます。

IMAGE          CREATED          CREATED BY                                      SIZE
a6215f271958   5 minutes ago    /bin/sh -c #(nop)  CMD ["/bin/sh"]               0B
<missing>      7 weeks ago      /bin/sh -c #(nop) ADD file:f28242cf608f6...     7.81MB

ここでSIZE項目に注目してください。0Bであるべき場所に数百MBと表示されている場合、それがダイエットの対象です。経験を積むと、「何かおかしい」と感じる場所が必ず見つかるはずです。

**💡 役立つヒント: --no-trunc**

デフォルトの出力では、コマンドが長いと途中で省略されます。この時--no-truncオプションを付けると、省略されずにコマンド全体を確認できるため、正確な分析には不可欠です。

docker history --no-trunc my-app:latest


実例:「犯人はchownだった」

実際に私が経験した実話をお話ししましょう。150MBのプロジェクトファイルをビルドしたところ、イメージが300MBを超えてしまうという奇妙な現象がありました。犯人は、ごく普通のDockerfileのたった2行だったのです。

[非効率な方法:2つのレイヤーが生成される]

# 1. ファイルを一時的にコピー (デフォルトではroot権限でコピーされる)
COPY . .

# 2. セキュリティのために所有権を変更 (別のコマンドとして実行)
RUN chown -R appuser:appgroup /app

これをビルドした後、docker historyで確認してみると、このような結果が表示されました。

IMAGE          CREATED BY                                        SIZE
<layer_id_2>   /bin/sh -c chown -R appuser:appgroup /app         150MB  <-- (問題の箇所!)
<layer_id_1>   /bin/sh -c #(nop) COPY dir:abc in /app            150MB

ここでDockerレイヤーの恐ろしい点が明らかになります。ステップ1で150MBのファイルをコピーすると、1つのレイヤーが生成されます。しかし、ステップ2でchownを実行すると、Dockerは「おや?ファイル情報(所有権)が変わったな?それなら、変更された状態でさらにレイヤーを一つ作ろう!」と判断し、既存の150MBをそのままコピーして新しいレイヤーを積み重ねてしまうのです。

結果として、内容は同じなのに所有権だけが異なるファイルが二重に保存され、容量が2倍になってしまったのです。


解決策は一行ダイエット!

解決策は簡単です。コピーする際に最初から所有権を指定し、レイヤーを一つにまとめれば良いのです。

[効率的な方法:1つのレイヤーが生成される]

# コピーと同時に所有権も指定!
COPY --chown=appuser:appgroup . .

Dockerfileをこのように修正し、再度docker historyを実行してみると、結果は劇的に変わります。

IMAGE          CREATED BY                                               SIZE
<layer_id_1>   /bin/sh -c #(nop) COPY --chown=appuser... dir:abc       150MB

お分かりでしょうか?たった一つのレイヤーのみが生成され、イメージ容量は再びスリムな150MBに戻りました。コマンドを2行から1行にまとめただけで、容量が半分になったのです。


結論:ビルド後は必ず「履歴」をチェック!

Dockerイメージはコマンド1行につき1レイヤーという事実を忘れないでください。

コードを書き終えてテストを行うように、ビルド後には習慣的にdocker history --no-truncを実行してみてください。「このapt-getはなぜこんなに重いんだ?」「このレイヤーはなぜわざわざ分けたのだろう?」といった疑問が次々と湧いてくるうちに、いつの間にか非常に軽量で効率的なシステムを構築していることでしょう。

不要なレイヤーはシステムの敵ですからね!


お役に立ちましたでしょうか? もしお役に立てたなら、ぜひ「いいね!」をお願いします。

関連記事もぜひご覧ください。

関連記事

Docker共有メモリ(shm_sizeとipc)を完全に理解する

Docker: ネットワーク共有なしでホストポートを介してコンテナ間で通信する

Dockerボリュームのコピー、「なぜ」そうする必要があるのか?