Dockerfile リファレンス

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

ここでは 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 と命名されています。 またこのファイルはコンテキストディレクトリのトップに置かれます。dockerbuild-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 デーモンは、送信されたコンテキスト内容を自動的にクリアします。

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

Docker は可能な限り中間イメージ(キャッシュ)を再利用しようとします。 これは dockerbuild 処理を速くするためです。 その場合は、端末画面に Usingcache というメッセージが出力されます。 (詳細については 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 \&/'&&echowait)| sh ---> Using cache ---> 7ea8aef582cc
Successfully built 7ea8aef582cc

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

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

記述書式

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

# CommentINSTRUCTION arguments

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

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

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

# CommentRUNecho'we are running some # of cool things'

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

パーサ・ディレクティブ

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

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

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

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

行の継続は無効:

# direc \tive=value

二度出現するため無効:

# directive=value1# directive=value2FROMImageName

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

FROMImageName# directive=value

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

# About my dockerfileFROMImageName# 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>dockerbuild-tcmd.SendingbuildcontexttoDockerdaemon3.072kBStep1/2:FROMmicrosoft/nanoserver--->22738ff49c6dStep2/2:COPY testfile.txtc:\RUNdir c:GetFileAttributesExc:RUN:Thesystemcannotfindthefilespecified.PS C:\John>

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

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

# escape=`
FROM microsoft/nanoserver
COPY testfile.txt c:\
RUN dir c:\

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

PS C:\John>dockerbuild-tsucceeds--no-cache=true.SendingbuildcontexttoDockerdaemon3.072kBStep1/3:FROMmicrosoft/nanoserver--->22738ff49c6dStep2/3:COPY testfile.txtc:\--->96655de338deRemovingintermediatecontainer4db9acbb1682Step3/3:RUNdir c:\--->Runningina2c157f842f5VolumeindriveChasnolabel.VolumeSerialNumberis7E6D-E0F7Directoryofc:\10/05/201605:04PM1,894License.txt10/05/201602:22PM<DIR>ProgramFiles10/05/201602:14PM<DIR>ProgramFiles(x86)10/28/201611:18AM62testfile.txt10/28/201611:20AM<DIR>Users10/28/201611:20AM<DIR>Windows2File(s)1,956bytes4Dir(s)21,259,096,064bytesfree--->01c7f3bef04fRemovingintermediatecontainera2c157f842f5Successfullybuilt01c7f3bef04fPS 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} という文字列そのものとして解釈されます。

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

FROMbusyboxENV foo /barWORKDIR ${foo} # WORKDIR /barADD . $foo # ADD . /barCOPY\$foo /quux # COPY $foo /quux

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

  • ADD

  • COPY

  • ENV

  • EXPOSE

  • LABEL

  • USER

  • WORKDIR

  • VOLUME

  • STOPSIGNAL

同様に、

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

注釈

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

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

ENVabc=helloENVabc=bye def=$abcENVghi=$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 で始まる名称のファイルまたはディレクトリすべてを除外します。たとえば通常のファイル /somedir/temporary.txt は除外されます。ディレクトリ /somedir/temp も同様です。

  • **.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 命令の ASname により行います。 この名前は後続の FROMCOPY--from=<name|index> 命令において利用することができ、このビルドステージにおいてビルドされたイメージを参照します。

    • tagdigest の設定はオプションです。 これを省略した場合、デフォルトである latest タグが指定されたものとして扱われます。tag の値に合致するものがなければ、エラーが返されます。

    ARG と FROM の関連について

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

    ARGCODE_VERSION=latestFROMbase:${CODE_VERSION}CMD /code/run-appFROMextras:${CODE_VERSION}CMD /code/run-extras

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

    ARGVERSION=latestFROMbusybox:$VERSIONARG VERSIONRUNecho$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","echohello"] とします。

    注釈

    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 命令に対するキャッシュは、次のビルドの際、その無効化は自動的に行われません。RUNapt-getdist-upgrade-y のような命令に対するキャッシュは、次のビルドの際にも再利用されます。RUN 命令に対するキャッシュを無効にするためには --no-cache フラグを利用します。 たとえば dockerbuild--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 のデフォルト・パラメータとして)

    • CMDcommandparam1param2 (シェル形式)

    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 の中で実行されます。

    FROMubuntuCMDecho"This is a test."| wc -

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

    FROMubuntuCMD["/usr/bin/wc","--help"]

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

    dockerrun において引数を指定することで、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"LABELversion="1.0"LABELdescription="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 命令も含まれます。 ラベルのキーが既に存在していた場合、そのキーに対応する古い値は、新しい値によって上書きされます。

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

    "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 を使うようにします。 そうすれば必要なメタデータとしてどのようにでも設定ができて、dockerinspect を用いて簡単に参照することができます。MAINTAINER フィールドに相当するラベルを作るには、以下のようにします。

    LABELmaintainer="SvenDowideit@home.org.au"

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

    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 つめの書式とは異なります。 コマンドライン上の解析で行われることと同じように、クォートやバックスラッシュを使えば、値の中に空白などを含めることができます。

    例:

    ENVmyName="John Doe"myDog=Rex\ The\ Dog \myCat=fluffy

    そして

    ENV myName John DoeENV myDog Rex The DogENV myCat fluffy

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

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

    注釈

    環境変数が維持されると、思わぬ副作用を引き起こすことがあります。 たとえば ENVDEBIAN_FRONTENDnoninteractive という設定を行なっていると、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 からの相対パスにより指定します。 対象としているコンテナ内において、そのパスに対してソースがコピーされます。

    ADDtest relativeDir/ # "test"`WORKDIR`/relativeDir/ (相対ディレクトリ)に追加ADDtest /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 を標準入力から生成する場合( dockerbuild-<somefile )は、ビルド・コンテキストが存在していないことになるので、ADD 命令には URL の指定しか利用できません。 また標準入力から圧縮アーカイブを入力する場合( dockerbuild-<archive.tar.gz )は、そのアーカイブのルートにある Dockerfile と、アーカイブ内のファイルすべてが、ビルド時のコンテキストとなります。

    注釈

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

    注釈

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

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

    • <src> のパス指定は、ビルド コンテキスト 内でなければならないため、たとえば ADD../something/something といったことはできません。dockerbuild の最初の処理ステップでは、コンテキスト・ディレクトリ(およびそのサブディレクトリ)を Docker デーモンに送信するところから始まるためです。

    • <src> が URL 指定であって <dest> の最後にスラッシュが指定されていない場合、そのファイルを URL よりダウンロードして <dest> にコピーします。

    • <src> が URL 指定であって <dest> の最後にスラッシュが指定された場合、ファイルが指定されたものとして扱われ、URL からダウンロードして <dest>/<filename> にコピーします。 たとえば ADDhttp://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 からの相対パスにより指定します。 対象としているコンテナ内において、そのパスに対してソースがコピーされます。

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

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

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

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

    注釈

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

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

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

    • <src> のパス指定は、ビルド コンテキスト 内でなければならないため、たとえば COPY../something/something といったことはできません。dockerbuild の最初の処理ステップでは、コンテキスト・ディレクトリ(およびそのサブディレクトリ)を Docker デーモンに送信するところから始まるためです。

    • <src> がディレクトリである場合、そのディレクトリ内の内容がすべてコピーされます。 ファイルシステムのメタデータも含まれます。

      注釈

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

    • <src> が上に示す以外のファイルであった場合、メタデータも含めて個々にコピーされます。 このとき <dest>/ で終わっていたらディレクトリとみなされるので、<src> の内容は <dest>/base(<src>) に書き込まれることになります。

    • 複数の <src> が直接指定された場合、あるいはワイルドカードを用いて指定された場合、<dest> はディレクトリとする必要があり、末尾には / をつけなければなりません。

    • <dest> の末尾にスラッシュがなかった場合、通常のファイルとみなされるため、<src> の内容が <dest> に書き込まれます。

    • <dest> のパス内のディレクトリが存在しなかった場合、すべて生成されます。

    ENTRYPOINT

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

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

    • ENTRYPOINTcommandparam1param2 (シェル形式)

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

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

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

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

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

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

    exec 形式の ENTRYPOINT 例

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

    FROMubuntuENTRYPOINT["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 2001974423362080 R 0.0 0.1 0:00.04 top

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

    $ docker exec -it test ps aux
    USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
    root 12.6 0.1 197522352 ? Ss+ 08:24 0:00 top -b -H
    root 70.0 0.1 155722164 ? R+ 08:25 0:00 ps aux

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

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

    FROMdebian:stableRUN apt-get update && apt-get install -y --force-yes apache2EXPOSE 80 443VOLUME["/var/www","/var/log/apache2","/etc/apache2"]ENTRYPOINT["/usr/sbin/apache2ctl","-D","FOREGROUND"]

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

    #!/bin/bashset -eif["$1"='postgres'];then chown -R postgres "$PGDATA"if[ -z "$(ls -A "$PGDATA")"];then gosu postgres initdb fiexec gosu postgres "$@"fiexec"$@"

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

    #!/bin/sh# メモ: ここで sh を用いました。したがって busybox コンテナーでも動作します。# ここで trap を用います。サービスが停止した後に手動でクリーンアップする# コマンドを実行するにはこれも必要となります。# こうしておかないと、1 つのコンテナーで複数サービスを起動しなければなりません。trap"echo TRAPed signal" HUP INT QUIT TERM# ここからバックグラウンドでサービスを開始します/usr/sbin/apachectl startecho"[hit enter key to exit] or run 'docker stop <container>'"read# ここでサービスを停止しクリーンアップします。echo"stopping apache"/usr/sbin/apachectl stopecho"exited $0"

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

    $ docker exec -it test ps aux
    USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
    root 10.1 0.0 4448692 ? Ss+ 00:42 0:00 /bin/sh /run.sh 123 cmd cmd2
    root 190.0 0.2 713044440 ? Ss 00:42 0:00 /usr/sbin/apache2 -k start
    www-data 200.2 0.2 3604686004 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start
    www-data 210.2 0.2 3604686000 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start
    root 810.0 0.1 155722140 ? R+ 00:44 0:00 ps aux
    $ docker top testPID USER COMMAND10035 root {run.sh} /bin/sh /run.sh 123 cmd cmd210054 root /usr/sbin/apache2 -k start1005533 /usr/sbin/apache2 -k start1005633 /usr/sbin/apache2 -k start
    $ /usr/bin/time docker stop testtestreal 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 の中で実行されます。 この形式は、シェル環境変数を置換しながらシェル処理を実行します。 そして CMDdockerrun におけるコマンドライン引数は無視します。ENTRYPOINT による実行モジュールがどれだけ実行し続けていても、確実に dockerstop によりシグナル送信ができるようにするためには、忘れずに exec をつけて実行する必要があります。

    FROMubuntuENTRYPOINTexec top -b

    上のイメージを実行すると、PID1 のプロセスがただ 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 10 root R 31640% 0% top -b

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

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

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

    FROMubuntuENTRYPOINT top -bCMD --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 10 root S 31680% 0% /bin/sh -c top -b cmd cmd2 71 root R 31640% 0% top -b

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

    この後に dockerstoptest を実行しても、コンテナはきれいに終了しません。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 testtestreal 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 クライアントを通じたマウントに関する情報、利用例などに関しては ボリュームを通じたディレクトリの共有 を参照してください。

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

    FROMubuntuRUN mkdir /myvolRUNecho"hello world" > /myvol/greetingVOLUME /myvol

    この Dockerfile はイメージに対する処理として、dockerrun により /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 /aWORKDIR bWORKDIR cRUN pwd

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

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

    ENV DIRPATH /pathWORKDIR $DIRPATH/$DIRNAMERUN pwd

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

    ARG

    ARG <name>[=<default value>]

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

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

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

    FROMbusyboxARG user1ARG buildno
    ...

    警告

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

    デフォルト値

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

    FROMbusyboxARGuser1=someuserARGbuildno=1...

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

    変数スコープ

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

    1FROMbusybox2USER ${user:-some_user}3ARG user4USER $user5...

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

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

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

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

    FROMbusyboxARG SETTINGSRUN ./run/setup $SETTINGSFROMbusyboxARG SETTINGSRUN ./run/other $SETTINGS

    ARG 変数の利用

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

    1FROMubuntu2ARG CONT_IMG_VER3ENV CONT_IMG_VER v1.0.04RUNecho$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 の組み合わせによる以下のような利用もできます。

    1FROMubuntu2ARG CONT_IMG_VER3ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}4RUNecho$CONT_IMG_VER

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

    $ 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>

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

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

    FROMubuntuRUNecho"Hello World"

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

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

    FROMubuntuARG HTTP_PROXYRUNecho"Hello World"

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

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

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

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

    1FROMubuntu2ARG CONT_IMG_VER3RUNecho$CONT_IMG_VER
    1FROMubuntu2ARG CONT_IMG_VER3RUNecho hello

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

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

    1FROMubuntu2ARG CONT_IMG_VER3ENV CONT_IMG_VER $CONT_IMG_VER4RUNecho$CONT_IMG_VER

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

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

    1FROMubuntu2ARG CONT_IMG_VER3ENV CONT_IMG_VER hello4RUNecho$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 というキーのもとに保存されます。 この情報は dockerinspect コマンドを使って確認することができます。

    3. 次のビルドにおけるベースイメージとして、このイメージを利用します。 その指定には FROM 命令を用います。FROM 命令の処理の中で、後続ビルド処理が ONBUILD トリガを見つけると、それが登録された順に実行していきます。 トリガが 1 つでも失敗したら、FROM 命令は中断され、ビルドが失敗することになります。 すべてのトリガが成功したら FROM 命令の処理が終わり、ビルド処理がその後に続きます。

    4. トリガは、イメージが実行された後は、イメージ内から削除されます。 別の言い方をすれば、「孫」のビルドにまでは受け継がれないということです。

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

    [...]ONBUILDADD . /app/srcONBUILDRUN /usr/local/bin/python-build --dir /app/src[...]

    警告

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

    警告

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

    STOPSIGNAL

    STOPSIGNAL signal

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

    HEALTHCHECK

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

    • HEALTHCHECK[OPTIONS]CMDcommand (コンテナ内部でコマンドを実行し、コンテナをヘルスチェック)

    • HEALTHCHECKNONE (ベースイメージが行うヘルスチェックを無効化)

    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 キーワードの後ろにあるコマンドは、シェルコマンド(たとえば HEALTHCHECKCMD/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/ ||exit1

    ヘルスチェックにが失敗しても、それをデバッグしやすくするために、そのコマンドが標準出力あるいは標準エラー出力へ書き込んだ文字列(UTF-8 エンコーディング)は、すべてヘルスステータス内に保存されます。dockerinspect を使えば、すべて確認することができます。 ただしその出力は切り詰められます(現時点においては最初の 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 命令の値を上書きし、それ以降の命令に効果を及ぼします。 たとえば以下のとおりです。

    FROMmicrosoft/windowsservercore# 以下のように実行: cmd /S /C echo defaultRUNecho default# 以下のように実行: cmd /S /C powershell -command Write-Host defaultRUN powershell -command Write-Host default# 以下のように実行: powershell -command Write-Host helloSHELL["powershell","-command"]RUN Write-Host hello# 以下のように実行: cmd /S /C echo helloSHELL["cmd","/S","/C"]RUNecho 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=`FROMmicrosoft/nanoserverSHELL["powershell","-command"]RUN New-Item -ItemType Directory C:\ExampleADD 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 上において SHELLcmd/S/C/V:ON|OFF を実行すると、遅延環境変数の展開方法を変更することができます。

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

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

    Dockerfile の記述例

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

    # Nginx## VERSION 0.0.1FROMubuntuMAINTAINER Victor Vieux <victor@docker.com>LABELDescription="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.3FROMubuntu# 「フェイク」(偽)のディスプレイ用の vnc, xvfb と firefox をインストールRUN apt-get update && apt-get install -y x11vnc xvfb firefoxRUN mkdir ~/.vnc# パスワードをセットアップRUN x11vnc -storepasswd 1234 ~/.vnc/passwd# firefox の自動起動(ベストな方法ではありませんが、動きます)RUN bash -c 'echo "firefox" >> /.bashrc'EXPOSE 5900CMD["x11vnc","-forever","-usepw","-create"]
    # 複数のイメージ例## VERSION 0.1FROMubuntuRUNecho foo > bar# 「===> 907ad6c2736f」 のような出力がありますFROMubuntuRUNecho moo > oink# 「===> 695d7793cbe4」 のような出力があります# You᾿ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with# /oink.# これで2つのイメージができました。# /bar がある 907ad6c2736f と、/oink がある 695d7793cbe4 です