Dockerfile リファレンス¶
Docker は Dockerfile
から命令を読み込み、自動的にイメージを構築できます。 Dockerfile
はテキスト形式のドキュメントであり、コマンドライン上でイメージを作り上げる命令を全て記述します。ユーザは docker build
を使い、複数のコマンド行の命令を順次実行し、イメージを自動構築します。
このページでは Dockerfile
内で利用可能な命令を説明します。ページを読み終えたら、より便利に使うための Dockerfile
の ベスト・プラクティス をご覧ください。
使い方¶
docker build
コマンドは Dockerfile
と コンテクスト(context;イメージに含まれる「内容」の意味) に従ってイメージを構築します。構築用コンテクストとは、ファイルを示す PATH
や URL
の場所です。 PATH
はローカルのファイルシステム上のディレクトリです。 URL
は Git リポジトリの場所です。
コンテクストの処理は再帰的です。そのため、 PATH
にはサブディレクトリを含みます。また URL
であればリポジトリと、そのサブモジュールも含みます。単に build コマンドを実行すると、現在のディレクトリをコンテクストとして使います。
$ docker build .
Sending build context to Docker daemon 6.51 MB
...
構築を処理するのは Docker デーモンであり、 CLI ではありません。まずはじめの構築プロセスは、対象のコンテクスト(再帰的)をデーモンに送信することです。多くの場合、空のディレクトリをコンテクストとして使いますので、Dockerfile をそのディレクトリ設置できます。Dockerfile の構築に必要なファイルのみを(ディレクトリに)追加します。
警告
PATH
として自分のルート・ディレクトリ /
を使わないでください。これは、自分のハードディスクに含まれる内容を、Docker デーモンに転送しようとするためです。
Dockerfile
に記述した COPY
命令などで使うファイルを指定を参照し、コンテクスト(内容物の意味)を構築します。構築パフォーマンスを向上するためには、 .dockerignore
ファイルにファイルやディレクトリを追加し、コンテクスト・ディレクトリから除外できます。より詳しい情報は、 .dockerignore ファイルの作成 をご覧ください。
伝統的に Dockerfile
は、Dockerfile
とコンテクストがあるルートの場所を示します。 docker build
時に -f
フラグを使えば、システム上のどこに Dockerfile があるか指定できます。
$ docker build -f /path/to/a/Dockerfile .
新しいイメージの構築に成功するときは、新しいイメージにリポジトリとタグを指定できます。
$ docker build -t shykes/myapp .
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 0 : FROM alpine:3.2
---> 31f630c65071
Step 1 : MAINTAINER SvenDowideit@home.org.au
---> Using cache
---> 2a1c91448f5f
Step 2 : RUN apk update && apk add socat && rm -r /var/cache/
---> Using cache
---> 21ed6e7fbb73
Step 3 : 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
構築が終わったら、レジストリにリポジトリを送信 する準備が整いました。
書式¶
ここでは Dockerfile
の書式を説明します。
# コメント
命令 引数
命令(instruction)は大文字と小文字を区別しません。しかし引数(arguments)を簡単に見分けられるよう、大文字にするのが便利です。
Docker は Dockerfile
の命令を順番に実行します。イメージ構築にあたり ベース・イメージ を指定するため、 1行目の命令は「FROM」であるべき です。
Docker は #
で 始まる 行をコメントとみなします。 #
マークは行における移行の文字をコメントとみなします。コメントは次のような書き方ができます。
# コメント
RUN echo '何か良いものを # で実行しています'
ここでは、 Dockerfile
でイメージ構築時に利用可能な命令セットを紹介します。
環境変数の置き換え¶
環境変数( env 命令 で宣言)を使うことで、 Dockerfile
で変数を解釈できるようにします。命令文字(ステートメント・リテラル)中では、変数の様な構文でエスケープ・シーケンスも扱えます。
Dockerfile
の中では、環境変数を $variable_name
または ${variable_name}
の形式で記述します。これらは同等に扱われます。固定用の構文として典型的に使われるのは、空白スペースを変数名に入れず ${foo}_bar
のような変数名で割り当てることです。
${変数の_名前}
構文は、次のような bash
の変更をサポートしています。
${変数:-文字}
は、変数
を設定すると、その値を使うことを意味します。もし変数
がセットされなければ、文字
が設定されます。${変数:+文字}
は、変数
を設定すると、文字
を使います。変数
がセットされなければ、空白のままにします。
いずれの場合でも、 文字
とは何らかの文字列であり、追加の環境変数を含みます。
エスケープするには \$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
同様に、
ONBLIUD
(上記の命令と組みあわせて使う場合にサポートされます)
注釈
1.4 より前のバージョンでは、環境変数における ONBUILD
命令と上記の命令の組み合わせはサポート されていません 。
環境変数を使う代わりに、各変数をコマンド上で利用できます。すなわち、次の例は、
ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
この結果、 def
は hello
値ですが、 bye
ではありません。しかしながら ghi
は bye
値になります。これは abc
を bye
に設定するのと同じコマンド行ではないためです。
.dockerignore ファイル¶
docker CLI がコンテクストを docker デーモンに送る前に、コンテクストのルートディレクトリ内の .dockerignore
ファイルを探します。もしファイルが存在していれば、CLI はコンテクストからパターンに一致するファイルとディレクトリを除外します。これは不必要に大きくならないようにします。また、取り扱いに注意が必要なファイルやディレクトリをデーモンに送らないようにします。ですが、 ADD
や COPY
でイメージに追加されるかもしれません。
CLI は .dockerignore
ファイルを行ごとに隔てて解釈します。行の一致パターンは Unix シェル上のものに似ています。パターンがコンテクストの root に一致すると考えられる場合は、root ディレクトリとして動作します。例えば、パターン /foo/bar
と foo/bar
がある場合、いずれも PATH
における foo
サブディレクトリの bar
ファイルを削除します。あるいは URL
の場所にある git のルートでもです。どちらでも除外されます。
これは .dockerignore
ファイルの例です:
*/temp*
*/*/temp*
temp?
このファイルは構築時に以下の動作をします。
*/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 を用いて除外します。
行を !
(エクスクラメーション・マーク)で始めると、除外ルールとして使えます。以下の例は .dockerignore
ファイルでこの仕組みを使ったものです。
*.md
!README.md
README.md を除く全てのマークダウンファイルが、コンテントから除外されます。
!
除外ルールが影響を与えるのは、 .dockerignore
ファイルに書いた場所以降に一致するパターンが現れた時、含めるか除外するかを決めます。次の例で考えて見ましょう。
*.md
!README*.md
README-secret.md
README を含むファイル以外は、README-secret.md
も含め、残り全てのマークダウンファイルが除外対象です。
その次の例を考えて見ましょう。
*.md
README-secret.md
!README*.md
README を含む全てのファイル除外します。真ん中の行 README-secret.md
は最終行の !README*.md
に一致するため、何の影響もありません。
.dockerignore
ファイルは Dockerfile
と .dockerignore
ファイルの除外にも使えます。それでも、これらのファイルはジョブを処理するためデーモンに送信されます。しかし ADD
と COPY
コマンドは、これらをイメージ内にコピーしません。
最後に、特定のファイルのみコンテクストに含め、他を除外したい場合があるでしょう。実行するには、始めに``*`` パターンに指定し、以下1つまたは複数の !
例外パターンを記述します。
注釈
歴史的な理由により、 .
パターンは無視されます。
FROM¶
FROM <イメージ>
または
FROM <イメージ>:<タグ>
または
FROM <イメージ>@<digest>
FROM
命令は、 ベース・イメージ サブシーケント命令を指定します。あるいは、有効な Dockerfile
は、1行目を FROM
命令で指定する必要があります。イメージとは、あらゆる有効なものが利用できます。 パブリック・リポジトリ から イメージを取得する 方法が一番簡単です。
Dockerfile
では、コメント以外ではFROM
を一番始めに書く必要があります。
- 単一の
Dockerfile
から複数のイメージを作成するため、複数のFROM
を指定できます。各FROM
命令ごとに自動的にコミットし、最新のイメージ ID が出力されるのを覚えておいてください。
タグ
やdigest
値はオプションです。省略した場合、ビルダーはデフォルトのlatest
とみなします。ビルダーは一致するtag
値がなければエラーを返します。
RUN¶
RUN には2つの形式があります。
RUN <コマンド>``(シェル形式、コマンドをシェル ``/bin/sh -c
で実行する)RUN ["実行バイナリ", "パラメータ1", "パラメータ2"]
( exec 形式)
RUN
命令は既存イメージ上の新しいレイヤーで、あらゆるコマンドを実行し、その結果をコミットする命令です。コミットの結果得られたイメージは、 Dockerfile
の次のステップで使われます。
RUN
命令の積み重ねとコミットによる生成は Docker の中心となるコンセプト(概念)に従ったものです。コミットは簡単であり、ソース・コントロールのように、イメージの履歴上のあらゆる場所からコンテナを作成可能です。
exec 形式はシェルの文字列を変更できないようにします。また、 /bin/sh
がベース・イメージに含まれなくても RUN
コマンドを使えます。
シェル 形式では、RUN 命令を \
(バックスラッシュ)を使い、次の行と連結します。例えば、次の2行があるものとします。
RUN /bin/bash -c 'source $HOME/.bashrc ;\
echo $HOME'
これは、次のように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" ]
。
次の構築時、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 ["実行バイナリ", "パラメータ1", "パラメータ2"]
( exec 形式、推奨する形式)CMD ["パラメータ1", "パラメータ2"]
( ENTRYPOINT のデフォルト・パラメータ)CMD <コマンド>
(シェル形式)
Dockerfile
で CMD
命令を一度だけ指定できます。複数の CMD
がある場合、最も後ろの CMD
のみ有効です。
CMD
の主な目的は、 ** コンテナ実行時のデフォルトを提供します** 。 デフォルトには、実行可能なコマンドが含まれているか、あるいは省略されるかもしれません。省略時は ENTRYPOINT
命令で同様に指定する必要があります。
注釈
ENTRYPOINT
命令のデフォルトの引数として CMD
を使う場合、 CMD
と ENTRYPOINT
命令の両方が JSON 配列フォーマットになっている必要があります。
注釈
exec 形式は JSON 配列でパースされます。つまり、文字を囲むのはシングル・クォート(‘) ではなくダブル・クォート(”)を使う必要があります。
注釈
シェル 形式と異なり、 exec 形式はコマンド・シェルを呼び出しません。つまり、通常のシェルによる処理が行われません。例えば CMD [ "echo", "$HOME" ]
は $HOME
の変数展開を行いません。シェルによる処理を行いたい場合は、 シェル 形式を使うか、あるいはシェルを直接使います。例: CMD [ "sh", "-c", "echo", "$HOME" ]
。
シェルあるいは exec 形式を使う時、 CMD
命令はイメージで実行するコマンドを指定します。
CMD
で シェル 形式を使うと、 <コマンド>
は /bin/sh -c
で実行されます。
FROM ubuntu
CMD echo "This is a test." | wc -
<コマンド>をシェルを使わずに実行 したい場合、コマンドを 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
の値に空白スペースを含む場合はクォートを使いますし、コマンドラインの分割にバックスラッシュを使います。使用例:
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."
イメージは複数のラベルを持てます。複数のラベルを指定すると、 Docker は可能であれば1つの LABEL
にすることをお勧めします。各 LABEL
命令は新しいレイヤを準備しますが、多くのラベルを使えば、それだけレイヤを使います。次の例は1つのイメージ・レイヤを使うものです。
LABEL multi.label1="value1" multi.label2="value2" other="value3"
上記の例は、次のようにも書き換えられます。
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
ラベルには、FROM
イメージが使う LABEL
も含まれています。ラベルのキーが既に存在しているとき、Docker は特定のキーを持つラベルの値を上書きします。
イメージが使っているラベルを確認するには、 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"
},
EXPOSE¶
EXPOSE <port> [<port>...]
EXPOSE
命令は、特定のネットワーク・ポートをコンテナが実行時にリッスンすることを Docker に伝えます。 EXPOSE
があっても、これだけではホストからコンテナにアクセスできるようにしません。アクセスするには、 -p
フラグを使ってポートの公開範囲を指定するか、 -P
フラグで全ての露出ポートを公開する必要があります。外部への公開時は他のポート番号も利用可能です。
ホストシステム上でポート転送を使うには、 -P フラグを使う をご覧ください。Docker のネットワーク機能は、ネットワーク内でポートを公開しないネットワークを作成可能です。詳細な情報は 機能概要 をご覧ください。
ENV¶
ENV <key> <value>
ENV <key>=<value> ...
ENV
命令は、環境変数 <key>
と 値 <value>
のセットです。値は Dockerfile
から派生する全てのコマンド環境で利用でき、 インラインで置き換え も可能です。
ENV
命令は2つの形式があります。1つめは、 ENV <key> <value>
であり、変数に対して1つの値を設定します。はじめの空白以降の文字列が <value>
に含まれます。ここには空白もクォートも含まれます。
2つめの形式は ENV <key>=<value> ...
です。これは一度に複数の変数を指定できます。先ほどと違い、構文の2つめにイコールサイン(=)があるので気をつけてください。コマンドラインの分割、クォート、バックスラッシュは、空白スペースも含めて値になります。
例:
ENV myName="John Doe" myDog=Rex\ The\ Dog \
myCat=fluffy
そして
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy
この例では、どちらも最終的に同じ結果をコンテナにもたらしますが、私たちが推奨するのは前者です。理由は前者であれば単一のキャッシュ・レイヤしか使わないからです。
環境変数の設定に ENV
を使うと、作成したイメージを使ってコンテナを実行しても有効です。どのような値が設定されているかは docker inspect
で確認でき、変更するには docker run --env <key>=<value>
を使います。
注釈
環境変数の一貫性は予期しない影響を与える場合があります。例えば、 ENV DEBIAN_FRONTEND noninteractive
が設定されていると、Debian ベースのイメージで apt-get の利用者が混乱するかもしれません。1つのコマンドだけで値を設定するには、 RUN <key>=<value> <コマンド>
を使います。
ADD¶
Add は2つの形式があります。
ADD <ソース>... <送信先>
ADD ["<ソース>", ... "<送信先>"]
(この形式はパスに空白スペースを使う場合に必要)
ADD
命令は <ソース>
にある新しいファイルやディレクトリをコピー、あるいはリモートの URL からコピーします。それから、コンテナ内のファイルシステム上にある 送信先
に指定されたパスに追加します。
複数の <ソース>
リソースを指定できます。このとき、ファイルやディレクトリはソースディレクトリ(構築時のコンテクスト)からの相対パス上に存在しないと構築できません。
それぞれの <ソース>
にはワイルドカードと Go 言語の filepath.Mach ルールに一致するパターンが使えます。例えば、次のような記述です。
ADD hom* /mydir/ # "hom" で始まる全てのファイルを追加
ADD hom?.txt /mydir/ # ? は1文字だけ一致します。例: "home.txt"
<送信先>
は絶対パスです。あるいは、パスは WORKDIR
からの相対パスです。ソースにあるものが、対象となる送信先コンテナの中にコピーされます。
ADD test relativeDir/ # "test" を `WORKDIR`/relativeDir/ (相対ディレクトリ)に追加
ADD test /absoluteDir # "test" を /absoluteDir (絶対ディレクトリ)に追加
追加される新しいファイルやディレクトリは、全て UID と GID が 0 として作成されます。
<ソース>
がリモート URL の場合は、送信先のパーミッションは 600 にします。もしリモートのファイルが HTTP Last-Modified
ヘッダを返す場合は、このヘッダの情報を元に送信先ファイルの mtime
を指定するのに使います。しかしながら、 ADD
を使ったファイルをコピーする手順では、 mtime
はファイルが更新されたかどうかの決定には使われず、ファイルが更新されればキャッシュも更新されます。
注釈
Dockerfile
を標準入力( docker build - < 何らかのファイル
)を通して構築しようとしても。構築時のコンテントは存在しないため、 Dockerfile
には URL を指定する ADD
命令のみ記述可能です。また、圧縮ファイルを標準入力( docker build - < archive.tar.gz
)を通すことができ、アーカイブに含まれるルートに Dockerfile
があれば、構築時のコンテクストとしてアーカイブが使われます。
注釈
URL で指定したファイルに認証がかかっている場合は、 RUN wget
や RUN curl
や他のツールを使う必要があります。これは ADD
命令が認証機能をサポートしていないからです。
注釈
ADD
命令が出てくると、まず <ソース>
に含まれる内容が変更されていれば、以降の Dockerfile
に書かれている命令のキャッシュを全て無効化します。これは RUN
命令のキャッシュ無効化も含まれます。より詳細な情報については Dockerfile
の ベスト・プラクティス・ガイド をご覧ください。
ADD
は以下のルールに従います。
<ソース>
パスは、構築時の コンテント 内にある必要があります。そのため、ADD ../something /something
の指定はできません。docker build
の最初のステップで、コンテクストのディレクトリ(と、サブディレクトリ)を docker デーモンに送るためです。
<ソース>
が URL であり、<送信先>
の末尾にスラッシュが無い場合、URL からファイルをダウンロードし、<送信先>
にコピーします。
- もし
<ソース>
が URL であり、<送信先>
の末尾がスラッシュの場合、URL からファイル名を推測し、ファイルを<送信先>/<ファイル名>
にダウンロードします。例えば、ADD http://example.com/foobar /
は、/foobar
ファイルを作成します。URL には何らかのパスが必要です。これは適切なファイル名を見つけられない場合があるためです(今回の例では、http://example.com
の指定は動作しません)。
<ソース>
がディレクトリの場合、ディレクトリの内容の全てがコピーされます。これにはファイルシステムのメタデータを含みます。
注釈
ディレクトリ自身はコピーされません。ディレクトリは単なるコンテントの入れ物です。
- もし
<ソース>
が ローカル にある tar アーカイブの場合、圧縮フォーマットを認識します(gzip、bzip2、xz を認識)。それからディレクトリに展開します。 リモート の URL が指定された場合は展開 しません。ディレクトリにコピーまたは展開するときは、tar -x
と同じ働きをします。結果は次の処理を同時に行います。
- 送信先のパスが存在しているかどうか
- ファイル単位の原則に従って、ソース・ツリーの内容と衝突しないかどうか「2」を繰り返す
注釈
ファイルが圧縮フォーマットと認識されるか、あるいはファイルの集まりをベースにしているのかは、ファイルの名前では判断しません。例えば、空のファイル名の拡張子が .tar.gz
であれば圧縮ファイルと認識しないため、展開エラーのメッセージを表示 しません 。そして単純に送信先にファイルをコピーします。
- もし
<ソース>
がファイル以外であれば、個々のメタデータと一緒にコピーします。<送信先>
の末尾がスラッシュ/
で終わる場合は、ディレクトリであるとみなし、ソース
の内容を<送信先>/base(<ソース>)
に書き込みます。
- もし複数の
<ソース>
リソースが指定された場合や、ディレクトリやワイルドカードを使った場合、<送信先>
は必ずディレクトリになり、最後はスラッシュ/
にしなければいけません。
- もし
<送信先>
の末尾がスラッシュで終わらなければ、通常のファイルとみなされ、<ソース>
の内容は<送信先>
として書き込まれます。
<送信先>
が存在しなければ、パスに存在しないディレクトリを作成します。
COPY¶
COPY has two forms:
COPY は2つの形式があります。
COPY <ソース>... <送信先>
COPY ["<ソース>",... "<送信先>"]
(この形式はパスに空白スペースを使う場合に必要)
COPY
命令は <ソース>
にある新しいファイルやディレクトリをコピーするもので、コンテナ内のファイルシステム上にある <送信先>
に指定されたパスに追加します。
複数の <ソース>
リソースを指定できます。このとき、ソースディレクトリ(構築時のコンテクスト)からの相対パス上に存在しないと構築できません。
それぞれの <ソース>
にはワイルドカードと Go 言語の filepath.Mach ルールに一致するパターンが使えます。例えば、次のような記述です。
COPY hom* /mydir/ # "hom" で始まる全てのファイルを追加
COPY hom?.txt /mydir/ # ? は1文字だけ一致します。例: "home.txt"
<送信先>
は絶対パスです。あるいは、パスは WORKDIR
からの相対パスです。ソースにあるものが、対象となる送信先コンテナの中にコピーされます。
COPY test relativeDir/ # "test" を `WORKDIR`/relativeDir/ (相対ディレクトリ)に追加
COPY test /absoluteDir # "test" を /absoluteDir (絶対ディレクトリ)に追加
追加される新しいファイルやディレクトリは、全て UID と GID が 0 として作成されます。
注釈
標準入力( docker build - < 何らかのファイル
)を使って構築しようとしても、構築時のコンテントは存在しないため、 COPY
を使えません。
COPY
は以下のルールに従います。
<ソース>
パスは、構築時の コンテント 内にある必要があります。そのため、COPY ../something /something
の指定はできません。docker build
の最初のステップで、コンテクストのディレクトリ(と、サブディレクトリ)を docker デーモンに送るためです。
<ソース>
がディレクトリの場合、ディレクトリの内容の全てがコピーされます。これにはファイルシステムのメタデータを含みます。
注釈
ディレクトリ自身はコピーされません。ディレクトリは単なるコンテントの入れ物です。
- もし
<ソース>
がファイル以外であれば、個々のメタデータと一緒にコピーします。<送信先>
の末尾がスラッシュ/
で終わる場合は、ディレクトリであるとみなし、ソース
の内容を<送信先>/base(<ソース>)
に書き込みます。
- もし複数の
<ソース>
リソースが指定された場合や、ディレクトリやワイルドカードを使った場合、<送信先>
は必ずディレクトリになり、最後はスラッシュ/
にしなければいけません。
- もし
<送信先>
の末尾がスラッシュで終わらなければ、通常のファイルとみなされ、<ソース>
の内容は<送信先>
として書き込まれます。
<送信先>
が存在しなければ、パスに存在しないディレクトリを作成します。
ENTRYPOINT¶
ENTRYPOINT には2つの形式があります。
ENTRYPOINT ["実行可能なもの", "パラメータ1", "パラメータ2"]
( exec 形式、推奨)ENTRYPOINT コマンド パラメータ1 パラメータ2
( シェル 形式)
ENTRYPOINT
はコンテナが実行するファイルを設定します。
例えば、次の例は nginx をデフォルトの内容で開始し、ポート 80 を開きます。
docker run -i -t --rm -p 80:80 nginx
コマンドラインで docker run <イメージ>
コマンドに引数を付けると、exec 形式 の ENTRYPOINT
で指定されている全要素の後に追加されます。そして、このとき CMD
を使って指定されていた要素は上書きされます。この動きにより、引数はエントリー・ポイント(訳者注:指定されたバイナリ)に渡されます。例えば、 docker run <イメージ> -d
は、引数 -d
をエントリポイントに渡します。 ENTRYPOINT
命令を上書きするには、 docker run --entrypoint
フラグを使います。
シェル 形式では CMD
や run
コマンド行の引数を使えないという不利な点があります。 ENTRYPOINT
は /bin/sh -c
のサブコマンドとして実行されるため、シグナルを渡せません。つまり、何かを実行してもコンテナの PID 1
にはなりません。そして、 Unix シグナルを受け付け ません。そのため、実行ファイルは docker stop <コンテナ>
を実行しても、 SIGTERM
を受信しません。
Dockerfile
の最後に現れた ENTRYPOINT
命令のみ有効です。
exec 形式の ENTRYPOINT 例¶
ENTRYPOINT
の exec 形式を使い、適切なデフォルトのコマンドと引数を指定します。それから CMD
を使い、変更する可能性のある追加のデフォルト引数も指定します。
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
コンテナを実行すると、 top
のプロセスが1つだけ見えます。
$ 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
それから、docker stop test
を使い top
を停止するよう、通常のリクエストを行えます。
次の Dockerfile
は ENTRYPOINT
を使って Apache をフォアグラウンドで実行します(つまり、 PID 1
として)。
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"]
もし実行するだけの起動スクリプトを書く必要があれば、最後に実行するコマンドが 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 "$@"
さいごに、シャットダウン時に何らかの追加クリーンアップ(あるいは、他のコンテナとの通信)が必要な場合や、1つ以上の実行ファイルと連携したい場合、 ENTRYPOINT
のスクリプトが Unix シグナルを受信出来るようにし、それを使って様々な処理を行います。
#!/bin/sh
# メモ:これは sh を使っていますので、busyboy コンテナでも動きます
# サービス停止時に手動でもクリーンアップが必要な場合は trap を使います。
# あるいは1つのコンテナ内に複数のサービスを起動する必要があります。
trap "echo TRAPed signal" HUP INT QUIT KILL 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
注釈
ENTRYPIONT
設定は --entrypoint
を使って上書きできますが、設定できるのはバイナリが実行可能な場合のみです( sh -c
が使われていない時のみ )。
注釈
exec 形式は JSON 配列でパースされます。つまり、語句はシングルクォート(‘)ではなく、ダブルクォート(”)で囲む必要があります。
注釈
シェル 形式とは異なり、 exec 形式はシェルを呼び出しません。つまり、通常のシェル上の処理はされません。例えば、 ENTRYPOINT ["echo", "$HOME"]
は $HOME
を変数展開しません。シェル上の処理が必要であれば、 シェル 形式を使うか、シェルを直接実行します。例: ENTRYPOINT [ "sh", "-c", "echo", "$HOME" ]
。変数は Dockerfile
で ENV
を使って定義することができ、 Dockerfile
パーサー上で展開されます。
シェル形式の ENTRYPOINT 例¶
ENTRYPOINT
に文字列を指定すると、 /bin/sh -c
で実行されます。この形式はシェルの処理を使うので、シェル上の環境変数を展開し、 CMD
や docker run
コマンド行の引数を無視します。 docker stop
で ENTRYPOINT
で指定している実行ファイルにシグナルを送りたい場合は、 exec
を使う必要があるのを思い出してください。
FROM ubuntu
ENTRYPOINT exec top -b
このイメージを実行すると、単一の PID 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
top
の出力から、 ENTRYPOINT
が 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
VOLUME¶
VOLUME ["/data"]
VOLUME
命令は指定した名前でマウントポイントを作成し、他のホストやコンテナから外部マウント可能なボリュームにします。指定する値は VOLUME ["/var/log"]
といったJSON 配列になるべきです。あるいは文字列で 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
ファイルを直近で作成したボリュームにコピーします。
注釈
構築ステップでボリューム内においてあらゆる変更を加えても、宣言後に内容は破棄されます。
注釈
リストは JSON 配列でパースされます。これが意味するのは、単語はシングルクォート(‘)で囲むのではなく、ダブルクォート(”)を使う必要があります。
USER¶
USER daemon
USER
命令セットはユーザ名か UID を使います。これはイメージを RUN
、 CMD
、 ENTRYPOINT
命令で実行するときのものであり、 Dockerfile
で指定します。
WORKDIR¶
WORKDIR /path/to/workdir
WORKDIR
命令セットは Dockerfile
で RUN
、 CMD
、 ENTRYPOINT
、 COPY
、 ADD
命令実行時の作業ディレクトリ(working directory)を指定します。
1つの Dockerfile
で複数回の利用が可能です。パスが指定されると、 WORKDIER
命令は直前に指定した相対パスに切り替えます。例:
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 <変数名>=<値>
フラグを定義するものです。ユーザが構築時に引数を指定しても Dockerfile で定義されていなければ、構築時に次のようなエラーが出ます。
One or more build-args were not consumed, failing build.
Dockerfile の作者は ARG
変数を1度だけ定義するだけでなく、複数の ARG
を指定可能です。有効な Dockerfile の例:
FROM busybox
ARG user1
ARG buildno
...
Dockerfile の作者は、オプションで ARG
命令のデフォルト値を指定できます。
FROM busybox
ARG user1=someuser
ARG buildno=1
...
ARG
がデフォルト値を持っている場合、構築時に値が指定されなければ、ビルダーはこのデフォルト値を使います。
ARG
変数は Dockerfile
で記述した行以降で効果があります。ただし、コマンドライン上で引数の指定が無い場合です。次の Dockerfile の例を見てみましょう。
FROM busybox
USER ${user:-some_user}
ARG user
USER $user
...
$ docker build --build-arg user=what_user Dockerfile
2行目の USER
は some_user
を、3行目サブシーケントで定義された user
変数として評価します。4行目では what_user
を USER
で定義したものと評価し、 what_user
値はコマンドラインで指定したものになります。 ARG
命令で定義するまで、あらゆる変数は空の文字列です。
注釈
構築時の変数として、GitHub の鍵やユーザの証明書などの秘密情報を含むのは、推奨される使い方ではありません。
ARG
や ENV
命令を RUN
命令のための環境変数にも利用できます。 ENV
命令を使った環境変数の定義は、常に同じ名前の ARG
命令を上書きします。Dockerfile における``ENV`` と ARG
命令を考えましょう。
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
のかわりに、 ARG
でユーザから渡された v2.0.1
を使います。この動作はシェルスクリプトの挙動に似ています。ローカルのスコープにある環境変数が、与えられた引数や上位の環境変数によって上書きするようなものです。
上記の ENV
指定の他にも、さらに ARG
と ENV
を使いやすくする指定も可能です。
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER
ARG
命令とは異なり、構築時の ENV
値は常に一定です。docker build で –build-arg フラグを使わない場合を考えてみましょう。
この Dockerfile の例では、 CONT_IMG_VER
はイメージの中では変わりませんが、3行目の ENV
命令でデフォルト値を設定することにより、値は v1.0.0
となります。
この例における変数展開のテクニックは、コマンドラインから引数を渡せるようにし、 ENV
命令を使うことで最終的に一貫したイメージを作成します。サポートされている変数展開は Dockerfile 命令の一部 のみです。
Docker は Dockerfile に対応する ARG
命令がなくても、既定の ARG
変数セットを持っています。
HTTP_PROXY
http_proxy
HTTPS_PROXY
https_proxy
FTP_PROXY
ftp_proxy
NO_PROXY
no_proxy
これらを使うには、コマンドラインで --build-arg <変数名>=<値>
フラグを単に渡すだけです。
ONBUILD¶
ONBUILD [命令]
イメージは他で構築したイメージをもとにしているとき、ONBUILD
命令はイメージに対して最終的に実行する トリガ 命令を追加します。トリガは構築後に行うもので、 Dockerfile
で FROM
命令のあとに書くことができます。
あらゆる構築時の命令をトリガとして登録可能です。
これは他のイメージからイメージを構築する時に役立つでしょう。例えば、アプリケーションの開発環境やデーモンは、ユーザごとに設定をカスタマイズする可能性があります。
例えば、イメージが Python アプリケーション・ビルダーを再利用するとき、アプリケーションのソースコードを適切なディレクトリに追加し、その後、構築スクリプトを実行することもあるでしょう。この時点では ADD
と RUN
を呼び出せません。なぜなら、まだアプリケーションのソースコードにアクセスしておらず、個々のアプリケーション構築によって異なるからです。アプリケーションの開発者は、ボイラープレートである Dockerfile
をコピーペーストでアプリケーションを入れるように編集するだけです。ですが、これは効率的ではなく、エラーを引き起こしやすく、アプリケーション固有のコード画混在することで更新が大変になります。
この解決方法として、 ONBLUID
を使い、実行後に別の構築ステージに進む上位命令を登録することです。
これは次のように動作します。
ONBUILD
命令が呼び出されると、ビルダーはイメージ構築時のメタデータの中にトリガを追加します。
- 構築が完了すると、すべてのトリガはイメージのマニフェスト内の
OnBuild
キー配下に保管されます。この構築時点では、命令は何ら影響を与えません。
- このイメージは後で何らかのイメージの元になrます。そのときは
FROM
命令で呼び出されます。FROM
命令の処理の一部として、ダウンストリームのビルダーはONBULID
トリガを探し、登録された順番で実行します。もしトリガが失敗すると、FROM
命令は処理を中断し、ビルドを失敗とします。もし全てのトリガが成功すると、FROM
命令は完了し、以降は通常の構築が進みます。
- 実行する前に、最終的なイメージ上からトリガが削除されます。言い替えると構築された「孫」には、何ら親子関係がありません。
次のような例の記述を追加するでしょう。
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
警告
ONBUILD ONBUILD
命令を使って ONBULID
命令の上書きはできません。
STOPSIGNAL¶
STOPSIGNAL シグナル
STOPSIGNAL
命令は、コンテナを終了するときに送信するための、システム・コール・シグナルを設定します。シグナルはカーネルの syscall テーブルと一致する、有効な番号の必要があります。例えば、9 あるいはシグナル名 SIGNAME や、 SIGKILL などです。
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/