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>` を参照してください。
慣例として Dockerfile
は Dockerfile
と命名されています。
またこのファイルはコンテキストディレクトリのトップに置かれます。
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
内の命令を複数行に分けることができます。
Dockerfile
に escape
パーサ・ディレクティブを記述していたとしても、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>
環境変数の置換¶
Dockerfile
の ENV 構文 により宣言される環境変数は、特定の命令において変数として解釈されます。
エスケープについても構文内にリテラルを含めることから、変数と同様の扱いと考えられます。
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
この結果、def
は hello
になります。
bye
ではありません。
しかし ghi
は bye
になります。
ghi
を設定している行は、 abc
に bye
を設定している命令と同一箇所ではないからです。
.dockerignore ファイル¶
Docker の CLI によってコンテキストが Docker デーモンに送信される前には、コンテキストのルートディレクトリの .dockerignore
というファイルが参照されます。
このファイルが存在したら、CLI はそこに記述されたパターンにマッチするようなファイルやディレクトリを除外した上で、コンテキストを扱います。
必要もないのに、巨大なファイルや取り扱い注意のファイルを不用意に送信してしまうことが避けられ、ADD
や COPY
を使ってイメージに間違って送信してしまうことを防ぐことができます。
CLI は .dockerignore
ファイルを各行ごとに区切られた設定一覧として捉えます。
ちょうど Unix シェルにおけるファイルグロブ(glob)と同様です。
マッチング処理の都合上、コンテキストのルートは、ワーキングディレクトリとルートディレクトリの双方であるものとしてみなされます。
たとえばパターンとして /foo/bar
と foo/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
命令は、イメージビルドのための処理ステージを初期化し、ベース・イメージ を設定します。後続の命令がこれに続きます。
このため、正しい Dockerfile
は FROM
命令から始めなければなりません。
ベース・イメージは正しいものであれば何でも構いません。
簡単に取り掛かりたいときは、公開リポジトリ から イメージを取得 します。
Dockerfile
内にてARG
は、FROM
よりも前に記述できる唯一の命令です。 ARG と FROM の関連について を参照してください。
- 1 つの
Dockerfile
内にFROM
を複数記述することが可能です。 これは複数のイメージを生成するため、あるいは 1 つのビルドステージを使って依存イメージをビルドするために行います。 各FROM
命令までのコミットによって出力される最終のイメージ ID は書き留めておいてください。 個々のFROM
命令は、それ以前の命令により作り出された状態を何も変更しません。
- オプションとして、新たなビルドステージに対しては名前をつけることができます。
これは
FROM
命令のAS name
により行います。 この名前は後続のFROM
やCOPY --from=<name|index>
命令において利用することができ、このビルドステージにおいてビルドされたイメージを参照します。
tag
とdigest
の設定はオプションです。 これを省略した場合、デフォルトである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
オプションに関する詳細はaufs
の man ページ を参照してください。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
命令を用いる場合、CMD
と ENTRYPOINT
の両命令とも、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
命令に指定されたデフォルトを上書きすることができます。
注釈
RUN
と CMD
を混同しないようにしてください。
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 wget
や RUN 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 つのいずれかに従います。- コピー先に指定されていれば、それが存在しているかどうかに関わらず。あるいは、
- ソース・ツリーの内容に従って各ファイルごとに行う。衝突が発生した場合は 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
の内容を上書きすることができます。
シェル形式では CMD
や run
のコマンドライン引数は受け付けずに処理を行います。
ただし 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 exec
や docker 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
の中で実行されます。
この形式は、シェル環境変数を置換しながらシェル処理を実行します。
そして CMD
や docker 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
命令も、ともにコンテナ起動時に実行するコマンドを定義するものです。
両方が動作する際に必要となるルールがいくらかあります。
- Dockerfile には、
CMD
またはENTRYPOINT
のいずれかが、少なくとも 1 つ必要です。
ENTRYPOINT
は、コンテナを実行モジュールとして実行する際に利用します。
CMD
は、ENTRYPOINT
のデフォルト引数を定義するため、あるいはその時点でのみコマンド実行を行うために利用します。
CMD
はコンテナ実行時に、別の引数によって上書きされることがあります。
以下の表は、ENTRYPOINT
と CMD
の組み合わせに従って実行されるコマンドを示しています。
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/log
や VOLUME /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
内の後続の RUN
、CMD
、ENTRYPOINT
の各命令においてこの情報を利用します。
警告
ユーザにプライマリグループがない場合、イメージ(あるいは次の命令)は root
グループとして実行されます。
WORKDIR¶
WORKDIR /path/to/workdir
WORKDIR
命令はワークディレクトリを設定します。
Dockerfile
内にてその後に続く RUN
、CMD
、ENTRYPOINT
、COPY
、ADD
の各命令において利用することができます。
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 行めの USER
が some-user
として評価されます。
これは user
変数が、直後の 3 行めにおいて定義されているからです。
そして 4 行めの USER
は what_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 つ別の仕様を用いると、さらに ARG
と ENV
の組み合わせによる以下のような利用もできます。
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_PROXY
は docker 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 アプリケーション環境イメージがあるとします。
そしてこのイメージにおいては、アプリケーションソースコードを所定のディレクトリに配置することが必要であって、さらにソースを配置した後にソースビルドを行うスクリプトを加えたいとします。
このままでは ADD
と RUN
を単に呼び出すだけでは実現できません。
それはアプリケーションソースコードがまだわかっていないからであり、ソースコードはアプリケーション環境ごとに異なるからです。
アプリケーション開発者に向けて、ひながたとなる Dockerfile
を提供して、コピーペーストした上でアプリケーションに組み入れるようにすることも考えられます。
しかしこれでは不十分であり、エラーも起こしやすくなります。
そしてアプリケーションに特有のコードが含まれることになるので、更新作業も大変になります。
これを解決するには ONBUILD
を利用します。
後々実行する追加の命令を登録しておき、次のビルドステージにおいて実行させるものです。
これは次のように動作します。
ONBUILD
命令があると、現在ビルドしているイメージのメタデータに対してトリガが追加されます。 この命令は現在のビルドには影響を与えません。- ビルドの最後に、トリガの一覧がイメージマニフェスト内の
OnBuild
というキーのもとに保存されます。 この情報はdocker inspect
コマンドを使って確認することができます。 - 次のビルドにおけるベースイメージとして、このイメージを利用します。
その指定には
FROM
命令を用います。FROM
命令の処理の中で、後続ビルド処理がONBUILD
トリガを見つけると、それが登録された順に実行していきます。 トリガが 1 つでも失敗したら、FROM
命令は中断され、ビルドが失敗することになります。 すべてのトリガが成功したらFROM
命令の処理が終わり、ビルド処理がその後に続きます。 - トリガは、イメージが実行された後は、イメージ内から削除されます。 別の言い方をすれば、「孫」のビルドにまでは受け継がれないということです。
例として以下のようなことを追加する場合が考えられます。
[...]
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 つのネイティブなシェル、つまり cmd
と powershell
があり、両者はかなり異なります。
しかも 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 において RUN
、CMD
、ENTRYPOINT
の各コマンドをシェル形式で記述した際には、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 において、zsh
、csh
、tcsh
などのシェルが必要となる場合にも利用することができます。
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 です
参考
- Dockerfile reference
- https://docs.docker.com/engine/reference/builder/