Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Docker Best Practices: Reduce Image Size + Common Interview Questions

2025年09月10日に「Dev.to」が公開したITニュース「Docker Best Practices: Reduce Image Size + Common Interview Questions」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Dockerイメージのサイズ削減は、ビルドやデプロイの高速化、ストレージコスト削減に繋がる。記事では、ベースイメージの選択、キャッシュの活用、.dockerignoreによる不要ファイルの除外など、具体的な最適化手法を解説。これによりイメージサイズを大幅に減らせる。Dockerに関する面接対策のQ&Aも紹介している。

ITニュース解説

Dockerは、ソフトウェアを「コンテナ」と呼ばれる独立した環境で動かすための技術である。コンテナは、アプリケーションとその実行に必要なすべてのもの(コード、ランタイム、システムツール、ライブラリなど)を一つのパッケージにまとめたもので、これによって開発環境、テスト環境、本番環境のどこでも、同じようにアプリケーションが動作することが保証される。このコンテナを作成するための設計図がDockerfileであり、Dockerfileから作られるパッケージがDockerイメージと呼ばれる。このDockerイメージのサイズは、実は非常に重要であり、様々な側面でパフォーマンスやコストに大きな影響を与える。

Dockerイメージのサイズが大きいと、まずアプリケーションをビルドするのに時間がかかる。ビルドとは、Dockerfileの指示に従ってイメージを作成するプロセスのことだ。大規模なプロジェクトでは、このビルドが頻繁に行われるため、ビルド時間が長くなると開発のサイクル全体が遅くなってしまう。また、ビルドされたイメージは、GCP Artifact RegistryやDocker Hubのような「コンテナレジストリ」と呼ばれる場所に保存されるが、イメージサイズが大きいとその保存容量も増え、クラウドサービスのストレージコストも上がることになる。さらに、アプリケーションをデプロイする際や、必要に応じてコンテナの数を増やす「スケーリング」を行う際にも、大きなイメージはネットワークを通じて転送されるのに時間がかかり、デプロイが遅くなったり、アプリケーションの起動に時間がかかったりする。結果として、ユーザー体験の低下や、クラウドコンピューティングの利用料金が増加するといった問題につながる。セキュリティの観点からも、イメージサイズが小さい方が、含まれるソフトウェアコンポーネントが少なくなり、潜在的な脆弱性(セキュリティ上の弱点)が減るため、攻撃を受ける可能性が低くなるという利点がある。

あるプロジェクトでは、最初のDockerイメージのサイズが1.9GBにも達していた。これは非常に大きなサイズだ。その原因は、いくつかの一般的な落とし穴にあった。最初のDockerfileは、FROM google/cloud-sdk:latestという行から始まっていた。これは、Google Cloud SDKが全て含まれたベースイメージを使用するという意味だが、このイメージ自体が約3GBと非常に巨大だった。アプリケーションの実行に必要なのは、Google Cloud SDKの一部機能だけなのに、全てを抱え込んでしまうことで、必然的にイメージサイズが肥大化したのだ。

次に問題だったのは、COPY . .というコマンドだ。これは、Dockerfileがあるディレクトリ内の全てのファイルを、コンテナ内の/appディレクトリにコピーするという指示である。一見便利に思えるが、この命令は頻繁にファイルの変更が発生するアプリケーションコードと、あまり変更されない依存関係のインストールを混同させてしまう。Dockerは、Dockerfileの各コマンドを実行した結果を「レイヤー」としてキャッシュする。しかし、COPY . .のように全てのファイルを一度にコピーすると、たとえコードの一部しか変更されていなくても、Dockerは「全てのファイルが変わった」と判断し、それ以降のレイヤー(特にRUN pip install -r requirements.txtのような依存関係のインストール)のキャッシュを無効にしてしまう。その結果、毎回依存関係の再インストールが発生し、ビルド時間が大幅に伸びる原因となっていた。

さらに、.dockerignoreファイルが使われていなかったことも問題だった。.dockerignoreファイルは、Gitリポジトリにおける.gitignoreファイルのような役割を果たす。このファイルに指定されたディレクトリやファイルは、COPYコマンドでイメージにコピーされる際に無視される。例えば、.gitディレクトリ(Gitの履歴情報)、__pycache__(Pythonのコンパイル済みバイトコード)、.vscode/(VS Codeの設定ファイル)など、アプリケーションの実行には不要なファイルが大量に存在することが多い。これらがイメージにコピーされると、その分イメージサイズが不必要に大きくなる。

最後に、pip installコマンドがデフォルトでパッケージのキャッシュを残してしまうことも、イメージ肥大化の一因だった。pipは、一度ダウンロードしたパッケージを再利用できるようにキャッシュする仕組みを持っているが、このキャッシュは通常、イメージ内で不要な数百MBのスペースを占有してしまう。

これらの課題を解決するために、Dockerfileを大幅に最適化した。まず、ベースイメージをFROM python:3.12-slimに変更した。このslimバージョンのPythonイメージは、必要なPythonランタイムだけが含まれており、サイズが約124MBと非常に小さい。元の3GBのgoogle/cloud-sdk:latestに比べて劇的な削減だ。Google Cloud SDKが必要な場合は、apt-getコマンドを使って必要なコンポーネントだけをイメージ内でインストールするように変更した。これにより、必要な機能だけを取り込みつつ、ベースイメージの小ささを最大限に活用できる。

次に、Dockerのレイヤーキャッシュを効率的に利用するために、COPYコマンドの順番を工夫した。具体的には、まずCOPY requirements.txt .で依存関係リストのファイルだけをコピーし、その後にRUN pip install --no-cache-dir -r requirements.txtで依存関係をインストールする。アプリケーションの依存関係は頻繁には変更されないため、requirements.txtに変更がなければ、この依存関係インストールレイヤーはキャッシュが再利用され、非常に高速にビルドが完了する。その後にCOPY . .でアプリケーションコード全体をコピーすることで、コードの変更があった場合でも、依存関係の再インストールをスキップできるようになる。

.dockerignoreファイルも導入した。このファイルに__pycache__/.git/.vscode/といった不要なファイルを記述することで、イメージにコピーされるファイルが本当に必要なものだけに限定され、イメージサイズが削減される。これは、イメージの「掃除」のようなものだ。

さらに、pip installコマンドには--no-cache-dirオプションを追加した。これにより、パッケージのインストール後にpipが生成するキャッシュファイルがイメージ内に残らないようにした。また、apt-get installでGoogle Cloud SDKをインストールした後に、rm -rf /var/lib/apt/lists/*というコマンドを実行した。これは、apt-getがパッケージ情報をダウンロードする際に作成する一時的なキャッシュファイルを削除するためのもので、これもイメージのサイズを減らすのに役立つ。

これらの最適化の結果、プロジェクトのDockerイメージは当初の1.96GBから、最終的にわずか495MBまで削減された。これは約75%もの大幅なサイズダウンだ。この改善により、ビルド速度は3倍も速くなり、コンテナレジストリへのプッシュやそこからのプル(ダウンロード)も劇的に高速化された。さらに、クラウドストレージのコストも削減されるという具体的なメリットが得られた。

このようなDockerイメージの最適化は、システムエンジニアを目指す上でも非常に重要な知識となる。例えば、面接では「Dockerイメージサイズを減らすにはどうすれば良いか?」といった質問がよく出される。その際には、「スリムなベースイメージを使う」「マルチステージビルドを活用する」「.dockerignoreファイルを適切に設定する」「ビルド時のみに必要な依存関係を最終イメージから削除する」「pipaptなどのキャッシュをクリーンアップする」といった具体的な方法を説明できる必要がある。

また、「なぜrequirements.txtをアプリケーションコードより先にコピーしてインストールするのか?」という問いには、「Dockerのレイヤーキャッシュを最大限に活用するためで、これによりrequirements.txtに変更がない限り依存関係の再インストールを避けてビルド時間を短縮できる」と答えられるだろう。.dockerignoreの役割や、マルチステージビルドが特に有効なケース(GoやJavaのようにコンパイルが必要な言語で、ビルドツール自体を最終イメージに含めたくない場合など)についても理解しておくべきだ。google/cloud-sdk:latestのような巨大なベースイメージを直接使わない理由も、そのサイズと、必要なツールだけを個別にインストールする方がはるかに効率的である点から説明できる。

Dockerイメージの最適化は単なる容量削減にとどまらない。それは、開発の効率化、CI/CD(継続的インテグレーション・継続的デリバリー)パイプラインの高速化、そして最終的なクラウドコストの削減に直結する。スリムなベースイメージの選択、レイヤーキャッシュの賢い利用、.dockerignoreによる不要ファイルの排除、そしてインストール後の適切なクリーンアップを組み合わせることで、開発プロセス全体を大きく改善できるのだ。