はじめに
Dockerを使ってアプリケーションを動かす際には、Dockerイメージが必要です。
Docker Hubなどで公開されているイメージを使用することもできますが、独自のアプリケーションを動かしたい場合や、必要なパッケージを追加したい場合には、自分でDockerイメージを作成する必要があります。
そこで使用するのが「Dockerfile」です。
Dockerfileを使用すると、Dockerイメージの作成手順をファイルに記述し、イメージのビルドを自動化できます。
本記事では、Dockerfileの基本的な書き方から、主要な命令の役割、Dockerイメージのビルド方法、コンテナの起動方法までを解説します。
特に、以下の内容を具体例とともに説明します。
FROMによるベースイメージの指定とタグ・ダイジェストRUNのシェル形式とexec形式COPYによるファイルのコピーWORKDIRによる作業ディレクトリの指定ENVとARGによる変数の設定EXPOSEによるポートの宣言LABELによるメタデータの設定USERによる実行ユーザーの指定VOLUMEによるボリュームの指定CMDとENTRYPOINTの違いdocker buildとdocker runの基本操作
Dockerfileとは
Dockerfileとは、Dockerイメージを作成するための手順を記述するテキストファイルです。
Dockerfileには、ベースとなるイメージや、必要なパッケージのインストール、ファイルのコピー、コンテナ起動時に実行するコマンドなどを記述できます。
例えば、Apache HTTP ServerをインストールしたDockerイメージを作成する場合、次のように記述します。
FROM centos:7
RUN yum install -y httpd
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
このDockerfileには、次の3つの命令が記述されています。
FROM:ベースとなるDockerイメージを指定するRUN:Dockerイメージのビルド時にコマンドを実行するCMD:コンテナ起動時に実行するデフォルトのコマンドを指定する
このようにDockerfileに必要な処理を記述することで、同じ手順でDockerイメージを作成できます。
※上記は参考資料で使用されているCentOS 7の例です。CentOS 7はサポートが終了しているため、新規開発でそのまま採用することは推奨しません。
Dockerfileの基本構文
Dockerfileは、基本的に次の形式で記述します。
命令 引数
例えば、ベースイメージを指定する場合は次のように記述します。
FROM nginx:alpine
Dockerfileでは、FROM、RUN、COPY、CMDなど、用途に応じてさまざまな命令を使用します。
Dockerfileで使用する主な命令
| 命令 | 役割 |
|---|---|
FROM | ベースとなるDockerイメージを指定する |
RUN | ビルド時にコマンドを実行する |
CMD | コンテナ起動時のデフォルトコマンドや引数を指定する |
ENTRYPOINT | コンテナ起動時に実行するコマンドを指定する |
COPY | ファイルやディレクトリをイメージにコピーする |
ADD | ファイルのコピーやアーカイブの展開を行う |
WORKDIR | 作業ディレクトリを指定する |
ENV | 環境変数を設定する |
ARG | ビルド時に使用する変数を定義する |
EXPOSE | コンテナが使用するポートを宣言する |
LABEL | イメージにメタデータを設定する |
USER | コマンドを実行するユーザーを指定する |
VOLUME | ボリュームのマウントポイントを指定する |
ここからは、主要な命令の使用方法を説明します。
FROM:ベースイメージを指定する
FROMは、Dockerイメージを作成する際のベースとなるイメージを指定する命令です。
例えば、次のように記述します。
FROM nginx:alpine
この例では、NginxのDockerイメージをベースとして使用します。
FROMでタグを指定する方法
FROMでは、イメージ名の後ろにコロン(:)を付けてタグを指定できます。
FROM イメージ名:タグ
例えば、次のように記述します。
FROM centos:7
この例では、centosがイメージ名、7がタグです。
タグは、Dockerイメージのバージョンや種類などを識別するために使用されます。
FROMでタグを省略した場合
タグを省略してイメージ名だけを指定することもできます。
FROM centos
この場合、通常はlatestタグが指定されたものとして扱われます。
FROM centos:latest
ただし、latestは必ずしも最新バージョンのイメージであることを保証するものではありません。
FROMでダイジェストを指定する方法
FROMでは、タグの代わりにダイジェストを使用してイメージを指定することもできます。
ダイジェストとは、イメージを識別するために使用されるハッシュ値です。
基本構文は次のとおりです。
FROM イメージ名@sha256:ダイジェスト値
参考資料では、次の例が紹介されています。
FROM centos@sha256:a799dd8a2ded4a83484bbae769d97655392b3f86533ceb7dd96bbac929809f3c
このように、@sha256:を使用すると、ダイジェストによってベースイメージを指定できます。
※参考資料に記載されたダイジェストの例であり、現在も取得できることを保証するものではありません。
docker images –digestsでダイジェストを確認する
ダイジェストは次のコマンドで確認できます。
docker images --digests
表示形式の例:
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
centos 7 sha256:... xxxxxxxxxxxx ... ...
各項目の意味は次のとおりです。
| 項目 | 説明 |
|---|---|
REPOSITORY | イメージ名 |
TAG | イメージのタグ |
DIGEST | イメージのダイジェスト |
IMAGE ID | ローカルイメージの識別子 |
CREATED | イメージの作成日時 |
SIZE | イメージのサイズ |
なお、イメージによってはDIGESTに<none>と表示される場合もあります。
タグとダイジェストの違い
| 比較項目 | タグ | ダイジェスト |
|---|---|---|
| 指定方法 | イメージ名:タグ | イメージ名@sha256:値 |
| 識別方法 | タグ名 | ハッシュ値 |
| 参照先 | 同じタグが別の内容を指す場合がある | 特定の内容を識別する |
| 主な目的 | バージョンや種類の指定 | 特定のイメージ内容の指定 |
タグは人間が識別しやすく、ダイジェストは特定のイメージ内容を指定できるという違いがあります。
RUN:ビルド時にコマンドを実行する
RUNは、Dockerイメージをビルドする際にコマンドを実行する命令です。
例えば、Apache HTTP Serverをインストールする場合は、次のように記述します。
RUN yum install -y httpd
RUNは、パッケージのインストール、ファイル操作、設定の変更などに使用します。
RUNのシェル形式とexec形式
RUNには、2つの記述形式があります。
シェル形式
RUN yum install -y httpd
exec形式
RUN ["yum", "install", "-y", "httpd"]
シェル形式では、Linuxの場合、通常/bin/sh -cを介してコマンドが実行されます。
例えば、次のDockerfileを考えます。
FROM alpine:3.21
RUN echo "Hello Docker"
ビルド時の出力:
Hello Docker
一方、exec形式では、指定したコマンドが直接実行されます。
RUN ["echo", "Hello Docker"]
シェル形式とexec形式の比較
| 比較項目 | シェル形式 | exec形式 |
|---|---|---|
| 記述方法 | コマンド文字列 | JSON配列 |
| 実行方法 | シェル経由 | 直接実行 |
| 環境変数の展開 | シェルによる展開が可能 | シェルによる展開は行われない |
&&の利用 | 可能 | 直接は利用できない |
RUNで複数のコマンドを実行する
RUNでは、&&を使用して複数のコマンドを連結できます。
RUN yum update -y && yum install -y httpd
&&は、前のコマンドが正常終了した場合に次のコマンドを実行します。
一方、;を使用すると、前のコマンドの成否にかかわらず次のコマンドを実行できます。
RUN echo "Hello"; echo "Docker"
| 演算子 | 動作 |
|---|---|
&& | 前のコマンドが成功した場合に次を実行 |
; | 前のコマンドの成否にかかわらず次を実行 |
RUNを複数行で記述する
長いコマンドは、バックスラッシュ(\)を使って複数行に分けて記述できます。
RUN yum update -y && \
yum install -y httpd && \
echo "Apache installed"
このように記述することで、コマンドの処理順序がわかりやすくなります。
複数のRUNをまとめる
Dockerfileでは、次のようにRUNを複数記述できます。
RUN yum update -y
RUN yum install -y httpd
一方、関連する処理を1つのRUNにまとめることもできます。
RUN yum update -y && \
yum install -y httpd
RUNの処理結果は、Dockerイメージのレイヤに記録されます。
関連する処理をまとめることでレイヤ構成を整理できますが、すべてのRUNを無理にまとめる必要はありません。
処理内容やDockerfileの読みやすさも考慮しましょう。
COPY:ファイルやディレクトリをコピーする
COPYは、ビルドコンテキスト内のファイルやディレクトリをDockerイメージにコピーする命令です。
COPY ./file1.conf /etc/file1.conf
この例では、file1.confをイメージ内の/etc/file1.confにコピーします。
ディレクトリをコピーすることもできます。
COPY ./my-app /opt/my-app
アプリケーションのソースコードや設定ファイルを追加する場合によく使用します。
WORKDIR:作業ディレクトリを指定する
WORKDIRは、Dockerfile内で使用する作業ディレクトリを指定する命令です。
WORKDIR /app
指定したディレクトリは、後続のRUN、CMD、ENTRYPOINTなどで使用されます。
WORKDIRの基本的な使い方
例えば、次のDockerfileを考えます。
FROM alpine:3.21
WORKDIR /tmp
RUN pwd
実行結果:
/tmp
WORKDIR /tmpによって作業ディレクトリが設定されるため、RUN pwdでは/tmpが表示されます。
WORKDIRを複数指定した場合
WORKDIRは1つのDockerfile内で複数回記述できます。
WORKDIR /tmp
RUN pwd
WORKDIR /var
RUN pwd
実行結果:
/tmp
/var
この例では、最初のWORKDIRによって作業ディレクトリが/tmpになります。
その後、2つ目のWORKDIRで/varに変更しています。
後続の命令には、直前のWORKDIRで指定したディレクトリが適用されます。
WORKDIRの複数指定を確認する
実際に動作を確認する場合は、次のDockerfileを作成します。
FROM alpine:3.21
WORKDIR /tmp
RUN pwd
WORKDIR /var
RUN pwd
次のコマンドでビルドします。
docker build --progress=plain -t workdir-sample .
ビルドログ内のRUN pwdの出力を確認すると、作業ディレクトリが変更されていることがわかります。
WORKDIRで環境変数を使用する
WORKDIRでは、ENVで設定した環境変数を使用できます。
ENV BASE_DIR=/opt/myapp
WORKDIR $BASE_DIR/tmp
この場合、$BASE_DIRが/opt/myappに展開されます。
そのため、作業ディレクトリは次のようになります。
/opt/myapp/tmp
実際に確認する場合は、次のDockerfileを使用します。
FROM alpine:3.21
ENV BASE_DIR=/opt/myapp
WORKDIR $BASE_DIR/tmp
RUN pwd
RUN pwdの実行結果:
/opt/myapp/tmp
WORKDIRとRUN cdの違い
WORKDIRとRUN cdは、どちらも作業ディレクトリに関係しますが、役割が異なります。
WORKDIR /tmp
RUN pwd
この場合、後続の命令にも/tmpが作業ディレクトリとして適用されます。
一方、次のように記述した場合です。
RUN cd /tmp && pwd
cd /tmpによるディレクトリ変更は、そのRUNの実行中に行われます。
後続のRUNまで作業ディレクトリが変更されるわけではありません。
| 比較項目 | WORKDIR | RUN cd |
|---|---|---|
| 主な役割 | 作業ディレクトリの設定 | コマンド実行中のディレクトリ変更 |
| 後続のRUNへの影響 | あり | なし |
| 指定方法 | WORKDIR /tmp | RUN cd /tmp && ... |
後続の命令でも同じ作業ディレクトリを使用したい場合は、WORKDIRが適しています。
ENV:環境変数を設定する
ENVは、Dockerfile内で環境変数を設定する命令です。
環境変数とは、アプリケーションやコマンドが参照できる名前付きの値です。
ENVの基本的な書き方
ENV 変数名=値
例えば、次のように記述します。
ENV DB_HOST=192.168.2.201
ENV DB_PORT=3306
ENVで設定した環境変数は、イメージから起動したコンテナにも引き継がれます。
ENVで設定した値を使用する
FROM alpine:3.21
ENV DB_HOST=192.168.2.201
RUN echo "$DB_HOST"
ビルド時の出力:
192.168.2.201
シェル形式のRUNでは、$DB_HOSTが環境変数の値に展開されます。
ENVで複数の環境変数を設定する
ENVでは、複数の環境変数を1つの命令で設定できます。
ENV DB_HOST="192.168.2.201" \
DB_PORT="3306" \
DB_USER="myapp" \
DB_DATABASE="sample"
バックスラッシュ(\)を使用することで、複数行に分けて記述できます。
なお、パスワードなどの秘密情報をDockerfileのENVに直接記述することは避けてください。
ARG:ビルド時に使用する変数を定義する
ARGは、Dockerイメージのビルド時に使用する変数を定義する命令です。
ENVと似ていますが、使用目的が異なります。
ARGの基本的な書き方
ARG 変数名=デフォルト値
例えば、次のように記述します。
ARG user=unknown
この場合、userというビルド引数を定義し、デフォルト値としてunknownを設定しています。
ARGで設定した値を使用する
FROM alpine:3.21
ARG user=unknown
RUN echo "$user"
次のコマンドでビルドします。
docker build -t my-app .
ビルド時の出力:
unknown
docker build –build-argで値を変更する
ARGで定義した変数は、--build-argによって変更できます。
docker build -t my-app --build-arg user=tanaka .
この場合、ビルド時にはtanakaが使用されます。
ENVとARGの違い
| 比較項目 | ENV | ARG |
|---|---|---|
| 主な用途 | 環境変数の設定 | ビルド時の変数 |
| Dockerfile内での使用 | 可能 | 可能 |
| RUNでの参照 | 可能 | 可能 |
| コンテナ起動後 | 環境変数として引き継がれる | ARG自体は引き継がれない |
| ビルド時の値の変更 | ENVを直接--build-argで変更するわけではない | --build-argを使用できる |
コンテナ起動後にも必要な値にはENV、ビルド時に使用する値にはARGを利用できます。
なお、ARGもパスワードなどの秘密情報を安全に渡す仕組みではありません。
EXPOSE:コンテナが使用するポートを宣言する
EXPOSEは、コンテナが使用するネットワークポートを宣言するための命令です。
例えば、Webサーバーが80番ポートを使用する場合は、次のように記述します。
EXPOSE 80
この記述によって、コンテナが80番ポートを使用することをDockerイメージのメタデータとして示せます。
EXPOSEの基本的な書き方
EXPOSEは、次の形式で記述します。
EXPOSE ポート番号
例えば、Apache HTTP Serverを使用する場合は次のように記述できます。
FROM centos:7
RUN yum install -y httpd
EXPOSE 80
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
このDockerfileでは、以下の処理を指定しています。
FROMでベースイメージを指定するRUNでApacheをインストールするEXPOSEで80番ポートを宣言するCMDでApacheを起動する
このように、DockerfileにEXPOSEを記述することで、コンテナが使用するポートを明示できます。
※上記は参考PDFに登場するCentOS 7とApacheの構成を組み合わせた説明例です。CentOS 7はサポート終了済みです。
EXPOSEとdocker run -pの違い
EXPOSEを理解する際に注意したいのは、EXPOSEを記述しただけでは、ホスト側にポートが公開されるわけではないということです。
例えば、次のDockerfileを考えます。
FROM nginx:alpine
EXPOSE 80
この場合、コンテナが80番ポートを使用することは宣言されていますが、ホストの8080番ポートからアクセスできるようになるわけではありません。
ホスト側からアクセスするには、次のようにdocker runでポートを公開します。
docker build -t my-app .
docker run --name my-nginx -p 8080:80 -d my-app
この場合、ホストの8080番ポートがコンテナの80番ポートに接続されます。
| 指定方法 | 役割 |
|---|---|
EXPOSE 80 | コンテナが使用する80番ポートを宣言する |
docker run -p 8080:80 | ホストの8080番ポートをコンテナの80番ポートへ公開する |
このように、EXPOSEとdocker run -pは役割が異なります。
EXPOSEのまとめ
EXPOSEは、コンテナが使用するポートを宣言する命令です。
基本的な記述例:
EXPOSE 80
ただし、EXPOSEを記述しただけではホスト側にポートは公開されません。
ホスト側からアクセスする場合は、必要に応じてdocker run -pなどでポートを公開します。
LABEL:Dockerイメージにメタデータを設定する
LABELは、Dockerイメージにメタデータを設定するための命令です。
メタデータとは、イメージ自体に付ける補足情報のことです。
例えば、作者名、ベンダー名、バージョン情報などを設定できます。
LABELの基本的な書き方
LABELは、次の形式で記述します。
LABEL キー="値"
例えば、Dockerイメージのバージョン情報を設定する場合は、次のように記述します。
LABEL version="1.0"
この例では、versionというキーに1.0という値を設定しています。
LABELで作者やベンダー情報を設定する
参考資料では、次のような例が紹介されています。
LABEL com.example.vendor="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
それぞれの設定は次のとおりです。
| キー | 値 |
|---|---|
com.example.vendor | ACME Incorporated |
com.example.label-with-value | foo |
version | 1.0 |
このように、複数のLABELを記述することで、Dockerイメージに情報を追加できます。
複数のLABELを1つにまとめる
LABELでは、複数のキーと値を1つの命令で設定できます。
参考資料では、次のような記述方法が紹介されています。
LABEL com.example.vendor="ACME Incorporated" \
com.example.label-with-value="foo" \
version="1.0"
バックスラッシュ(\)を使用することで、複数行に分けて記述できます。
このようにまとめると、関連するメタデータを1か所に記述できます。
MAINTAINERとLABELの違い
参考資料では、MAINTAINERという命令も紹介されています。
MAINTAINERは、Dockerイメージの作者を指定するための命令です。
例えば、次のように記述します。
MAINTAINER yamada <yamada@example.com>
ただし、MAINTAINERは非推奨の命令です。
そのため、作者情報を設定する場合は、LABELを使用する方法が推奨されています。
例えば、次のように記述します。
LABEL maintainer="yamada <yamada@example.com>"
このように、Dockerイメージの作者情報をメタデータとして設定できます。
LABELを使用したDockerfileの例
次のDockerfileを考えます。
FROM nginx:alpine
LABEL maintainer="yamada <yamada@example.com>" \
version="1.0"
EXPOSE 80
このDockerfileでは、以下の内容を指定しています。
- Nginxのイメージをベースとして使用する
LABELで作者情報を設定するLABELでバージョン情報を設定するEXPOSEで80番ポートを宣言する
このように、LABELを使用することで、Dockerイメージに補足情報を設定できます。
LABELのまとめ
LABELは、Dockerイメージにメタデータを設定するための命令です。
作者名、バージョン、ベンダー名などを設定できます。
LABEL maintainer="yamada <yamada@example.com>" \
version="1.0"
また、非推奨のMAINTAINERの代わりに、LABELを使用する方法が推奨されています。
USER:コマンドを実行するユーザーを指定する
USERは、Dockerfile内で実行するコマンドや、コンテナ起動時のプロセスを実行するユーザーを指定する命令です。
ユーザー名、またはユーザーIDを指定できます。
USERの基本的な書き方
USERは、次の形式で記述します。
USER ユーザー名
例えば、次のように記述します。
USER apache
この例では、以降のコマンドを実行するユーザーとしてapacheを指定しています。
また、ユーザーIDを指定することもできます。
USER 1000
このように、ユーザー名だけでなく、数値のユーザーIDによっても実行ユーザーを指定できます。
USERとCMDを組み合わせる
参考資料では、次のような例が紹介されています。
USER apache
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
この場合、CMDで指定したコマンドは、apacheユーザーとして実行される設定になります。
なお、ユーザー名を指定する場合は、コンテナ内にそのユーザーが存在している必要があります。また、対象のプログラムがそのユーザーの権限で起動できることも必要です。
USERが影響する命令
USERで指定したユーザーは、主に次の処理で使用されます。
| 対象 | USERの影響 |
|---|---|
RUN | ビルド時に実行するコマンドのユーザー |
CMD | コンテナ起動時の実行ユーザー |
ENTRYPOINT | コンテナ起動時の実行ユーザー |
例えば、次のDockerfileを考えます。
FROM alpine:3.21
USER 1000
RUN id
この場合、RUN idは指定されたユーザーIDで実行されます。
実行環境やファイルの権限によっては、指定したユーザーでは実行できない操作もあります。
USERを指定する際の注意点
USERで実行ユーザーを指定した場合、そのユーザーの権限でコマンドが実行されます。
そのため、次のような操作では権限に注意する必要があります。
- パッケージのインストール
- システムディレクトリへのファイルの書き込み
- アプリケーションの起動
必要な権限がない場合、コマンドが失敗することがあります。
USERのまとめ
USERは、Dockerfile内で実行するコマンドや、コンテナ起動時のプロセスを実行するユーザーを指定する命令です。
ユーザー名を使用する例:
USER apache
ユーザーIDを使用する例:
USER 1000
実行ユーザーを指定する場合は、対象のコマンドを実行できる権限があるかを確認しましょう。
VOLUME:ボリュームのマウントポイントを指定する
VOLUMEは、Dockerコンテナで使用するボリュームのマウントポイントを指定する命令です。
Dockerコンテナの内部に保存されるデータとは別に、ボリュームを利用してデータを管理するための設定を行えます。
VOLUMEの基本的な書き方
VOLUMEは、次のように記述します。
VOLUME /var/disk1
この例では、コンテナ内の/var/disk1をボリュームのマウントポイントとして指定しています。
参考資料では、複数のマウントポイントを指定する例が紹介されています。
VOLUME /var/disk1 /var/disk2 /var/disk3
このように、複数のディレクトリを指定することもできます。
VOLUMEを使用したDockerfileの例
例えば、次のDockerfileを考えます。
FROM alpine:3.21
VOLUME /var/disk1
CMD ["/bin/sh"]
このDockerfileでは、次の処理を指定しています。
- Alpine Linuxをベースイメージとして使用する
/var/disk1をボリュームのマウントポイントとして宣言する- コンテナ起動時のデフォルトコマンドとして
/bin/shを指定する
VOLUMEを指定したディレクトリには、コンテナ起動時にボリュームを割り当てることができます。
通常、別のボリュームを明示していなければ、Dockerが匿名ボリュームを作成してマウントします。
VOLUMEとdocker run -vの違い
参考資料では、VOLUMEとdocker run -vの違いについて説明されています。
docker runでは、-vオプションによってマウントするボリュームを指定できます。
例えば、次のように記述します。
docker run -v mydata:/var/disk1 my-app
この場合、mydataという名前付きボリュームを、コンテナ内の/var/disk1にマウントします。
一方、DockerfileのVOLUMEでは、マウントポイントを指定します。
VOLUME /var/disk1
DockerfileのVOLUME命令だけでは、名前付きボリュームの名前を指定することはできません。
| 比較項目 | VOLUME | docker run -v |
|---|---|---|
| 指定場所 | Dockerfile | コンテナ起動コマンド |
| 主な役割 | マウントポイントの宣言 | マウントの設定 |
| 名前付きボリュームの指定 | できない | できる |
| 記述例 | VOLUME /var/disk1 | -v mydata:/var/disk1 |
ボリュームの保存場所
参考資料では、Dockerのボリュームがホスト側の次のような場所に作成されると説明されています。
/var/lib/docker/volumes
ただし、実際の保存場所はDockerの実行環境によって異なります。
例えば、Docker Desktopでは、ボリュームが内部のLinux環境に管理されるため、ホストOS上の同じパスを直接参照できるとは限りません。
VOLUMEを使用する際の注意点
VOLUMEを使用する際は、次の点に注意しましょう。
1. Dockerfileではマウントポイントを指定する
VOLUME /var/disk1
VOLUMEは、ボリュームの名前を指定するための命令ではありません。
2. 名前付きボリュームを使用する場合はdocker run -vで指定できる
docker run -v mydata:/var/disk1 my-app
この場合、名前付きボリュームmydataが使用されます。
3. 匿名ボリュームも作成される
DockerfileのVOLUMEで指定したマウントポイントに、起動時に別のボリュームを割り当てなかった場合、Dockerは通常匿名ボリュームを作成します。
匿名ボリュームは、コンテナを削除しただけでは必ずしも削除されません。
VOLUMEのまとめ
VOLUMEは、コンテナ内で使用するボリュームのマウントポイントを指定する命令です。
基本的な記述例:
VOLUME /var/disk1
複数指定する場合:
VOLUME /var/disk1 /var/disk2 /var/disk3
名前付きボリュームを指定する場合は、docker run -vなどを使用します。
EXPOSE・LABEL・USER・VOLUMEの違い
ここまで紹介した4つの命令を比較します。
| 命令 | 主な役割 | 記述例 |
|---|---|---|
EXPOSE | コンテナが使用するポートを宣言する | EXPOSE 80 |
LABEL | イメージにメタデータを設定する | LABEL version="1.0" |
USER | コマンドを実行するユーザーを指定する | USER apache |
VOLUME | ボリュームのマウントポイントを指定する | VOLUME /var/disk1 |
それぞれの命令は、目的が異なります。
EXPOSEはネットワークポート、LABELはメタデータ、USERは実行ユーザー、VOLUMEはボリュームのマウントポイントを指定します。
Dockerfileでは、これらの命令を必要に応じて組み合わせて使用できます。
CMD:コンテナ起動時のデフォルトコマンドを指定する
CMDは、コンテナ起動時に実行するデフォルトのコマンド、またはENTRYPOINTに渡すデフォルト引数を指定する命令です。
例えば、Apacheをフォアグラウンドで実行する場合は、次のように記述します。
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
CMDには、シェル形式とexec形式があります。
exec形式
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
シェル形式
CMD /usr/sbin/httpd -DFOREGROUND
exec形式では、指定したプログラムを直接実行します。
シェル形式では、通常シェルを介してコマンドが実行されます。
コンテナのメインプロセスを指定する際は、停止シグナルの扱いを考慮してexec形式を使用することが推奨されます。
docker runでCMDを置き換える
次のDockerfileを考えます。
FROM alpine:3.21
CMD ["/bin/echo", "Hello"]
イメージをビルドします。
docker build -t my-app .
引数なしで起動します。
docker run my-app
実行結果:
Hello
一方、docker runで別のコマンドを指定します。
docker run my-app /bin/echo World
実行結果:
World
この場合、Dockerfileで指定したCMDが置き換えられます。
ENTRYPOINT:コンテナ起動時に実行するコマンドを指定する
ENTRYPOINTは、コンテナ起動時に実行するコマンドを指定する命令です。
CMDと似ていますが、docker runで引数を指定した場合の動作が異なります。
exec形式
ENTRYPOINT ["/bin/echo", "Hello"]
シェル形式
ENTRYPOINT /bin/echo Hello
CMDとENTRYPOINTの違い
主な違いは次のとおりです。
CMD:docker runの引数でデフォルトのコマンドや引数が置き換えられるENTRYPOINT:exec形式では、docker runの引数が指定したコマンドに追加される
例えば、次のDockerfileを考えます。
FROM alpine:3.21
ENTRYPOINT ["/bin/echo", "Hello"]
イメージをビルドします。
docker build -t my-app .
引数なしで実行します。
docker run my-app
実行結果:
Hello
引数を指定して実行します。
docker run my-app World
実行結果:
Hello World
ENTRYPOINTとCMDを組み合わせる
ENTRYPOINTとCMDは組み合わせて使用できます。
FROM alpine:3.21
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["Docker"]
イメージをビルドします。
docker build -t my-app .
引数なしで実行します。
docker run my-app
実行結果:
Hello Docker
引数を指定した場合:
docker run my-app World
実行結果:
Hello World
この場合、CMDで指定したDockerがWorldに置き換えられます。
ENTRYPOINTを変更する
ENTRYPOINTは通常のdocker run引数では置き換えられませんが、--entrypointオプションで変更できます。
例えば、次のDockerfileを使用します。
FROM alpine:3.21
ENTRYPOINT ["/bin/echo", "Hello"]
ビルド後、次のコマンドを実行します。
docker run --entrypoint /bin/echo my-app World
実行結果:
World
このように、ENTRYPOINTは絶対に変更できないわけではありません。
CMDとENTRYPOINTの比較
| 指定方法 | 引数なし | 引数あり |
|---|---|---|
| CMDのみ | CMDを実行 | CMDを置き換える |
| ENTRYPOINTのみ(exec形式) | ENTRYPOINTを実行 | ENTRYPOINTに引数を追加 |
| ENTRYPOINT+CMD(exec形式) | 両方を組み合わせて実行 | CMDを指定引数で置き換える |
なお、シェル形式のENTRYPOINTでは引数の扱いが異なります。
詳しくは関連記事「DockerfileのCMDとENTRYPOINTの違いとは?docker runの引数による動作を実例で比較」で解説しています。
Dockerfileを作成してイメージをビルドする
ここまで説明した内容をもとに、DockerfileからDockerイメージを作成する手順を確認します。
1. 作業ディレクトリを作成する
まず、Dockerfileを配置するディレクトリを作成します。
mkdir docker-sample
cd docker-sample
2. Dockerfileを作成する
作業ディレクトリ内にDockerfileを作成し、次の内容を記述します。
FROM nginx:alpine
LABEL version="1.0"
EXPOSE 80
この例では、NginxをベースとしてDockerイメージを作成します。
さらに、LABELでバージョン情報を設定し、EXPOSEで80番ポートを宣言しています。
RUNやCOPYを使ったカスタマイズは行っていません。
3. Dockerイメージをビルドする
次のコマンドを実行します。
docker build -t my-app .
各指定の意味は次のとおりです。
| 指定 | 意味 |
|---|---|
docker build | Dockerイメージをビルドする |
-t my-app | イメージにmy-appという名前を付ける |
. | 現在のディレクトリをビルドコンテキストとして指定する |
4. Dockerイメージを確認する
ビルドしたイメージは、次のコマンドで確認できます。
docker image ls
表示形式の例:
REPOSITORY TAG IMAGE ID CREATED SIZE
my-app latest xxxxxxxxxxxx 1 minute ago ...
一覧にmy-appが表示されていれば、イメージが作成されています。
5. コンテナを起動する
ビルドしたイメージを使用してコンテナを起動します。
docker run --name my-nginx -p 8080:80 -d my-app
| 指定 | 意味 |
|---|---|
--name my-nginx | コンテナ名を指定する |
-p 8080:80 | ホストの8080番ポートをコンテナの80番ポートに接続する |
-d | バックグラウンドで起動する |
my-app | 使用するDockerイメージ |
重要なのは、ビルド時に作成したイメージ名と、起動時に使用するイメージ名を一致させることです。
docker build -t my-app .
docker run --name my-nginx -p 8080:80 -d my-app
my-nginxはコンテナ名、my-appはイメージ名です。
6. コンテナの状態を確認する
docker ps
表示形式の例:
CONTAINER ID IMAGE STATUS PORTS NAMES
xxxxxxxxxxxx my-app Up ... 0.0.0.0:8080->80/tcp my-nginx
この例では、my-appイメージからmy-nginxコンテナが起動しています。
7. ブラウザからアクセスする
次のURLにアクセスします。
http://localhost:8080
Nginxの初期画面が表示されれば成功です。
8. コンテナを停止・削除する
停止:
docker stop my-nginx
削除:
docker rm my-nginx
これらのコマンドでは、イメージ名ではなくコンテナ名を指定します。
Dockerfileを使用するメリット
Dockerfileを使用する主なメリットは、Dockerイメージの作成手順をファイルとして管理できることです。
手動でパッケージをインストールしたり、設定ファイルを配置したりする場合、同じ作業を再現することが難しくなります。
一方、Dockerfileを使用すると、必要な手順をあらかじめ記述できます。
例えば、次のような構成です。
FROM centos:7
LABEL version="1.0"
RUN yum install -y httpd
COPY ./index.html /var/www/html/index.html
EXPOSE 80
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
この例では、次の処理を自動化しています。
- ベースイメージを指定する
- イメージのバージョン情報を設定する
- Apacheをインストールする
- HTMLファイルをコピーする
- コンテナが使用するポートを宣言する
- コンテナ起動時にApacheを実行する
※参考資料に合わせた説明用の例です。CentOS 7はサポートが終了しています。
まとめ
今回は、Dockerfileの基本的な書き方と、主要な命令の役割、Dockerイメージのビルド方法を解説しました。
Dockerfileでは、FROMでベースイメージを指定し、RUNで必要な処理を実行し、CMDやENTRYPOINTでコンテナ起動時の動作を指定できます。
また、ENVとARGを使用することで、環境変数やビルド時の変数を定義できます。
今回詳しく説明したEXPOSE、LABEL、USER、VOLUMEは、それぞれ異なる目的で使用する命令です。
EXPOSE:ポートの宣言
EXPOSE 80
LABEL:メタデータの設定
LABEL version="1.0"
USER:実行ユーザーの指定
USER apache
VOLUME:マウントポイントの指定
VOLUME /var/disk1
最後に、Dockerfileで使用する主な命令をまとめます。
| 命令 | 主な役割 |
|---|---|
FROM | ベースイメージの指定 |
RUN | ビルド時のコマンド実行 |
COPY | ファイルやディレクトリのコピー |
WORKDIR | 作業ディレクトリの指定 |
ENV | 環境変数の設定 |
ARG | ビルド時の変数の定義 |
EXPOSE | 使用するポートの宣言 |
LABEL | メタデータの設定 |
USER | 実行ユーザーの指定 |
VOLUME | ボリュームのマウントポイント指定 |
CMD | 起動時のデフォルトコマンドや引数の指定 |
ENTRYPOINT | 起動時の実行コマンドの指定 |
Dockerfileでは、これらの命令を組み合わせることで、アプリケーションに必要な構成をイメージとして定義できます。
まずは簡単なDockerfileを作成し、それぞれの命令の役割を確認してみましょう。