Dockerfile リファレンス

Docker は Dockerfile から命令を読み込んで、自動的にイメージをビルドします。 Dockerfile はテキストファイルであり、イメージを作り上げるために実行するコマンドラインコマンドを、すべてこのファイルに含めることができます。 docker build を実行すると、順次コマンドライン命令を自動化した処理が行われて、ビルド結果となるイメージが得られます。

ここでは Dockerfile において利用可能なコマンドを説明します。 このページを読み終えたら、さまざまなガイドとなる Dockerfileベスト・プラクティス を参照してください。

利用方法

docker build コマンドは、Dockerfileコンテキスト (context)からイメージをビルドします。 ビルドにおけるコンテキストとは、指定された PATH または URL にある一連のファイルのことです。 PATH はローカルファイルシステム内のディレクトリを表わします。 URL は Git のリポジトリ URL のことです。

コンテキストは再帰的に処理されます。 つまり PATH の場合はサブディレクトリがすべて含まれ、URL の場合はリポジトリとそのサブモジュールが含まれます。 以下の例におけるビルドコマンドは、コンテキストとしてカレントディレクトリを用いるものです。

$ docker build .
Sending build context to Docker daemon  6.51 MB
...

ビルド処理は Docker デーモンが行うものであって CLI により行われるものではありません。 ビルド処理の開始時にまず行われるのは、コンテキスト全体を(再帰的に)デーモンに送信することです。 普通はコンテキストとして空のディレクトリを用意して、そこに Dockerfile を置きます。 そのディレクトリへは、Dockerfile の構築に必要となるファイルのみを置くようにします。

警告

PATH に対して root ディレクトリ / を指定することはやめてください。 これを行うとビルド時に Docker デーモンに対して、ハードディスクの内容すべてを送り込むことになってしまいます。

ビルドコンテキスト内のファイルを利用する場合、Dockerfile では命令を記述する際にファイル参照を指定します。 たとえば COPY 命令の対象として参照します。 ビルド時の処理性能を上げるために、コンテキストディレクトリ内に .dockerignore ファイルを追加し、不要なファイルやディレクトリは除外するようにします。 詳しくはこのページ内の .dockerignore ファイルの生成方法 <#dockerignore-file>` を参照してください。

慣例として DockerfileDockerfile と命名されています。 またこのファイルはコンテキストディレクトリのトップに置かれます。 docker build-f フラグを用いれば、Dockerfile がファイルシステム内のどこにあっても指定することができます。

$ docker build -f /path/to/a/Dockerfile .

イメージのビルドが成功した後の保存先として、リポジトリとタグを指定することができます。

$ docker build -t shykes/myapp .

ビルドの際に複数のリポジトリに対してイメージをタグづけするには、build コマンドの実行時に -t パラメータを複数指定します。

$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .

Dockerfile 内に記述されている命令を Docker デーモンが実行する際には、事前に Dockerfile が検証され、文法の誤りがある場合にはエラーが返されます。

$ docker build -t test/myapp .
Sending build context to Docker daemon 2.048 kB
Error response from daemon: Unknown instruction: RUNCMD

Docker デーモンは Dockerfile 内の命令を 1 つずつ実行し、必要な場合にはビルドイメージ内にその処理結果を確定します。 最後にビルドイメージの ID を出力します。 Docker デーモンは、送信されたコンテキスト内容を自動的にクリアします。

各命令は個別に実行されます。 それによって新たなイメージがビルドされます。 したがって、たとえば RUN cd /tmp を実行したとしても、次の命令には何の効果も与えません。

Docker は可能な限り中間イメージ(キャッシュ)を再利用しようとします。 これは docker build 処理を速くするためです。 その場合は、端末画面に Using cache というメッセージが出力されます。 (詳細については Dockerfile のベストプラクティスガイドにある ビルドキャッシュの説明 を参照してください。)

$ docker build -t svendowideit/ambassador .
Sending build context to Docker daemon 15.36 kB
Step 1/4 : FROM alpine:3.2
 ---> 31f630c65071
Step 2/4 : MAINTAINER SvenDowideit@home.org.au
 ---> Using cache
 ---> 2a1c91448f5f
Step 3/4 : RUN apk update &&      apk add socat &&        rm -r /var/cache/
 ---> Using cache
 ---> 21ed6e7fbb73
Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh
 ---> Using cache
 ---> 7ea8aef582cc
Successfully built 7ea8aef582cc

ビルドキャッシュは、ローカルにて親イメージへのつながりを持ったイメージからのみ利用されます。 利用されるイメージとはつまり、前回のビルドによって生成されたイメージか、あるいは docker load によってロードされたイメージのいずれかです。 ビルドキャッシュを特定のイメージから利用したい場合は --cache-from オプションを指定します。 --cache-from オプションが用いられた場合に、そのイメージは親イメージへのつながりを持っている必要はなく、他のレジストリから取得するイメージであっても構いません。

ビルドに関する操作を終えたら、次は リポジトリをレジストリへ送信 を読んでみてください。

記述書式

ここに Dockerfile の記述書式を示します。

# Comment
INSTRUCTION arguments

命令(instruction)は大文字小文字を区別しません。 ただし慣習として大文字とします。 そうすることで引数(arguments)との区別をつけやすくします。

Docker は Dockerfile 内の命令を記述順に実行します。 Dockerfile は必ず FROM 命令で 始めなければなりません。 FROM 命令は、ビルドするイメージに対しての ベースイメージ を指定するものです。 FROM よりも先に記述できる命令として ARG があります。 これは FROM において用いられる引数を宣言するものです。

行頭が # で始まる行はコメントとして扱われます。 ただし例外として パーサ・ディレクティブ があります。 行途中の # は単なる引数として扱われます。 以下のような行記述が可能です。

# Comment
RUN echo 'we are running some # of cool things'

コメントにおいて行継続を指示する文字はサポートされていません。

パーサ・ディレクティブ

パーサ・ディレクティブ(parser directive)を利用することは任意です。 これは Dockerfile 内のその後に続く記述行を取り扱う方法を指示するものです。 パーサ・ディレクティブはビルドされるイメージにレイヤを追加しません。 したがってビルドステップとして表示されることはありません。 パーサ・ディレクティブは、特別なコメントの記述方法をとるもので、# ディレクティブ=値 という書式です。 同一のディレクティブは一度しか記述できません。

コメント、空行、ビルド命令が一つでも読み込まれたら、それ以降 Docker はパーサ・ディレクティブの処理を行いません。 その場合、パーサ・ディレクティブの書式で記述されていても、それはコメントとして扱われます。 そしてパーサ・ディレクティブとして適切な書式であるかどうかも確認しません。 したがってパーサ・ディレクティブは Dockerfile の冒頭に記述しなければなりません。

パーサ・ディレクティブは大文字小文字を区別しません。 ただし慣習として小文字とします。 同じく慣習として、パーサ・ディレクティブの次には空行を 1 行挿入します。 パーサ・ディレクティブにおいて、行継続を指示する文字はサポートされていません。

これらのルールがあるため、以下の例は全て無効です。

行の継続は無効:

# direc \
tive=value

二度出現するため無効:

# directive=value1
# directive=value2

FROM ImageName

構築命令の後にあれば、コメントとして扱う:

FROM ImageName
# directive=value

パーサ・ディレクティブでないコメントがあれば、以降のものはコメントとして扱う:

# About my dockerfile
FROM ImageName
# directive=value

不明なディレクティブは認識できないため、コメントとして扱う。さらに、パーサ・ディレクティブではないコメントの後にディレクティブがあったとしても、コメントとして扱う:

# unknowndirective=value # knowndirective=value

改行ではないホワイトスペースは、パーサ・ディレクティブにおいて記述することができます。 そこで、以下の各行はすべて同一のものとして扱われます。

#directive=value
# directive =value
#    directive= value
# directive = value
#      dIrEcTiVe=value

以下のパーサ・ディレクティブをサポートします:

  • escape

escape

# escape=\ (バックスラッシュ)

または

# escape=` (バッククォート)

ディレクティブ escape は、Dockerfile 内でエスケープ文字として用いる文字を設定します。 設定していない場合は、デフォルトとして `` が用いられます。

エスケープ文字は行途中での文字をエスケープするものと、行継続をエスケープするものがあります。 行継続のエスケープを使うと Dockerfile 内の命令を複数行に分けることができます。 Dockerfileescape パーサ・ディレクティブを記述していたとしても、RUN コマンドの途中でのエスケープは無効であり、行末の行継続エスケープのみ利用することができます。

Windows においてはエスケープ文字を「`」とします。 \ はディレクトリ・セパレータとなっているためです。 「`」は Windows PowerShell 上でも利用できます。

以下のような Windows 上の例を見てみます。 これはよく分からずに失敗してしまう例です。 2 行めの行末にある 2 つめの \ は、次の行への継続を表わすエスケープと解釈されます。 つまり 1 つめの \ をエスケープするものとはなりません。 同様に 3 行めの行末にある \ も、この行が正しく命令として解釈されるものであっても、行継続として扱われることになります。 結果としてこの Dockerfile の 2 行めと 3 行めは、一続きの記述行とみなされます。

FROM microsoft/nanoserver
COPY testfile.txt c:\\
RUN dir c:\

この Dockerfile を用いると以下の結果になります。

PS C:\John> docker build -t cmd .
Sending build context to Docker daemon 3.072 kB
Step 1/2 : FROM microsoft/nanoserver
 ---> 22738ff49c6d
Step 2/2 : COPY testfile.txt c:\RUN dir c:
GetFileAttributesEx c:RUN: The system cannot find the file specified.
PS C:\John>

上を解決するには COPY 命令と dir の対象において / を用います。 ただし Windows 上における普通のパス記述とは違う文法であるため混乱しやすく、さらに Windows のあらゆるコマンドがパス・セパレータとして / をサポートしているわけではないので、エラーになることもあります。

パーサ・ディレクティブ escape を利用すれば、Windows 上のファイル・パスの文法をそのままに、期待どおりに Dockerfile が動作してくれます。

# escape=`

FROM microsoft/nanoserver
COPY testfile.txt c:\
RUN dir c:\

上を処理に用いると以下のようになります。

PS C:\John> docker build -t succeeds --no-cache=true .
Sending build context to Docker daemon 3.072 kB
Step 1/3 : FROM microsoft/nanoserver
 ---> 22738ff49c6d
Step 2/3 : COPY testfile.txt c:\
 ---> 96655de338de
Removing intermediate container 4db9acbb1682
Step 3/3 : RUN dir c:\
 ---> Running in a2c157f842f5
 Volume in drive C has no label.
 Volume Serial Number is 7E6D-E0F7

 Directory of c:\

10/05/2016  05:04 PM             1,894 License.txt
10/05/2016  02:22 PM    <DIR>          Program Files
10/05/2016  02:14 PM    <DIR>          Program Files (x86)
10/28/2016  11:18 AM                62 testfile.txt
10/28/2016  11:20 AM    <DIR>          Users
10/28/2016  11:20 AM    <DIR>          Windows
           2 File(s)          1,956 bytes
           4 Dir(s)  21,259,096,064 bytes free
 ---> 01c7f3bef04f
Removing intermediate container a2c157f842f5
Successfully built 01c7f3bef04f
PS C:\John>

環境変数の置換

DockerfileENV 構文 により宣言される環境変数は、特定の命令において変数として解釈されます。 エスケープについても構文内にリテラルを含めることから、変数と同様の扱いと考えられます。

Dockerfile における環境変数の記述書式は、$variable_name あるいは ${variable_name} のいずれかが可能です。 両者は同等のものですが、ブレースを用いた記述は ${foo}_bar といった記述のように、変数名にホワイトスペースを含めないようにするために利用されます。

${variable_name} という書式は、標準的な bash の修飾書式をいくつかサポートしています。 たとえば以下のものです。

  • ${variable:-word} は、variable が設定されているとき、この結果はその値となります。 variable が設定されていないとき、word が結果となります。
  • ${variable:+word} は、variable が設定されているとき、この結果は word となります。 variable が設定されていないとき、結果は空文字となります。

どの例においても、word は文字列であれば何でもよく、さらに別の環境変数を含んでいても構いません。

変数名をエスケープすることも可能で、変数名の前に \$foo\${foo} のように \ をつけます。 こうすると、この例はそれぞれ $foo${foo} という文字列そのものとして解釈されます。

記述例 (# の後に変数解釈した結果を表示)

FROM busybox
ENV foo /bar
WORKDIR ${foo}   # WORKDIR /bar
ADD . $foo       # ADD . /bar
COPY \$foo /quux # COPY $foo /quux

環境変数は、以下に示す Dockerfile 内の命令においてサポートされます。

  • ADD
  • COPY
  • ENV
  • EXPOSE
  • LABEL
  • USER
  • WORKDIR
  • VOLUME
  • STOPSIGNAL

同様に、

  • ONBUILD (上記のサポート対象の命令と組み合わせて用いる場合)

注釈

Docker バージョン 1.4 より以前では ONBUILD 命令は環境変数をサポートしていません。 一覧にあげた命令との組み合わせで用いる場合も同様です。

環境変数の置換は、命令全体の中で個々の変数ごとに同一の値が用いられます。 これを説明するために以下の例を見ます。

ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc

この結果、defhello になります。 bye ではありません。 しかし ghibye になります。 ghi を設定している行は、 abcbye を設定している命令と同一箇所ではないからです。

.dockerignore ファイル

Docker の CLI によってコンテキストが Docker デーモンに送信される前には、コンテキストのルートディレクトリの .dockerignore というファイルが参照されます。 このファイルが存在したら、CLI はそこに記述されたパターンにマッチするようなファイルやディレクトリを除外した上で、コンテキストを扱います。 必要もないのに、巨大なファイルや取り扱い注意のファイルを不用意に送信してしまうことが避けられ、ADDCOPY を使ってイメージに間違って送信してしまうことを防ぐことができます。

CLI は .dockerignore ファイルを各行ごとに区切られた設定一覧として捉えます。 ちょうど Unix シェルにおけるファイルグロブ(glob)と同様です。 マッチング処理の都合上、コンテキストのルートは、ワーキングディレクトリとルートディレクトリの双方であるものとしてみなされます。 たとえばパターンとして /foo/barfoo/bar があったとすると、PATH 上であればサブディレクトリ foo 内、URL であればその git レポジトリ内の、いずれも bar というファイルまたはディレクトリを除外します。 その他のものについては除外対象としません。

.dockerignore ファイルの各行頭の第 1 カラムめに # があれば、その行はコメントとみなされて、CLI による解釈が行われず無視されます。

これは .dockerignore ファイルの例です:

# コメント
*/temp*
*/*/temp*
temp?

このファイルは構築時に以下の動作をします。

  • # comment … 無視されます。
  • */temp* … ルートディレクトリの直下にあるサブディレクトリ内にて、temp で始まる名称のファイルまたはディレクトリすべてを除外します。たとえば通常のファイル /somedir/temporary.txt は除外されます。ディレクトリ /somedir/temp も同様です。
  • */*/temp* … ルートから 2 階層下までのサブディレクトリ内にて、temp で始まる名称のファイルまたはディレクトリすべてを除外します。たとえば /somedir/subdir/temporary.txt は除外されます。
  • temp? … ルートディレクトリにあるファイルやディレクトリであって、temp にもう 1 文字ついた名前のものを除外します。たとえば /tempa/tempb が除外されます。

パターンマッチングには Go 言語の filepath.Match ルールが用いられています。 マッチングの前処理として、文字列前後のホワイトスペースは取り除かれ、Go 言語の filepath.Clean によって ... が除外されます。 前処理を行った後の空行は無視されます。

Docker では Go 言語の filepath.Match ルールを拡張して、特別なワイルドカード文字列 ** をサポートしています。 これは複数のディレクトリ(ゼロ個を含む)にマッチします。 たとえば **/*.go は、ファイル名が .go で終わるものであって、どのサブディレクトリにあるものであってもマッチします。 ビルドコンテキストのルートも含まれます。

行頭を感嘆符 ! で書き始めると、それは除外に対しての例外を指定するものとなります。 以下の .dockerignore はこれを用いる例です。

*.md
!README.md

マークダウンファイルがすべてコンテキストから除外されますが、README.md だけは 除外されません

! による例外ルールは、それを記述した位置によって処理に影響します。 特定のファイルが含まれるのか除外されるのかは、そのファイルがマッチする .dockerignore 内の最終の行によって決まります。 以下の例を考えてみます。

*.md
!README*.md
README-secret.md

コンテキストにあるマークダウンファイルはすべて除外されます。 例外として README ファイルは含まれることになりますが、ただし README-secret.md は除外されます。

その次の例を考えましょう。

*.md
README-secret.md
!README*.md

README ファイルはすべて含まれます。 2 行めは意味をなしていません。 なぜなら !README*.md には README-secret.md がマッチすることになり、しかも !README*.md が最後に記述されているからです。

.dockerignore ファイルを使って Dockerfile.dockerignore ファイルを除外することもできます。 除外したとしてもこの 2 つのファイルはデーモンに送信されます。 この 2 つのファイルはデーモンの処理に必要なものであるからです。 ただし ADD 命令や COPY 命令では、この 2 つのファイルはイメージにコピーされません。

除外したいファイルを指定するのではなく、含めたいファイルを指定したい場合があります。 これを実現するには、冒頭のマッチングパターンとして * を指定します。 そしてこれに続けて、例外となるパターンを ! を使って指定します。

注釈

これまでの開発経緯によりパターン . は無視されます。

FROM

FROM <image> [AS <name>]

または

FROM <image>[:<tag>] [AS <name>]

または

FROM <image>[@<digest>] [AS <name>]

FROM 命令は、イメージビルドのための処理ステージを初期化し、ベース・イメージ を設定します。後続の命令がこれに続きます。 このため、正しい DockerfileFROM 命令から始めなければなりません。 ベース・イメージは正しいものであれば何でも構いません。 簡単に取り掛かりたいときは、公開リポジトリ から イメージを取得 します。

  • 1 つの Dockerfile 内に FROM を複数記述することが可能です。 これは複数のイメージを生成するため、あるいは 1 つのビルドステージを使って依存イメージをビルドするために行います。 各 FROM 命令までのコミットによって出力される最終のイメージ ID は書き留めておいてください。 個々の FROM 命令は、それ以前の命令により作り出された状態を何も変更しません。
  • オプションとして、新たなビルドステージに対しては名前をつけることができます。 これは FROM 命令の AS name により行います。 この名前は後続の FROMCOPY --from=<name|index> 命令において利用することができ、このビルドステージにおいてビルドされたイメージを参照します。
  • tagdigest の設定はオプションです。 これを省略した場合、デフォルトである latest タグが指定されたものとして扱われます。 tag の値に合致するものがなければ、エラーが返されます。

ARG と FROM の関連について

FROM 命令では、ARG 命令によって宣言された変数すべてを参照できます。 この ARG 命令は、初出の FROM 命令よりも前に記述します。

ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-app

FROM extras:${CODE_VERSION}
CMD  /code/run-extras

FROM よりも前に宣言されている ARG は、ビルドステージ内に含まれるものではありません。 したがって FROM 以降の命令において利用することはできません。 初出の FROM よりも前に宣言された ARG の値を利用するには、ビルドステージ内において ARG 命令を、値を設定することなく利用します。

ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version

RUN

RUN には2つの形式があります。

  • RUN <command> (シェル形式、コマンドはシェル内で実行される、シェルとはデフォルトで Linux なら /bin/sh -c、Windows なら cmd /S /C
  • RUN ["executable", "param1", "param2"] (exec 形式)

RUN 命令は、現在のイメージの最上位の最新レイヤーにおいて、あらゆるコマンドを実行します。 そして処理結果を確定します。 結果が確定したイメージは、Dockerfile の次のステップにおいて利用されていきます。

RUN 命令をレイヤー上にて扱い処理確定を行うこの方法は、Docker の根本的な考え方に基づいています。 この際の処理確定は容易なものであって、イメージの処理履歴上のどの時点からでもコンテナーを復元できます。 この様子はソース管理システムに似ています。

exec 形式は、シェル文字列が置換されないようにします。 そして RUN の実行にあたっては、特定のシェル変数を含まないベースイメージを用います。

シェル形式にて用いるデフォルトのシェルを変更するには SHELL コマンドを使います。

シェル形式においては ````(バックスラッシュ)を用いて、1 つの RUN 命令を次行にわたって記述することができます。 たとえば以下のような 2 行があるとします。

RUN /bin/bash -c 'source $HOME/.bashrc ;\
echo $HOME'

上は 2 行を合わせて、以下の 1 行としたものと同じです。

RUN /bin/bash -c 'source $HOME/.bashrc ; echo $HOME'

注釈

'/bin/sh' 以外の別のシェルを利用する場合は、exec 形式を用いて、目的とするシェルを引数に与えます。 たとえば RUN ["/bin/bash", "-c", "echo hello"] とします。

注釈

exec 形式は JSON 配列として解釈されます。 したがって文字列をくくるのはダブル・クォート(")であり、シングル・クォート(')は用いてはなりません。

注釈

シェル形式とは違って exec 形式はコマンドシェルを起動しません。 これはつまり、ごく普通のシェル処理とはならないということです。 たとえば RUN [ "echo", "$HOME" ] を実行したとすると、$HOME の変数置換は行われません。 シェル処理が行われるようにしたければ、シェル形式を利用するか、あるいはシェルを直接実行するようにします。 たとえば RUN [ "sh", "-c", "echo $HOME" ] とします。 exec 形式によってシェルを直接起動した場合、シェル形式の場合でも同じですが、変数置換を行うのはシェルであって、docker ではありません。

注釈

JSON 記述においてバックスラッシュはエスケープする必要があります。 特に関係してくるのは Windows であり、Windows ではパス・セパレータにバックスラッシュを用います。 RUN ["c:\windows\system32\tasklist.exe"] という記述例は、適正な JSON 記述ではないことになるため、シェル形式として扱われ、思いどおりの動作はせずエラーとなります。 正しくは RUN ["c:\\windows\\system32\\tasklist.exe"] と記述します。

RUN 命令に対するキャッシュは、次のビルドの際、その無効化は自動的に行われません。 RUN apt-get dist-upgrade -y のような命令に対するキャッシュは、次のビルドの際にも再利用されます。 RUN 命令に対するキャッシュを無効にするためには --no-cache フラグを利用します。 たとえば docker build --no-cache とします。

より詳しい情報は Dockerfile ベスト・プラクティス・ガイド をご覧ください。

RUN 命令のキャッシュは、 ADD 命令によって無効化されます。詳細は 以下 をご覧ください。

既知の問題(RUN)

  • Issue 783 はファイル・パーミッションに関する問題を取り上げていて、ファイルシステムに AUFS を用いている場合に発生します。 たとえば rm によってファイルを削除しようとしたときに、これが発生する場合があります。

    aufs の最新バージョンを利用するシステム(つまりマウントオプション dirperm1 を設定可能なシステム)の場合、docker はレイヤーに対して dirperm1 オプションをつけてマウントすることで、この問題を自動的に解消するように試みます。 dirperm1 オプションに関する詳細は aufsman ページ を参照してください。

    dirperm1 をサポートしていないシステムの場合は、issue に示される回避方法を参照してください。

CMD

CMD には3つの形式があります。

  • CMD ["executable","param1","param2"] (exec 形式、この形式が推奨される)
  • CMD ["param1","param2"] ( ENTRYPOINT のデフォルト・パラメータとして)
  • CMD command param1 param2 (シェル形式)

Dockerfile では CMD 命令を 1 つしか記述できません。 仮に複数の CMD を記述しても、最後の CMD 命令しか処理されません。

CMD 命令の主目的は、コンテナの実行時のデフォルト処理を設定することです。 この処理設定においては、実行モジュールを含める場合と、実行モジュールを省略する場合があります。 省略する場合は ENTRYPOINT 命令を合わせて指定する必要があります。

注釈

ENTRYPOINT 命令に対するデフォルト引数を設定する目的で CMD 命令を用いる場合、CMDENTRYPOINT の両命令とも、JSON 配列形式で指定しなければなりません。

注釈

exec 形式は JSON 配列として解釈されます。 したがって文字列をくくるのはダブル・クォート(")であり、シングル・クォート(')は用いてはなりません。

注釈

シェル形式とは違って exec 形式はコマンドシェルを起動しません。 これはつまり、ごく普通のシェル処理とはならないということです。 たとえば RUN [ "echo", "$HOME" ] を実行したとすると、$HOME の変数置換は行われません。 シェル処理が行われるようにしたければ、シェル形式を利用するか、あるいはシェルを直接実行するようにします。 たとえば RUN [ "sh", "-c", "echo $HOME" ] とします。 exec 形式によってシェルを直接起動した場合、シェル形式の場合でも同じですが、変数置換を行うのはシェルであって、docker ではありません。

シェル形式または exec 形式を用いる場合、CMD 命令は、イメージが起動されたときに実行するコマンドを指定します。

シェル形式を用いる場合、<command>/bin/sh -c の中で実行されます。

FROM ubuntu
CMD echo "This is a test." | wc -

<command> をシェル実行することなく実行 したい場合は、そのコマンドを JSON 配列として表現し、またそのコマンドの実行モジュールへのフルパスを指定しなければなりません。 この配列書式は CMD において推奨される記述です。 パラメータを追加する必要がある場合は、配列内にて文字列として記述します。

FROM ubuntu
CMD ["/usr/bin/wc","--help"]

コンテナにおいて毎回同じ実行モジュールを起動させたい場合は、CMD 命令と ENTRYPOINT 命令を合わせて利用することを考えてみてください。 ENTRYPOINT を参照のこと。

docker run において引数を指定することで、CMD 命令に指定されたデフォルトを上書きすることができます。

注釈

RUNCMD を混同しないようにしてください。 RUN は実際にコマンドが実行されて、結果を確定させます。 一方 CMD はイメージビルド時には何も実行しません。 イメージに対して実行する予定のコマンドを指示するものです。

LABEL

LABEL <key>=<value> <key>=<value> <key>=<value> ...

LABEL 命令はイメージに対してメタデータを追加します。 LABEL ではキーバリューペアによる記述を行います。 値に空白などを含める場合は、クォートとバックスラッシュを用います。 これはコマンドライン処理において行うことと同じです。 以下に簡単な例を示します。

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

イメージには複数のラベルを含めることができます。 複数のラベルを指定する場合、可能であれば LABEL 命令の記述を 1 行とすることをお勧めします。 LABEL 命令 1 つからは新しいレイヤが生成されますが、多数のラベルを利用すると、非効率なイメージがビルドされてしまいます。 以下の例は、ただ 1 つのイメージ・レイヤを作るものです。

LABEL multi.label1="value1" multi.label2="value2" other="value3"

上記の例は、以下のように書くこともできます。

LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"

ラベルには FROM に指定されたイメージ内の LABEL 命令も含まれます。 ラベルのキーが既に存在していた場合、そのキーに対応する古い値は、新しい値によって上書きされます。

イメージのラベルを参照するには docker inspect コマンドを用います。

"Labels": {
    "com.example.vendor": "ACME Incorporated"
    "com.example.label-with-value": "foo",
    "version": "1.0",
    "description": "This text illustrates that label-values can span multiple lines.",
    "multi.label1": "value1",
    "multi.label2": "value2",
    "other": "value3"
},

MAINTAINER(廃止予定)

MAINTAINER <name>

MAINTAINER 命令は、ビルドされるイメージの Author フィールドを設定します。 LABEL 命令を使った方がこれよりも柔軟に対応できるため、LABEL を使うようにします。 そうすれば必要なメタデータとしてどのようにでも設定ができて、docker inspect を用いて簡単に参照することができます。 MAINTAINER フィールドに相当するラベルを作るには、以下のようにします。

LABEL maintainer="SvenDowideit@home.org.au"

こうすれば docker inspect によってラベルをすべて確認することができます。

EXPOSE

EXPOSE <port> [<port>...]

EXPOSE 命令はコンテナの実行時に、所定ネットワーク上のどのポートをリッスンするかを指定します。 EXPOSE はコンテナーのポートをホストが利用できるようにするものではありません。 利用できるようにするためには -p フラグを使ってポートの公開範囲を指定するか、 -P フラグによって expose したポートをすべて公開する必要があります。 1 つのポート番号を expose して、これを外部に向けては別の番号により公開することも可能です。

ホストシステム上にてポート転送を行う場合は、-P フラグの利用 を参照してください。 Docker のネットワークにおいては、ネットワーク内でポートを expose しなくてもネットワークを生成できる機能がサポートされています。 詳しくは ネットワーク機能の概要 を参照してください。

ENV

ENV <key> <value>
ENV <key>=<value> ...

ENV 命令は、環境変数 <key><value> という値を設定します。 Dockerfile 内の後続命令の環境において、環境変数の値は維持されます。 また、いろいろと インラインにて変更 することもできます。

ENV 命令には 2 つの書式があります。 1 つめの書式は ENV <key> <value> です。 1 つの変数に対して 1 つの値を設定します。 全体の文字列のうち、最初の空白文字以降がすべて <value> として扱われます。 そこには空白やクォートを含んでいて構いません。

2 つめの書式は ENV <key>=<value> ... です。 これは一度に複数の値を設定できる形です。 この書式では等号(=)を用いており、1 つめの書式とは異なります。 コマンドライン上の解析で行われることと同じように、クォートやバックスラッシュを使えば、値の中に空白などを含めることができます。

例:

ENV myName="John Doe" myDog=Rex\ The\ Dog \
    myCat=fluffy

そして

ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy

上の 2 つは最終的に同じ結果をイメージに書き入れます。 ただし 1 つめの書式が望ましいものです。 1 つめは単一のキャッシュ・レイヤしか生成しないからです。

ENV を用いて設定された環境変数は、そのイメージから実行されたコンテナであれば維持されます。 環境変数の参照は docker inspect を用い、値の変更は docker run --env <key>=<value> により行うことができます。

注釈

環境変数が維持されると、思わぬ副作用を引き起こすことがあります。 たとえば ENV DEBIAN_FRONTEND noninteractive という設定を行なっていると、Debian ベースのイメージにおいて apt-get を使う際には混乱を起こすかもしれません。 1 つのコマンドには 1 つの値のみを設定するには RUN <key>=<value> <command> を実行します。

ADD

ADD には 2 つの書式があります。

  • ADD <src>... <dest>
  • ADD ["<src>",... "<dest>"] (この書式はホワイトスペースを含むパスを用いる場合に必要)

ADD 命令は <src> に示されるファイル、ディレクトリ、リモートファイル URL をコピーして、イメージ内のファイルシステム上のパス <dest> にこれらを加えます。

<src> には複数のソースを指定することが可能です。 ソースとしてファイルあるいはディレクトリが指定されている場合、そのパスは生成されたソース・ディレクトリ(ビルド・コンテキスト)からの相対パスでなければなりません。

<src> にはワイルドカードを含めることができます。 その場合、マッチング処理は Go 言語の filepath.Match ルールに従って行われます。 記述例は以下のとおりです。

ADD hom* /mydir/        # "hom" で始まる全てのファイルを追加
ADD hom?.txt /mydir/    # ? は1文字だけ一致します。例: "home.txt"

<dest> は絶対パスか、あるいは WORKDIR からの相対パスにより指定します。 対象としているコンテナ内において、そのパスに対してソースがコピーされます。

ADD test relativeDir/          # "test"`WORKDIR`/relativeDir/ (相対ディレクトリ)に追加
ADD test /absoluteDir/          # "test" を /absoluteDir/ (絶対ディレクトリ)に追加

ファイルやディレクトリを追加する際に、その名前の中に( [] のような)特殊な文字が含まれている場合は、Go 言語のルールに従ってパス名をエスケープする必要があります。 これはパターン・マッチングとして扱われないようにするものです。 たとえば arr[0].txt というファイルを追加する場合は、以下のようにします。

ADD arr[[]0].txt /mydir/    # "arr[0].txt" というファイルを /mydir/ へコピー

ADD されるファイルやディレクトリの UID と GID は、すべて 0 として生成されます。

<src> にリモートファイル URL が指定された場合、コピー先のパーミッションは 600 となります。 リモートファイルの取得時に HTTP の Last-Modified ヘッダが含まれている場合は、ヘッダに書かれたタイムスタンプを利用して、コピー先ファイルの mtime を設定します。 ただし ADD によって処理されるファイルが何であっても、ファイルが変更されたかどうか、そしてキャッシュを更新するべきかどうかは mtime によって判断されるわけではありません。

注釈

Dockerfile を標準入力から生成する場合( docker build - < somefile )は、ビルド・コンテキストが存在していないことになるので、ADD 命令には URL の指定しか利用できません。 また標準入力から圧縮アーカイブを入力する場合( docker build - < archive.tar.gz )は、そのアーカイブのルートにある Dockerfile と、アーカイブ内のファイルすべてが、ビルド時のコンテキストとなります。

注釈

URL ファイルが認証によって保護されている場合は、RUN wgetRUN curl あるいは同様のツールをコンテナ内から利用する必要があります。ADD 命令は認証処理をサポートしていません。

注釈

ADD 命令の <src> の内容が変更されていた場合、その ADD 命令以降に続く命令のキャッシュはすべて無効化されます。 そこには RUN 命令に対するキャッシュの無効化も含まれます。 詳しくは Dockerfileベスト・プラクティス・ガイド を参照してください。

ADD は以下のルールに従います。

  • <src> のパス指定は、ビルド コンテキスト 内でなければならないため、たとえば ADD ../something /something といったことはできません。 docker build の最初の処理ステップでは、コンテキスト・ディレクトリ(およびそのサブディレクトリ)を Docker デーモンに送信するところから始まるためです。
  • <src> が URL 指定であって <dest> の最後にスラッシュが指定されていない場合、そのファイルを URL よりダウンロードして <dest> にコピーします。
  • <src> が URL 指定であって <dest> の最後にスラッシュが指定された場合、ファイルが指定されたものとして扱われ、URL からダウンロードして <dest>/<filename> にコピーします。 たとえば ADD http://example.com/foobar / という記述は /foobar というファイルを作ることになります。 URL には正確なパス指定が必要です。 上の記述であれば、適切なファイルが見つけ出されます。 ( http://example.com では正しく動作しません。)
  • <src> がディレクトリである場合、そのディレクトリ内の内容がすべてコピーされます。 ファイルシステムのメタデータも含まれます。

    注釈

    ディレクトリそのものはコピーされません。 コピーされるのはその中身です。

  • <src>ローカル にある tar アーカイブであって、認識できるフォーマット(gzip、bzip2、xz)である場合、1 つのディレクトリ配下に展開されます。 リモート URL の場合は展開 されません 。 ディレクトリのコピーあるいは展開の仕方は tar -x と同等です。 つまりその結果は以下の 2 つのいずれかに従います。

    1. コピー先に指定されていれば、それが存在しているかどうかに関わらず。あるいは、
    2. ソース・ツリーの内容に従って各ファイルごとに行う。衝突が発生した場合は 2. を優先する。

    注釈

    圧縮されたファイルが認識可能なフォーマットであるかどうかは、そのファイル内容に基づいて確認されます。 名前によって判断されるわけではありません。 たとえば、空のファイルの名前の末尾がたまたま .tar.gz となっていた場合、圧縮ファイルとして認識されないため、解凍に失敗したといったエラーメッセージは一切 出ることはなく 、このファイルはコピー先に向けて単純にコピーされるだけです。

  • <src> が上に示す以外のファイルであった場合、メタデータも含めて個々にコピーされます。 このとき <dest>/ で終わっていたらディレクトリとみなされるので、<src> の内容は <dest>/base(<src>) に書き込まれることになります。
  • 複数の <src> が直接指定された場合、あるいはワイルドカードを用いて指定された場合、<dest> はディレクトリとする必要があり、末尾には / をつけなければなりません。
  • <dest> の末尾にスラッシュがなかった場合、通常のファイルとみなされるため、<src> の内容は <dest> に書き込まれることになります。
  • <dest> のパス内のディレクトリが存在しなかった場合、すべて生成されます。

COPY

COPY は2つの形式があります。

  • COPY <src>... <dest>
  • COPY ["<src>",... "<dest>"] (パスにホワイトスペースを含む場合にこの書式が必要)

COPY 命令は <src> からファイルやディレクトリを新たにコピーして、コンテナ内のファイルシステムのパス <dest> に追加します。

<src> には複数のソースを指定することが可能です。 ソースとしてファイルあるいはディレクトリが指定されている場合、そのパスは生成されたソース・ディレクトリ(ビルド・コンテキスト)からの相対パスでなければなりません。

<src> にはワイルドカードを含めることができます。 その場合、マッチング処理は Go 言語の filepath.Match ルールに従って行われます。 記述例は以下のとおりです。

COPY hom* /mydir/        # "hom" で始まる全てのファイルを追加
COPY hom?.txt /mydir/    # ? は1文字だけ一致します。例: "home.txt"

<dest> は絶対パスか、あるいは WORKDIR からの相対パスにより指定します。 対象としているコンテナ内において、そのパスに対してソースがコピーされます。

COPY test relativeDir/   # "test"`WORKDIR`/relativeDir/ (相対ディレクトリ)に追加
COPY test /absoluteDir/   # "test" を /absoluteDir/ (絶対ディレクトリ)に追加

ファイルやディレクトリを追加する際に、その名前の中に( [] のような)特殊な文字が含まれている場合は、Go 言語のルールに従ってパス名をエスケープする必要があります。 これはパターン・マッチングとして扱われないようにするものです。 たとえば arr[0].txt というファイルを追加する場合は、以下のようにします。

COPY arr[[]0].txt /mydir/    # "arr[0].txt" というファイルを /mydir/ へコピー

コピーされるファイルやディレクトリの UID と GID は、すべて 0 として生成されます。

注釈

Dockerfile を標準入力から生成する場合( docker build - < somefile )は、ビルド・コンテキストが存在していないことになるので、COPY 命令は利用することができません。

オプションとして COPY にはフラグ --from=<name|index> があります。 これは実行済のビルド・ステージ( FROM .. AS <name> により生成)におけるソース・ディレクトリを設定するものです。 これがあると、ユーザーが指定したビルド・コンテキストのかわりに、設定されたディレクトリが用いられます。 このフラグは数値インデックスを指定することも可能です。 この数値インデックスは、FROM 命令から始まる実行済のビルド・ステージすべてに割り当てられている値です。 指定されたビルド・ステージがその名前では見つけられなかった場合、指定された数値によって見つけ出します。

COPY は以下のルールに従います。

  • <src> のパス指定は、ビルド コンテキスト 内でなければならないため、たとえば COPY ../something /something といったことはできません。 docker build の最初の処理ステップでは、コンテキスト・ディレクトリ(およびそのサブディレクトリ)を Docker デーモンに送信するところから始まるためです。
  • <src> がディレクトリである場合、そのディレクトリ内の内容がすべてコピーされます。 ファイルシステムのメタデータも含まれます。

    注釈

    ディレクトリそのものはコピーされません。 コピーされるのはその中身です。

  • <src> が上に示す以外のファイルであった場合、メタデータも含めて個々にコピーされます。 このとき <dest>/ で終わっていたらディレクトリとみなされるので、<src> の内容は <dest>/base(<src>) に書き込まれることになります。
  • 複数の <src> が直接指定された場合、あるいはワイルドカードを用いて指定された場合、<dest> はディレクトリとする必要があり、末尾には / をつけなければなりません。
  • <dest> の末尾にスラッシュがなかった場合、通常のファイルとみなされるため、<src> の内容が <dest> に書き込まれます。
  • <dest> のパス内のディレクトリが存在しなかった場合、すべて生成されます。

ENTRYPOINT

ENTRYPOINT には2つの形式があります。

  • ENTRYPOINT ["executable", "param1", "param2"] (exec 形式、推奨)
  • ENTRYPOINT command param1 param2 (シェル形式)

ENTRYPOINT は、コンテナを実行モジュールのようにして実行する設定を行ないます。

たとえば以下の例では、nginx をデフォルト設定で起動します。 ポートは 80 番を利用します。

docker run -i -t --rm -p 80:80 nginx

docker run <image> に対するコマンドライン引数は、exec 形式の ENTRYPOINT の指定要素の後に付け加えられます。 そして CMD において指定された引数は上書きされます。 これはつまり、引数をエントリーポイントに受け渡すことができるということです。 たとえば docker run <image> -d としたときの -d は、引数としてエントリーポイントに渡されます。 docker run --entrypoint を利用すれば ENTRYPOINT の内容を上書きすることができます。

シェル形式では CMDrun のコマンドライン引数は受け付けずに処理を行います。 ただし ENTRYPOINT/bin/sh -c のサブコマンドとして起動されるので、シグナルを送信しません。 これはつまり、実行モジュールがコンテナの PID 1 にはならず、Unix のシグナルを受信しないということです。 したがって docker stop <container> が実行されても、その実行モジュールは SIGTERM を受信しないことになります。

ENTRYPOINT 命令は複数記述されていても、最後の命令しか処理されません。

exec 形式の ENTRYPOINT 例

ENTRYPOINT の exec 形式は、デフォルト実行するコマンドおよび引数として、ほぼ変わることがないものを設定します。 そして CMD 命令の 2 つある書式のいずれでもよいので、変更が必要になりそうな内容を追加で設定します。

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

コンテナを実行すると、ただ 1 つのプロセスとして top があるのがわかります。

$ docker run -it --rm --name test  top -H
top - 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
    1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 top

さらに詳しく見るには docker exec を実行します。

$ docker exec -it test ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  2.6  0.1  19752  2352 ?        Ss+  08:24   0:00 top -b -H
root         7  0.0  0.1  15572  2164 ?        R+   08:25   0:00 ps aux

top を適切に終了させるには docker stop test を実行します。

次の Dockerfile は、Apache をフォアグラウンドで(つまり PID 1 として)実行するような ENTRYPOINT の例を示しています。

FROM debian:stable
RUN apt-get update && apt-get install -y --force-yes apache2
EXPOSE 80 443
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

1 つの実行モジュールを起動するスクリプトを書く場合、最終実行される実行モジュールが Unix シグナルを受信できるようにするには exec あるいは gosu を用います。

#!/bin/bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"

シャットダウンの際に追加でクリーンアップするようなコマンドを実行したい(他のコンテナとの通信を行ないたい)場合、あるいは複数の実行モジュールを連動して動かしている場合は、ENTRYPOINT のスクリプトが確実に Unix シグナルを受信し、これを受けて動作するようにすることが必要になるかもしれません。

#!/bin/sh
# メモ: ここで sh を用いました。したがって busybox コンテナーでも動作します。

# ここで trap を用います。サービスが停止した後に手動でクリーンアップする
# コマンドを実行するにはこれも必要となります。
# こうしておかないと、1 つのコンテナーで複数サービスを起動しなければなりません。
trap "echo TRAPed signal" HUP INT QUIT TERM

# ここからバックグラウンドでサービスを開始します
/usr/sbin/apachectl start

echo "[hit enter key to exit] or run 'docker stop <container>'"
read

# ここでサービスを停止しクリーンアップします。
echo "stopping apache"
/usr/sbin/apachectl stop

echo "exited $0"

このイメージを docker run -it --rm -p 80:80 --name test apache により実行したら、このコンテナのプロセスは docker execdocker top を使って確認することができます。 そしてこのスクリプトから Apache を停止させます。

$ docker exec -it test ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.1  0.0   4448   692 ?        Ss+  00:42   0:00 /bin/sh /run.sh 123 cmd cmd2
root        19  0.0  0.2  71304  4440 ?        Ss   00:42   0:00 /usr/sbin/apache2 -k start
www-data    20  0.2  0.2 360468  6004 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
www-data    21  0.2  0.2 360468  6000 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
root        81  0.0  0.1  15572  2140 ?        R+   00:44   0:00 ps aux
$ docker top test
PID                 USER                COMMAND
10035               root                {run.sh} /bin/sh /run.sh 123 cmd cmd2
10054               root                /usr/sbin/apache2 -k start
10055               33                  /usr/sbin/apache2 -k start
10056               33                  /usr/sbin/apache2 -k start
$ /usr/bin/time docker stop test
test
real 0m 0.27s
user 0m 0.03s
sys  0m 0.03s

注釈

--entrypoint を使うと ENTRYPOINT の設定を上書きすることができます。 ただしこの場合は、実行モジュールを exec 形式にできるだけです。 (sh -c は利用されません。)

注釈

exec 形式は JSON 配列として解釈されます。 したがって文字列をくくるのはダブルクォート(")であり、シングルクォート(')は用いてはなりません。

注釈

シェル形式とは違って exec 形式はコマンドシェルを起動しません。 これはつまり、ごく普通のシェル処理とはならないということです。 たとえば ENTRYPOINT [ "echo", "$HOME" ] を実行したとすると、$HOME の変数置換は行われません。 シェル処理が行われるようにしたければ、シェル形式を利用するか、あるいはシェルを直接実行するようにします。 たとえば ENTRYPOINT [ "sh", "-c", "echo $HOME" ] とします。 exec 形式によってシェルを直接起動した場合、シェル形式の場合でも同じですが、変数置換を行うのはシェルであって、docker ではありません。

シェル形式の ENTRYPOINT 例

ENTRYPOINT に指定した文字列は、そのまま /bin/sh -c の中で実行されます。 この形式は、シェル環境変数を置換しながらシェル処理を実行します。 そして CMDdocker run におけるコマンドライン引数は無視します。 ENTRYPOINT による実行モジュールがどれだけ実行し続けていても、確実に docker stop によりシグナル送信ができるようにするためには、忘れずに exec をつけて実行する必要があります。

FROM ubuntu
ENTRYPOINT exec top -b

上のイメージを実行すると、PID 1 のプロセスがただ 1 つだけあるのがわかります。

$ docker run -it --rm --name test top
Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
Load average: 0.08 0.03 0.05 2/98 6
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     R     3164   0%   0% top -b

きれいに終了させるには docker stop を実行します。

$ /usr/bin/time docker stop test
test
real 0m 0.20s
user 0m 0.02s
sys  0m 0.04s

仮に ENTRYPOINT の先頭に exec を記述し忘れたとします。

FROM ubuntu
ENTRYPOINT top -b
CMD --ignored-param1

そして以下のように実行したとします。 (名前をつけておいて次のステップで使います。)

$ docker run -it --name test top --ignored-param2
Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
CPU:   9% usr   2% sys   0% nic  88% idle   0% io   0% irq   0% sirq
Load average: 0.01 0.02 0.05 2/101 7
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     S     3168   0%   0% /bin/sh -c top -b cmd cmd2
    7     1 root     R     3164   0%   0% top -b

ENTRYPOINT によって指定された top の出力は PID 1 ではないことがわかります。

この後に docker stop test を実行しても、コンテナはきれいに終了しません。 stop コマンドは、タイムアウトの後に強制的に SIGKILL を送信することになるからです。

$ docker exec -it test ps aux
PID   USER     COMMAND
    1 root     /bin/sh -c top -b cmd cmd2
    7 root     top -b
    8 root     ps aux
$ /usr/bin/time docker stop test
test
real 0m 10.19s
user 0m 0.04s
sys  0m 0.03s

CMD と ENTRYPOINT の関連について

CMD 命令も ENTRYPOINT 命令も、ともにコンテナ起動時に実行するコマンドを定義するものです。 両方が動作する際に必要となるルールがいくらかあります。

  1. Dockerfile には、CMD または ENTRYPOINT のいずれかが、少なくとも 1 つ必要です。
  1. ENTRYPOINT は、コンテナを実行モジュールとして実行する際に利用します。
  1. CMD は、ENTRYPOINT のデフォルト引数を定義するため、あるいはその時点でのみコマンド実行を行うために利用します。
  1. CMD はコンテナ実行時に、別の引数によって上書きされることがあります。

以下の表は、ENTRYPOINTCMD の組み合わせに従って実行されるコマンドを示しています。

  ENTRYPOINT なし ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
CMD なし エラー。実行できない。 /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_cmd p1_cmd exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry p1_cmd p2_cmd exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

VOLUME

VOLUME ["/data"]

VOLUME 命令は指定された名前を使ってマウントポイントを生成します。 そして自ホストまたは他のコンテナからマウントされたボリュームとして、そのマウントポイントを扱います。 指定する値は JSON 配列として VOLUME ["/var/log/"] のようにするか、あるいは単純な文字列を複数与えます。 たとえば VOLUME /var/logVOLUME /var/log /var/db などです。 Docker クライアントを通じたマウントに関する情報、利用例などに関しては ボリュームを通じたディレクトリの共有 を参照してください。

docker run コマンドは、新たに生成するボリュームを初期化します。 ベースイメージ内の指定したディレクトリに、データが存在していても構いません。 たとえば以下のような Dockerfile の記述部分があったとします。

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

この Dockerfile はイメージに対する処理として、docker run により /myvol というマウントポイントを新たに生成し、そのボリュームの中に greeting ファイルをコピーします。

ボリュームの指定に関して

Dockerfile におけるボリューム設定に関しては、以下のことを覚えておいてください。

  • Windows ベースのコンテナでのボリューム: Windows ベースのコンテナを利用しているときは、コンテナ内部のボリューム先は、以下のいずれかでなければなりません。
    • 存在していないディレクトリ、または空のディレクトリ
    • C: 以下のドライブ
  • Dockerfile 内からのボリューム変更: ボリュームを宣言した後に、そのボリューム内のデータを変更する処理があったとしても、そのような変更は無視され処理されません。
  • JSON 形式: 引数リストは JSON 配列として扱われます。 したがって文字列をくくるのはダブルクォート(")であり、シングルクォート(')は用いてはなりません。
  • コンテナ実行時に宣言されるホストディレクトリ: ホストディレクトリ(マウントポイント)は、その性質からして、ホストに依存するものです。 これはイメージの可搬性を確保するためなので、設定されたホストディレクトリが、あらゆるホスト上にて利用可能になるかどうかの保証はありません。 このため、Dockerfile の内部からホストディレクトリをマウントすることはできません。 つまり VOLUME 命令は host-dir (ホストのディレクトリを指定する)パラメータをサポートしていません。 マウントポイントの指定は、コンテナを生成、実行するときに行う必要があります。

USER

USER <user>[:<group>]

または

USER <UID>[:<GID>]

USER 命令は、ユーザ名(または UID)と、オプションとしてユーザグループ(または GID)を指定します。 そしてイメージが実行されるとき、Dockerfile 内の後続の RUNCMDENTRYPOINT の各命令においてこの情報を利用します。

警告

ユーザにプライマリグループがない場合、イメージ(あるいは次の命令)は root グループとして実行されます。

WORKDIR

WORKDIR /path/to/workdir

WORKDIR 命令はワークディレクトリを設定します。 Dockerfile 内にてその後に続く RUNCMDENTRYPOINTCOPYADD の各命令において利用することができます。 WORKDIR が存在しないときは生成されます。 これはたとえ、この後にワークディレクトリが利用されていなくても生成されます。

WORKDIR 命令は Dockerfile 内にて複数利用することができます。 ディレクトリ指定に相対パスが用いられた場合、そのパスは、直前の WORKDIR 命令からの相対パスとなります。 たとえば以下のとおりです。

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

上の Dockerfile の最後の pwd コマンドは /a/b/c という出力結果を返します。

WORKDIR 命令では、その前に ENV によって設定された環境変数を解釈します。 環境変数は Dockerfile の中で明示的に設定したものだけが利用可能です。 たとえば以下のようになります。

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd

上の Dockerfile の最後の pwd コマンドは /path/$DIRNAME という出力結果を返します。

ARG

ARG <name>[=<default value>]

ARG 命令は変数を定義して、ビルド時にその値を受け渡します。 これは docker build コマンドにおいて --build-arg <varname>=<value> フラグを利用して行います。 指定したビルド引数(build argument)が Dockerfile 内において定義されていない場合は、ビルド処理時に警告メッセージが出力されます。

One or more build-args were not consumed, failing build.

Dockerfile には複数の ARG 命令を含めることもできます。 たとえば以下の Dockerfile は有効な例です。

FROM busybox
ARG user1
ARG buildno
...

警告

ビルド時の変数として、github キーや認証情報などの秘密の情報を設定することは、お勧めできません。 ビルド変数の値は、イメージを利用する他人が docker history コマンドを実行すれば容易に見ることができてしまうからです。

デフォルト値

ARG 命令にはオプションとしてデフォルト値を設定することができます。

FROM busybox
ARG user1=someuser
ARG buildno=1
...

ARG 命令にデフォルト値が設定されていて、ビルド時に値設定が行われなければ、デフォルト値が用いられます。

変数スコープ

ARG による値定義が有効になるのは、Dockerfile 内の記述行以降です。 コマンドラインなどにおいて用いられるときではありません。 たとえば以下のような Dockerfile を見てみます。

1
2
3
4
5
FROM busybox
USER ${user:-some_user}
ARG user
USER $user
...

このファイルをビルドするには以下を実行します。

$ docker build --build-arg user=what_user Dockerfile

2 行めの USERsome-user として評価されます。 これは user 変数が、直後の 3 行めにおいて定義されているからです。 そして 4 行めの USERwhat_user として評価されます。 user が定義済であって、コマンドラインから what_user という値が受け渡されたからです。 ARG 命令による定義を行うまで、その変数を利用しても空の文字列として扱われます。

ARG 命令の変数スコープは、それが定義されたビルドステージが終了するときまでです。 複数のビルドステージにおいて ARG を利用する場合は、個々に ARG 命令を指定する必要があります。

FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS

FROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS

ARG 変数の利用

ARG 命令や ENV 命令において変数を指定し、それを RUN 命令にて用いることができます。 ENV 命令を使って定義された環境変数は、ARG 命令において同名の変数が指定されていたとしても優先されます。 以下のように ENV 命令と ARG 命令を含む Dockerfile があるとします。

1
2
3
4
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER v1.0.0
RUN echo $CONT_IMG_VER

そしてこのイメージを以下のコマンドによりビルドしたとします。

$ docker build --build-arg CONT_IMG_VER=v2.0.1 Dockerfile

この例において RUN 命令は v1.0.0 という値を採用します。 コマンドラインから v2.0.1 が受け渡され ARG の値に設定されますが、それが用いられるわけではありません。 これはちょうどシェルスクリプトにおいて行われる動きに似ています。 ローカルなスコープを持つ変数は、指定された引数や環境から受け継いだ変数よりも優先されます。

上の例を利用しつつ ENV のもう 1 つ別の仕様を用いると、さらに ARGENV の組み合わせによる以下のような利用もできます。

1
2
3
4
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER

ARG 命令とは違って ENV による値はビルドイメージ内に常に保持されます。 以下のような --build-arg フラグのない docker build を見てみます。

$ docker build .

上の Dockerfile の例を用いると、CONT_IMG_VER の値はイメージ内に保持されますが、その値は v1.0.0 になります。 これは 3 行めの ENV 命令で設定されているデフォルト値です。

この例で見たように変数展開の手法では、コマンドラインから引数を受け渡すことが可能であり、ENV 命令を用いればその値を最終イメージに残すことができます。 変数展開は、特定の Dockerfile 命令 においてのみサポートされます。

定義済 ARG 変数

Docker にはあらかじめ定義された ARG 変数があります。 これは Dockerfile において ARG 命令を指定しなくても利用することができます。

  • HTTP_PROXY
  • http_proxy
  • HTTPS_PROXY
  • https_proxy
  • FTP_PROXY
  • ftp_proxy
  • NO_PROXY
  • no_proxy

これを利用する場合は、コマンドラインから以下のフラグを与えるだけです。

--build-arg <varname>=<value>

デフォルトにおいて、これらの定義済変数は docker history による出力からは除外されます。 除外する理由は、HTTP_PROXY などの各変数内にある重要な認証情報が漏洩するリスクを軽減するためです。

たとえば --build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com という引数を用いて、以下の Dockerfile をビルドするとします。

FROM ubuntu
RUN echo "Hello World"

この場合、HTTP_PROXY 変数の値は docker history から取得することはできず、キャッシュにも含まれていません。 したがって URL が変更され、プロキシサーバーも http://user:pass@proxy.sfo.example.com に変更したとしても、この後に続くビルド処理において、キャッシュ・ミスは発生しません。

この動作を取り消す必要がある場合は、以下のように Dockerfile 内に ARG 命令を加えれば実現できます。

FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"

この Dockerfile がビルドされるとき、HTTP_PROXYdocker history に保存されます。 そしてその値を変更すると、ビルドキャッシュは無効化されます。

ビルドキャッシュへの影響

ARG 変数は ENV 変数とは違って、ビルドイメージの中に保持されません。 しかし ARG 変数はビルドキャッシュへ同じような影響を及ぼします。 Dockerfile に ARG 変数が定義されていて、その値が前回のビルドとは異なった値が設定されたとします。 このとき「キャッシュ・ミス」(cache miss)が発生しますが、それは初めて利用されたときであり、定義された段階ではありません。 特に ARG 命令に続く RUN 命令は、ARG 変数の値を(環境変数として)暗に利用しますが、そこでキャッシュ・ミスが起こります。 定義済の ARG 変数は、Dockerfile 内に ARG 行がない限りは、キャッシュは行われません。

たとえば、2つの Dockerfile を考えます。

1
2
3
FROM ubuntu
ARG CONT_IMG_VER
RUN echo $CONT_IMG_VER
1
2
3
FROM ubuntu
ARG CONT_IMG_VER
RUN echo hello

コマンドラインから --build-arg CONT_IMG_VER=<value> を指定すると 2 つの例ともに、2 行めの記述ではキャッシュ・ミスが起きず、3 行めで発生します。 ARG CONT_IMG_VER は、RUN 行において CONT_IMG_VER=<value> echo hello と同等のことが実行されるので、<value> が変更されると、キャッシュ・ミスが起こるということです。

もう 1 つの例を、同じコマンドライン実行を行って利用するとします。

1
2
3
4
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER $CONT_IMG_VER
RUN echo $CONT_IMG_VER

この例においてキャッシュ・ミスは 3 行めで発生します。 これは ENV における変数値が ARG 変数を参照しており、その変数値がコマンドラインから変更されるために起きます。 この例では ENV コマンドがイメージに対して変数値を書き込むものとなります。

ENV 命令が ARG 命令の同一変数名を上書きする例を見てみます。

1
2
3
4
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER hello
RUN echo $CONT_IMG_VER

3 行めにおいてキャッシュ・ミスは発生しません。 これは CONT_IMG_VER が定数(hello)であるからです。 その結果、4 行めの RUN 命令において用いられる環境変数およびその値は、ビルドの際に変更されません。

ONBUILD

ONBUILD [INSTRUCTION]

ONBUILD 命令は、イメージに対して トリガ 命令(trigger instruction)を追加します。 トリガ命令は後々実行されるものであり、そのイメージが他のビルドにおけるベースイメージとして用いられたときに実行されます。 このトリガ命令は、後続のビルドコンテキスト内で実行されます。 後続の Dockerfile 内での FROM 命令の直後に、その命令が挿入されたかのようにして動作します。

どのようなビルド命令でも、トリガ命令として登録することができます。

この命令は、他のイメージのビルドに用いることを意図したイメージをビルドする際に利用できます。 たとえばアプリケーションやデーモンの開発環境であって、ユーザ特有の設定を行うような場合です。

たとえば、繰り返し利用できる Python アプリケーション環境イメージがあるとします。 そしてこのイメージにおいては、アプリケーションソースコードを所定のディレクトリに配置することが必要であって、さらにソースを配置した後にソースビルドを行うスクリプトを加えたいとします。 このままでは ADDRUN を単に呼び出すだけでは実現できません。 それはアプリケーションソースコードがまだわかっていないからであり、ソースコードはアプリケーション環境ごとに異なるからです。 アプリケーション開発者に向けて、ひながたとなる Dockerfile を提供して、コピーペーストした上でアプリケーションに組み入れるようにすることも考えられます。 しかしこれでは不十分であり、エラーも起こしやすくなります。 そしてアプリケーションに特有のコードが含まれることになるので、更新作業も大変になります。

これを解決するには ONBUILD を利用します。 後々実行する追加の命令を登録しておき、次のビルドステージにおいて実行させるものです。

これは次のように動作します。

  1. ONBUILD 命令があると、現在ビルドしているイメージのメタデータに対してトリガが追加されます。 この命令は現在のビルドには影響を与えません。
  2. ビルドの最後に、トリガの一覧がイメージマニフェスト内の OnBuild というキーのもとに保存されます。 この情報は docker inspect コマンドを使って確認することができます。
  3. 次のビルドにおけるベースイメージとして、このイメージを利用します。 その指定には FROM 命令を用います。 FROM 命令の処理の中で、後続ビルド処理が ONBUILD トリガを見つけると、それが登録された順に実行していきます。 トリガが 1 つでも失敗したら、FROM 命令は中断され、ビルドが失敗することになります。 すべてのトリガが成功したら FROM 命令の処理が終わり、ビルド処理がその後に続きます。
  4. トリガは、イメージが実行された後は、イメージ内から削除されます。 別の言い方をすれば、「孫」のビルドにまでは受け継がれないということです。

例として以下のようなことを追加する場合が考えられます。

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

警告

ONBUILD 命令をつなぎ合わせた命令、ONBUILD ONBUILD は実現することはできません。

警告

ONBUILD 命令は FROM 命令や MAINTAINER 命令をトリガーとすることはできません。

STOPSIGNAL

STOPSIGNAL signal

STOPSIGNAL 命令はシステムコールシグナルを設定するものであり、コンテナが終了するときに送信されます。 シグナルは負ではない整数値であり、カーネルのシステムコールテーブル内に合致するものを指定します。 たとえば 9 などです。 あるいは SIGNAME という形式のシグナル名を指定します。 たとえば SIGKILL などです。

HEALTHCHECK

HEALTHCHECK 命令は2つの形式があります:

  • HEALTHCHECK [OPTIONS] CMD command (コンテナ内部でコマンドを実行し、コンテナをヘルスチェック)
  • HEALTHCHECK NONE (ベースイメージが行うヘルスチェックを無効化)

HEALTHCHECK 命令は、コンテナが動作していることをチェックする方法を指定するものです。 この機能はたとえば、ウェブサーバのプロセスが稼動はしているものの、無限ループに陥っていて新たな接続を受け入れられない状態を検知する場合などに利用できます。

コンテナーヘルスチェックが設定されていると、通常のステータスに加えて ヘルスステータス を持つことになります。 このステータスの初期値は starting です。 ヘルスチェックが行われると、このステータスは(それまでにどんなステータスであっても) healthy となります。 ある一定数、連続してチェックに失敗すると、そのステータスは unhealty となります。

CMD より前に記述するオプションは、以下の通りです。

  • --interval=DURATION (デフォルト: 30s)
  • --timeout=DURATION (デフォルト: 30s)
  • --start-period=DURATION (デフォルト: 0s)
  • --retries=N (default: 3)

ヘルスチェックは、コンテナが起動した interval 秒後に最初に起動されます。 そして直前のヘルスチェックが完了した interval 秒後に、再び実行されます。

1 回のヘルスチェックが timeout 秒以上かかったとき、そのチェックは失敗したものとして扱われます。

コンテナに対するヘルスチェックが retries 回分、連続して失敗した場合は unhealthy とみなされます。

開始時間 (start period)は、コンテナが起動するまでに必要となる初期化時間を設定します。 この時間内にヘルスチェックの失敗が発生したとしても、 retries 数の最大を越えたかどうかの判断は行われません。 ただしこの開始時間内にヘルスチェックが 1 つでも成功したら、コンテナは起動済であるとみなされます。 そこで、それ以降にヘルスチェックが失敗したら、retries 数の最大を越えたかどうかがカウントされます。

1 つの Dockerfile に記述できる HEALTHCHECK 命令はただ 1 つです。 複数の HEALTHCHECK を記述しても、最後の命令しか効果はありません。

CMD キーワードの後ろにあるコマンドは、シェルコマンド(たとえば HEALTHCHECK CMD /bin/check-running)か、あるいは exec 形式の配列(他の Dockerfile コマンド、たとえば ENTRYPOINT にあるもの)のいずれかを指定します。

そのコマンドの終了ステータスが、コンテナのヘルスステータスを表わします。 返される値は以下となります。

  • 0: 成功(success) - コンテナは健康であり、利用が可能です。
  • 1: 不健康(unhealthy) - コンテナは正常に動作していません。
  • 2: 予約(reserved) - このコードを戻り値として利用してはなりません。

たとえば 5 分間に 1 回のチェックとして、ウェブサーバが 3 秒以内にサイトのメインページを提供できているかを確認するには、以下のようにします。

HEALTHCHECK --interval=5m --timeout=3s \
  CMD curl -f http://localhost/ || exit 1

ヘルスチェックにが失敗しても、それをデバッグしやすくするために、そのコマンドが標準出力あるいは標準エラー出力へ書き込んだ文字列(UTF-8 エンコーディング)は、すべてヘルスステータス内に保存されます。 docker inspect を使えば、すべて確認することができます。 ただしその出力は切り詰められます(現時点においては最初の 4096 バイト分のみを出力します)。

コンテナのヘルスステータスが変更されると、health_status イベントが生成されて、新たなヘルスステータスになります。

HEALTHCHECK 機能は Docker 1.12 で追加されました。

SHELL

SHELL ["executable", "parameters"]

SHELL 命令は、各種コマンドのシェル形式において用いられるデフォルトのシェルを、上書き設定するために利用します。 デフォルトのシェルは Linux 上では ["/bin/sh", "-c"]、Windows 上では ["cmd", "/S", "/C"] です。 SHELL 命令は Dockerfile 内において JSON 形式で記述しなければなりません。

SHELL 命令は特に Windows 上において利用されます。 Windows には主に 2 つのネイティブなシェル、つまり cmdpowershell があり、両者はかなり異なります。 しかも sh のような、さらに別のシェルも利用することができます。

SHELL 命令は、何度でも記述できます。 個々の SHELL 命令は、それより前の SHELL 命令の値を上書きし、それ以降の命令に効果を及ぼします。 たとえば以下のとおりです。

FROM microsoft/windowsservercore

# 以下のように実行: cmd /S /C echo default
RUN echo default

# 以下のように実行: cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default

# 以下のように実行: powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello

# 以下のように実行: cmd /S /C echo hello
SHELL ["cmd", "/S", "/C"]
RUN echo hello

Dockerfile において RUNCMDENTRYPOINT の各コマンドをシェル形式で記述した際には、SHELL 命令の設定による影響が及びます。

以下に示す例は、Windows 上において見られる普通の実行パターンですが、SHELL 命令を使って簡単に実現することができます。

...
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
...

Docker によって実行されるコマンドは以下となります。

cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"

これは効率的ではなく、そこには 2 つの理由があります。 1 つめは、コマンドプロセッサー cmd.exe(つまりはシェル)が不要に呼び出されているからです。 2 つめは、シェル形式の RUN 命令において、常に powershell -command を各コマンドの頭につけて実行しなければならないからです。

これを効率化するには、2 つあるメカニズムの 1 つを取り入れることです。 1 つは、RUN コマンドの JSON 形式を使って、以下のようにします。

...
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
...

JSON 形式を使えば、あいまいさはなくなり、不要な cmd.exe を使うこともなくなります。 しかしダブルクォートやエスケープを行うことも必要となり、より多くを記述することにもなります。 もう 1 つの方法は SHELL 命令とシェル形式を使って、Windows ユーザーにとって、より自然な文法で実現するやり方です。 特にパーサーディレクティブ escape を組み合わせて実現します。

# escape=`

FROM microsoft/nanoserver
SHELL ["powershell","-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'

これは以下のようになります。

PS E:\docker\build\shell> docker build -t shell .
Sending build context to Docker daemon 4.096 kB
Step 1/5 : FROM microsoft/nanoserver
 ---> 22738ff49c6d
Step 2/5 : SHELL powershell -command
 ---> Running in 6fcdb6855ae2
 ---> 6331462d4300
Removing intermediate container 6fcdb6855ae2
Step 3/5 : RUN New-Item -ItemType Directory C:\Example
 ---> Running in d0eef8386e97


    Directory: C:\


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       10/28/2016  11:26 AM                Example


 ---> 3f2fbf1395d9
Removing intermediate container d0eef8386e97
Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\
 ---> a955b2621c31
Removing intermediate container b825593d39fc
Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world'
 ---> Running in be6d8e63fe75
hello world
 ---> 8e559e9bf424
Removing intermediate container be6d8e63fe75
Successfully built 8e559e9bf424
PS E:\docker\build\shell>

SHELL 命令はまた、シェルの動作を変更する際にも利用することができます。 たとえば Windows 上において SHELL cmd /S /C /V:ON|OFF を実行すると、遅延環境変数の展開方法を変更することができます。

SHELL 命令は Linux において、zshcshtcsh などのシェルが必要となる場合にも利用することができます。

SHELL 機能は Docker 1.12 で追加されました。

Dockerfile の記述例

以下では Dockerfile の文法例をいくつか示します。 より実践的なところに興味がある場合は Docker 化のサンプル を参照してください。

# Nginx
#
# VERSION               0.0.1

FROM      ubuntu
MAINTAINER Victor Vieux <victor@docker.com>

LABEL Description="This image is used to start the foobar executable" Vendor="ACME Products" Version="1.0"
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
# Firefox over VNC
#
# VERSION               0.3

FROM ubuntu

# 「フェイク」(偽)のディスプレイ用の vnc, xvfb と firefox をインストール
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir ~/.vnc
# パスワードをセットアップ
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# firefox の自動起動(ベストな方法ではありませんが、動きます)
RUN bash -c 'echo "firefox" >> /.bashrc'

EXPOSE 5900
CMD    ["x11vnc", "-forever", "-usepw", "-create"]
# 複数のイメージ例
#
# VERSION               0.1

FROM ubuntu
RUN echo foo > bar
# 「===> 907ad6c2736f」 のような出力があります

FROM ubuntu
RUN echo moo > oink
# 「===> 695d7793cbe4」 のような出力があります

# You᾿ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
# /oink.
# これで2つのイメージができました。
# /bar がある 907ad6c2736f と、/oink がある 695d7793cbe4 です