Dockerfile入門|基本の書き方からイメージのビルド・コンテナ起動まで解説


はじめに

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まで作業ディレクトリが変更されるわけではありません。

比較項目WORKDIRRUN cd
主な役割作業ディレクトリの設定コマンド実行中のディレクトリ変更
後続のRUNへの影響ありなし
指定方法WORKDIR /tmpRUN 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の違い

比較項目ENVARG
主な用途環境変数の設定ビルド時の変数
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では、以下の処理を指定しています。

  1. FROMでベースイメージを指定する
  2. RUNでApacheをインストールする
  3. EXPOSEで80番ポートを宣言する
  4. 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.vendorACME Incorporated
com.example.label-with-valuefoo
version1.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では、以下の内容を指定しています。

  1. Nginxのイメージをベースとして使用する
  2. LABELで作者情報を設定する
  3. LABELでバージョン情報を設定する
  4. 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では、次の処理を指定しています。

  1. Alpine Linuxをベースイメージとして使用する
  2. /var/disk1をボリュームのマウントポイントとして宣言する
  3. コンテナ起動時のデフォルトコマンドとして/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命令だけでは、名前付きボリュームの名前を指定することはできません。

比較項目VOLUMEdocker 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 buildDockerイメージをビルドする
-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"]

この例では、次の処理を自動化しています。

  1. ベースイメージを指定する
  2. イメージのバージョン情報を設定する
  3. Apacheをインストールする
  4. HTMLファイルをコピーする
  5. コンテナが使用するポートを宣言する
  6. コンテナ起動時に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を作成し、それぞれの命令の役割を確認してみましょう。

参考資料


コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です