Dockerの基本概念を理解したら、次に必要になるのが自分だけの「Dockerイメージ」を作成する技術です。それを実現するのが「Dockerfile」です。
この記事は、『【Docker】Dockerとは?Dify導入のための基本概念と使い方ガイド』の補足記事として、Dockerfileとは何か、基本的な書き方、主要なコマンド、そして効率的で安全なイメージを作るためのベストプラクティスまでを詳しく解説します。
- 1. Dockerfileとは? なぜ必要なのか?
- 2. Dockerfileでよく使う用語
- 3. Dockerfileの基本的な書き方と例
- 4. よく使うDockerfileの命令 (Instruction)
- FROM <イメージ>[:<タグ>]
- RUN <コマンド>
- COPY <コピー元(ホスト)> <コピー先(コンテナ)>
- ADD <コピー元(ホスト or URL)> <コピー先(コンテナ)>
- WORKDIR <パス>
- CMD ["実行ファイル", "パラメータ1", "パラメータ2"] (推奨: exec形式)
- ENTRYPOINT ["実行ファイル", "パラメータ1", "パラメータ2"] (推奨: exec形式)
- ENV <キー>=<値>
- ARG <キー>[=<デフォルト値>]
- EXPOSE <ポート番号>[/<プロトコル>]
- USER <ユーザー名>[:<グループ名>]
- VOLUME ["<パス>"]
- LABEL <キー>=<値>
- 5. Dockerfileからイメージをビルドする (docker build)
- 6. ベストプラクティスと高度なテクニック
- まとめ
1. Dockerfileとは? なぜ必要なのか?
Dockerfileとは、**Dockerコンテナイメージを自動的に作成するための設計図(レシピ)**が書かれたテキストファイルです。ファイル名はそのまま Dockerfile とします。
このファイルに、ベースとなるOSイメージ、インストールするソフトウェア、コピーするファイル、実行するコマンドなどを順番に記述しておけば、docker build コマンド一つで、**誰でも、何度でも、全く同じ環境(コンテナイメージ)**を再現できます。
なぜDockerfileが重要なのか?
- 環境の再現性: 開発環境と本番環境の違いによる問題を解消します。
- 自動化: イメージ作成プロセスをコード化し、手作業によるミスを防ぎます。
- 共有とバージョン管理: Dockerfile自体をGitなどで管理・共有できるため、環境構築の手順が明確になります。
- Difyでの利用: Difyのコミュニティ版も、内部的にはDockerfileを使って各コンポーネントのイメージをビルドしています。
PCに例えると…
Dockerの概念をPCに例えてみましょう。
- イメージ (Dockerfileで作成): OSやソフトウェアがインストール済みの「システムイメージ」や「ROM (Read Only Memory)」のようなもの。基本的に変更できません。
- コンテナ (イメージから起動): システムイメージから起動した、実際に動作している「PC(メモリ上で動いている状態)」のようなもの。電源を切る(コンテナを停止・削除する)と、作業中の内容は消えてしまいます (揮発性)。
- ボリューム: コンテナに接続する「外付けHDD/SSD」のようなもの。コンテナを削除してもデータが永続的に残り、再利用できます。
2. Dockerfileでよく使う用語
Dockerfileを理解する上で重要な用語を解説します。
イメージレイヤー (Image Layer)
Dockerfileの各命令(FROM, RUN, COPY など)は、基本的にそれぞれがイメージを構成する「層(レイヤー)」を作り出します。イメージはこのレイヤーが積み重なってできています。
- キャッシュ: Dockerはビルド時にこのレイヤー単位でキャッシュを利用します。Dockerfileに変更がなければ、キャッシュされたレイヤーを再利用するため、ビルドが高速になります。
- イメージサイズ: レイヤー数が多いほど、イメージサイズが大きくなる傾向があります。そのため、複数の
RUNコマンドを&&で繋いで1つのレイヤーにまとめるなどの工夫が有効です。
# これは2レイヤー (非効率な場合あり)
RUN apt-get update
RUN apt-get install -y vim
# これは1レイヤー (効率的な場合が多い)
RUN apt-get update && apt-get install -y vim
ただし、キャッシュ効率を考えると、変更頻度の低い apt-get update と、変更頻度の高いパッケージインストールは分ける方が良い場合もあります(後述)。
ビルドコンテキスト (Build Context)
docker build コマンドを実行する際に、Dockerエンジンに送られるファイル群(通常は Dockerfile があるディレクトリ全体)のことです。Dockerfile内の COPY や ADD 命令は、このビルドコンテキスト内のファイルしか参照できません。
.dockerignoreファイル:.gitignoreと同様に、ビルドコンテキストに含めたくないファイルやディレクトリ(例:.git,node_modules,*.log)を指定するファイルです。これを適切に設定することで、ビルドコンテキストのサイズを小さくし、ビルド時間の短縮やセキュリティ向上に繋がります。
3. Dockerfileの基本的な書き方と例
Dockerfileは、基本的に上から下へ順番に命令を実行していきます。
# Dockerfileの例 (シンプルなNginx設定)
# 1. ベースとなるイメージを指定 (どのOSやミドルウェアを土台にするか)
FROM nginx:stable-alpine
# 2. (任意) 作者情報などメタデータを記述
LABEL maintainer="Your Name <your.email@example.com>"
# 3. ホストPCから設定ファイルをコンテナ内の指定パスにコピー
COPY nginx.conf /etc/nginx/nginx.conf
# 4. ホストPCのWebコンテンツディレクトリをコンテナ内の公開ディレクトリにコピー
COPY ./html /usr/share/nginx/html
# 5. (任意) このコンテナが公開するポート番号を宣言 (ドキュメント目的)
EXPOSE 80
# 6. コンテナが起動した時に実行されるデフォルトコマンド
CMD ["nginx", "-g", "daemon off;"]
4. よく使うDockerfileの命令 (Instruction)
Dockerfileで特によく使われる命令を解説します。
FROM <イメージ>[:<タグ>]
-
- 必須: Dockerfileの最初の命令である必要があります(
ARGを除く)。 - ベースとなるイメージを指定します。タグを省略すると
latestが使われますが、再現性のために具体的なタグ(例:ubuntu:22.04)を指定することが強く推奨されます。 FROM scratchとすると、ベースイメージなし(空)からイメージを構築できます(超軽量イメージ作成時など)。
- 必須: Dockerfileの最初の命令である必要があります(
RUN <コマンド>
-
- イメージをビルドする過程で実行したいシェルコマンドを記述します。
- パッケージのインストール (
apt-get install,pip installなど)、ディレクトリ作成 (mkdir)、コンパイルなどに使われます。 RUN命令ごとに新しいイメージレイヤーが作成されます。キャッシュを意識し、変更頻度の低い処理を先に、変更頻度の高い処理を後に記述するのがセオリーです。# requirements.txt が変更されない限り、pip install はキャッシュされる COPY requirements.txt . RUN pip install -r requirements.txt COPY . . # ソースコードのコピーは最後に
COPY <コピー元(ホスト)> <コピー先(コンテナ)>
-
- ホストPC(ビルドコンテキスト内)のファイルやディレクトリを、コンテナイメージ内にコピーします。
- 基本的にファイルのコピーには
COPYを使うことが推奨されます。 --chown=<ユーザー>:<グループ>オプションで、コピー時に所有者を指定できます(非rootユーザーでの実行に便利)。
ADD <コピー元(ホスト or URL)> <コピー先(コンテナ)>
-
COPYの機能に加え、以下の特殊機能があります。<コピー元>が URL の場合、ファイルをダウンロードしてコピーします。<コピー元>が ローカルのtar圧縮ファイル (gzip,bzip2,xz) の場合、自動的に展開してコピーします。
- これらの自動機能は意図しない動作を招く可能性やセキュリティリスクがあるため、基本的には
COPYを使い、URLからのダウンロードや自動展開が必要な場合にのみADDを検討してください。
WORKDIR <パス>
-
- これ以降に続く
RUN,CMD,ENTRYPOINT,COPY,ADD命令を実行する際の**作業ディレクトリ(カレントディレクトリ)**を指定します。 - 指定しない場合のデフォルトは
/(ルート) です。 - 絶対パスでの指定が推奨されます。パスが存在しない場合は自動的に作成されます。
WORKDIR /app COPY requirements.txt . # /app/requirements.txt にコピーされる RUN pip install -r requirements.txt # /app で実行される
- これ以降に続く
CMD ["実行ファイル", "パラメータ1", "パラメータ2"] (推奨: exec形式)
-
- コンテナが起動した時にデフォルトで実行されるコマンドを指定します。
- Dockerfile内に複数記述された場合、最後の
CMDのみ有効になります。 docker runコマンドで引数を指定した場合、CMDの内容は上書きされます。- 主に、コンテナのメインプロセスを起動するために使われます。
ENTRYPOINT ["実行ファイル", "パラメータ1", "パラメータ2"] (推奨: exec形式)
-
- コンテナが起動した時に必ず実行されるコマンドを指定します。
docker runコマンドで引数を指定した場合、その引数はENTRYPOINTで指定されたコマンドの追加パラメータとして渡されます(CMDのように上書きされません)。CMDとENTRYPOINTを組み合わせることで、デフォルトのパラメータを指定しつつ、docker runでパラメータを上書き可能にする、といった使い方ができます。ENTRYPOINT ["echo", "Hello"] CMD ["world"] # docker run <イメージ名> -> Hello world と表示 # docker run <イメージ名> Docker -> Hello Docker と表示- コンテナを特定の実行ファイルのように振る舞わせたい場合に使われます。
ENV <キー>=<値>
-
- コンテナ内で利用できる環境変数を設定します。
- ビルド時だけでなく、コンテナ実行時にも参照されます。
- アプリケーションの設定値(APIキー、接続先情報など)を渡すのによく使われますが、Dockerfileに直接機密情報を書き込むのは避けるべきです(
.envファイルやDocker Secretsなどを利用)。
ARG <キー>[=<デフォルト値>]
-
- Dockerfileのビルド時にのみ利用できる変数を定義します。
docker build --build-arg <キー>=<値>で外部から値を渡すことができます。 - コンテナ実行時には参照できません。
ENVと組み合わせて、ビルド時に渡された値を環境変数として設定することは可能です。
- Dockerfileのビルド時にのみ利用できる変数を定義します。
EXPOSE <ポート番号>[/<プロトコル>]
-
- このコンテナがリッスンする(待ち受ける)ネットワークポートをドキュメント化するための命令です。
- 実際にポートを公開(ホストOSにマッピング)する機能はありません。ポートの公開は
docker run -pやdocker-compose.ymlのportsで行います。 - デフォルトプロトコルは
tcpです。udpも指定可能です (例:EXPOSE 80/tcp 53/udp)。
USER <ユーザー名>[:<グループ名>]
-
- これ以降の
RUN,CMD,ENTRYPOINT命令を実行するユーザーを指定します。 - セキュリティのベストプラクティスとして、非rootユーザーでコンテナを実行することが強く推奨されます。事前に
RUN命令でユーザーとグループを作成しておく必要があります。# 非rootユーザーを作成 RUN addgroup -S appgroup && adduser -S appuser -G appgroup # ... ファイルコピーなど ... # ユーザーを切り替え USER appuser # アプリケーション起動 CMD ["python", "app.py"]
- これ以降の
VOLUME ["<パス>"]
-
- 指定したパスを、外部からマウント可能なボリュームとして定義します。
- データを永続化したいディレクトリ(例: データベースのデータディレクトリ、ログディレクトリ)を指定します。
- 実際にホストのどの領域にマウントするかは
docker run -vやdocker-compose.ymlのvolumesで指定します。
LABEL <キー>=<値>
-
- イメージにメタデータ(作者情報、バージョン、説明など)を付与します。
5. Dockerfileからイメージをビルドする (docker build)
Dockerfileを作成したら、docker build コマンドを使ってイメージを構築します。
# 基本構文
docker build [オプション] <Dockerfileがあるパス or URL>
# よく使うオプション
# -t, --tag <イメージ名>:<タグ> : 作成するイメージに名前とタグを付ける (例: myapp:1.0)
# -f, --file <Dockerfileのパス> : デフォルト名(Dockerfile)以外のファイルを使う場合
# --build-arg <キー>=<値> : ARG命令で定義した変数に値を渡す
# --no-cache : ビルドキャッシュを使わずに強制的に再ビルドする
# --target <ステージ名> : マルチステージビルドで、特定のステージまでビルドする
# 例: カレントディレクトリ(.)のDockerfileを使って、myapp:latest というイメージを作成
docker build -t myapp:latest .
6. ベストプラクティスと高度なテクニック
より効率的で、安全で、軽量なイメージを作成するためのヒントです。
レイヤーキャッシュを意識する:
-
- 変更頻度の低い命令(OSのアップデート、ライブラリのインストール)を先に、変更頻度の高い命令(ソースコードのコピー)を後に記述します。
RUN命令は&&で繋いでレイヤー数を減らすことを検討しますが、キャッシュ効率とのバランスを見ます。
.dockerignore を活用する:
-
- ビルドコンテキストを最小限にし、ビルド速度を向上させ、不要なファイルがイメージに含まれるのを防ぎます。
マルチステージビルドを活用する:
-
- ビルドに必要なツール(コンパイラ、SDKなど)と、実行に必要なランタイムのみを含む最終イメージを分けることで、イメージサイズを劇的に削減できます。セキュリティ向上にも繋がります。
# --- ビルドステージ --- FROM golang:1.18 AS builder WORKDIR /app COPY . . RUN go build -o myapp . # --- 実行ステージ --- FROM alpine:latest WORKDIR /app COPY --from=builder /app/myapp . # ビルド成果物のみコピー CMD ["./myapp"]
- ビルドに必要なツール(コンパイラ、SDKなど)と、実行に必要なランタイムのみを含む最終イメージを分けることで、イメージサイズを劇的に削減できます。セキュリティ向上にも繋がります。
非rootユーザーで実行する:
-
- コンテナ内での権限昇格リスクを低減するため、
USER命令を使って専用の非rootユーザーでプロセスを実行します。
- コンテナ内での権限昇格リスクを低減するため、
軽量なベースイメージを選ぶ:
-
alpineやslimタグが付いたイメージは、通常のイメージよりもサイズが小さく、セキュリティリスクも低減できます。ただし、必要なツールが含まれていない場合があるので注意が必要です。
イメージの脆弱性スキャンを行う:
-
docker scanコマンド (Docker Desktop連携) や、AWS ECRなどのレジストリが提供するスキャン機能を使って、イメージに含まれる既知の脆弱性をチェックします。
hadolint などのLinterツールを使う:
-
- Dockerfileの書き方がベストプラクティスに従っているかを静的に解析し、改善点を指摘してくれます。
まとめ
Dockerfileは、Dockerイメージを作成するための強力なツールです。
- 各命令の意味と役割を理解しましょう (
FROM,RUN,COPY,CMD,WORKDIRなど)。 - レイヤーキャッシュとビルドコンテキストを意識して、効率的なビルドを目指しましょう。
- マルチステージビルド、非rootユーザー実行、
.dockerignoreなどを活用し、軽量で安全なイメージを作成しましょう。
Dockerfileを使いこなせるようになれば、Difyのような複雑なアプリケーションでも、その環境構築を完全にコントロールできるようになります。


コメント