自分なりのDockerfile ベストプラクティス
Dockerfileとは
Dockerfileとは、Docker imageを構成するための設計書のこと。
DockerはDockerfileに記載されている命令を読み込み、自動的にDocker imageを構築します。
Dockerfileのベストプラクティス
1コンテナ1プロセス
コンテナは1つの役割のみ持つことが推奨されています。
アプリケーションを複数のコンテナに切り離すことで、水平スケールやコンテナの再利用がより容易になります。
(どうしても追加プロセスが発生する場合はその限りではありません)
Rootlessなコンテナを作成する
コンテナをrootで実行することは推奨しません。
(通常、コンテナはデフォルトでroot実行されてしまいます)
推奨しない理由については、下記が分かりやすいかと思いますので、引用させていただきます。
コンテナを root 実行することはなぜ危険なのでしょうか。それは、コンテナ内の root の実態がホスト(仮想)マシン上の root と全く同じだからです。攻撃者が root として実行されているコンテナを侵害することに成功した場合、ホストを乗っ取るための一歩を踏み出すことになります。その「一歩」として、コンテナエスケープの脆弱性が利用される可能性があります。頻繁に起こるものではありませんが、可能性はゼロではありません。新しいコンテナ脱出の脆弱性が発見された場合、悪用されるためには権限が必要になることが多いため、まず行う対策としてはコンテナが root 実行されていないことを確認することです。
引用
コンテナを、非rootユーザで実行することによって、Dockerに脆弱性があったとしても、攻撃者にホストのroot権限を奪取されることを防ぐことができるということです。
USER app
built contextを意識する
docker build実行時にDockerfileだけではなく、Dockerfileのあるディレクトリ内の他のファイルも使ってDocker imageを作成します。この、ディレクトリ内の状況をbuilt contextといいます。
重要なのが、docker daemonに受け渡しているデータ量が、built contextに依存するということです。
つまり、built contextに不要なディレクトリやファイルがあると、build時に時間がかかってしまったり、メモリを消費する原因となってしまうのです。
built context内にファイルを配置しなくてはいけない状況になった場合は、.dockerignoreを使用して、該当ファイルをbuilt contextから除外しましょう。
ポイント
- built contextに不要なファイルやディレクトリを含まない
- .dockerignoreを使用する
Layerを最小にする
Docker imageを作成する際は、Dockerfileに記述された手順に沿って1つのimageを作成することになります。
このとき作成されたimageはLayer構造をしており、1つのLayerはDockerfile内の1つ手順に該当します。
Dockerfileでimage Layer数を最小に意識する必要があります。
RUNやCOPY、ADDといった命令はdocker imageのLayerを増やすことになり、Layerが増えることによって最終的にできるimageの容量が大きくなってしまいます。
Layerの最小化については、命令を&&で繋ぐことによって実現可能となります。
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y nginx
FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl nginx
マルチステージビルドを利用する
マルチステージビルドとは、Dockerfileを最適化するための手法のことです。
マルチステージビルドを利用すると、複数のFROM命令をDockerfileに記述することができます。
例えば、開発環境用にアプリケーション構築に必要な手順をすべて含むDockerfileと、本番環境用にスリム化したDockerfileを用意したとしましょう。
この場合、1つのプロジェクトで2つのDockerfileを運用・保守する必要が出てきます。
運用コストが高くなってしまいますね。
マルチステージビルドは、環境にかかわらず、1つのDockerfileで共通部分をベースにして、それぞれの環境のimageを作成することが可能になります。
また、最終段階(ステージ)でimageをbuildすることができるため、imageやlayerを最小化することができます。
ADDではなく、COPYを使用する
ADDはローカルファイルのCOPYに加えて、URLからファイルシステムに追加する機能も持っています。
そのため、悪意のある外部URLからファイルを取得しないためにも、ADDではなくCOPYの利用が推奨されています。
また、URLからファイルを自動で取りに行くのでダウンロード中、中間者攻撃の対象となり得るため可能性もあります。
ベースimageのバージョンを指定する
ベースimageのバージョンをlatestにしてしまうと、時間が経過するにつれてコンテナのimageのバージョンが変更されてしまいます。
バージョンによってもたらす影響は計り知れないため、latestを指定するのではなく、利用バージョンを指定するようにしましょう。
また、ベースimageには、信頼性のあるimageを利用しましょう。
FROM ruby:latest
FROM ruby:3.1.2
他にも意識しなくてはいけないポイントがあるかと思いますが、自分なりの重要要素をまとめてみました。
またアップデートがあれば、更新していきます。
以上。