Dockerfileのリファレンスまとめ(自分用)
概要
Dockerを使用していたが、そもそもDockerfileについてしっかりと理解していなかったので、ここで一旦 Dockerfile についてまとめてみます。Dockerfile の命令コマンドについて簡単にまとめてある程度理解をしようと思います。
まとめる内容は以下のリファレンスを参考にしているものです。
簡易的なまとめ
命令 | 説明 |
---|---|
FROM | ベースイメージを作成する |
RUN | シェルで実行するコマンドをここで命令する(イメージ) |
CMD | RUNと同様で、制約(最後のCMD命令のみ実行される)がある |
LABEL | イメージにメタデータを付与する |
EXOPOSE | 解放したいポートを指定する(実際は解放されない) |
EMV | 環境変数 |
ADD | 追加したいファイル、ディレクトリ、リモートファイルの URLを指定すると、イメージのファイルシステム上に追加します |
COPY | 追加したいファイル、ディレクトリからイメージのファイルシステム上に追加します |
ENTRYPOINT | CMDと同様で、一つのENTRYPOINTを実行する |
WORKDIR | コンテナが作成された時に作業するディレクトリを指定する |
ARG | 変数として値を代入してDockerfile内で使用することが可能です |
命令コマンド
FROM
FROM命令は、新しいビルドステージを初期化し、後続の命令のためのベースイメージを設定します。そのため、有効なDockerfileはFROM命令で始まる必要がある。(例外として、ARG
命令は、FROM
命令より前に記載することが可能)
# | 説明 |
---|---|
1 | ARGはDockerfileでFROMに先行することができる唯一の命令です |
2 | FROM命令は、複数のイメージを作成したり、あるビルドステージを別のビルドステージの依存関係として使用するために、1つのDockerfile内で複数回現れることある。新しいFROM命令(2つ目以降)の前に、コミットされ、出力された最後のイメージIDをメモしておくだけでよい。各FROM命令は、前の命令で作成された状態をすべてクリアする。 |
3 | オプションとして、FROM命令にAS名を追加することで、新しいビルドステージに名前を付けることができる。これは、後続のFROM命令やCOPY -from=<名前>命令で、このステージで構築されたイメージを参照するために使用することができる。 |
4 | タグやダイジェストの値はオプションです。どちらかを省略した場合、ビルダーはデフォルトでlatest をしていする。タグの値が見つからない場合、ビルダーはエラーとなる。。 |
ARGとFROMの相互作用を理解する
FROM命令は、最初のFROMの前に出現するARG命令で宣言された変数をサポートします。
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
# shell 形式(コマンドはシェル内で実行される。デフォルトは Linux が /bin/sh -c で、 Windows は cmd /S /C )
RUN <コマンド>
# exec 形式
RUN ["実行ファイル", "パラメータ1", "パラメータ2"]
RUN命令は、現在のイメージの上に新しいレイヤーで任意のコマンドを実行し、その結果をコミットします。コミットされたイメージは、Dockerfileの次のステップで使用されます。
- RUN命令を重ねてコミットを生成することは、コミットが安価で、ソース管理のようにイメージの履歴のどの時点からでもコンテナを作成できるDockerの中核概念に適合しています。
-
exec形式
は、シェルの文字列の乱れを回避し、指定したシェル実行ファイルを含まないベースイメージを使用してコマンド実行を可能にしている。 - シェル形式では、1つのRUN命令を次の行に続けるために、
\
(バックスラッシュ)を使用することができます。
RUN /bin/bash -c 'source $HOME/.bashrc ;\
echo $HOME'
# ↑と↓は同等
RUN /bin/bash -c 'source $HOME/.bashrc ; echo $HOME'
# exec形式だと
RUN ["/bin/bash", "-c", "echo hello"]
:::note
exec形式
は JSON配列
として構文解析されます。そのため、文字を囲むにはシングル・クォート(')
ではなく、ダブル・クォート(")
を使う必要がある。
:::
exec形式は、shell形式と異なり、コマンドシェルを呼び出すものではありません。つまり、通常のシェル処理は行われない。例えば、RUN [ "echo", "
- シェル処理を行いたい場合は、シェル形式を使用するか、シェルを直接実行します:
RUN [ "sh", "-c", "echo $HOME" ]
- exec形式を使用してシェルを直接実行する場合、シェル形式の場合と同様に、環境変数の拡張を行うのはシェルであり、Dockerではありません。
RUN命令のキャッシュは、ビルド時に自動的に無効化されるわけではありません。RUN apt-get dist-upgrade -y
のような命令のキャッシュは、次のビルド時に再利用されます。RUN命令のキャッシュは、docker build --no-cache
のように--no-cache
フラグを使用することで無効にすることができます。
CMD
CMD ["実行ファイル","パラメータ1","パラメータ2”](exec 形式:推奨)
CMD ["パラメータ1", "パラメータ2”](ENTRYPOINT 命令に対するデフォルトのパラメータとして扱う)
CMD コマンド パラメータ1 パラメータ2(シェル形式)
DockerfileのCMD
命令は1つだけで、複数のCMDを記載した場合は、最後のCMD
のみが有効になる。
CMDの主な目的 | 実行中のコンテナにデフォルトを提供することです。 |
---|---|
これらのデフォルトは実行可能ファイルを含むことも、実行可能ファイルを省略することもでき、その場合はENTRYPOINT 命令も指定する必要がある。 |
ENTRYPOINT
命令のデフォルト引数としてCMD
を使用する場合は、CMD
命令とENTRYPOINT
命令の両方をJSON配列形式で指定する必要がある。
-
exec 形式は、RUN 命令と同等。
コンテナを起動するたびに、同じコマンドを毎回実行するのであれば、 ENTRYPOINT 命令と CMD 命令の組み合わせを検討。
LABEL
LABEL <キー>=<値> <キー>=<値> <キー>=<値> ...
LABEL
命令は、イメージにメタデータを付加する命令です。LABEL
は、キーと値のペアです。LABEL
の値にスペースを含めるには、コマンドラインのパースと同様に、引用符とバックスラッシュを使用します。
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
イメージには複数のLABELを持つことが可能、また一行に複数のラベルを指定可能。
LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
EXOPOSE
EXPOSE <ポート> [<ポート>/<プロトコル>...]
EXPOSE
命令は、コンテナが実行時に指定されたネットワークポートをリッスンすることをDockerに通知します。ポートはTCPまたはUDPのどちらかを指定でき、プロトコルを指定しない場合のデフォルトはTCPです。
-
EXPOSE
命令は、実際にポートを公開するわけではありません。これは、イメージを構築するユーザーとコンテナを実行するユーザーの間で、どのポートを公開することを意図しているかについて、一種の文書として機能している。 - 実際にポートを公開するには、
docker run
で-p
フラグを使用して1つまたは複数のポートを公開してマッピングするか、-P
フラグを使用してすべての公開ポートを公開して高位ポートにマッピングする。 - デフォルトでは、
EXPOSE
はTCPを想定しています。UDPを指定することも可能です。
EXPOSE 80/udp
EMV
ENV <キー>=<値> ...
ENV
命令は、環境変数key
に値value
を設定します。この値は、ビルドステージにおける後続のすべての命令の環境変数となり、同様に多くのインラインで置き換えることができます。この値は他の環境変数に対しても解釈されるため、引用文字がエスケープされていない場合は削除されます。コマンドラインの解析と同様に、引用符とバックスラッシュを使用して、値の中にスペースを含めることができます。
ENV
命令は、環境変数key
に値value
を設定します。
この値は、ビルドステージにおける後続のすべての命令の環境変数となり、同様に多くのインラインで置き換えることができます。この値は他の環境変数に対しても解釈されるため、引用文字がエスケープされていない場合は削除されます。コマンドラインの解析と同様に、引用符とバックスラッシュを使用して、値の中にスペースを含めることができます。
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
一行に複数の値を設定することが可能です。
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy
ADD
ADD [--chown=<user>:<group>] [--chmod=<perms>] [--checksum=<checksum>] <src>... <dest>
ADD [--chown=<user>:<group>] [--chmod=<perms>] ["<src>",... "<dest>"]
後者の形式は、空白を含むパスの場合に必要です。
-
ADD
命令は、新しいファイル、ディレクトリ、またはリモートファイルURLをsrc
からコピーし、パスdest
にあるイメージのファイルシステムに追加する命令です。 - 複数の
src
リソースを指定することができますが、それらがファイルまたはディレクトリである場合、それらのパスはビルドのコンテキストのソースからの相対パスとして解釈されます。
hom "で始まるファイルをすべて追加する場合
ADD hom* /mydir/
相対パスを使用し、WORKDIR/relativeDir/
にtest.txt
を追加しています:
ADD test.txt relativeDir/
ADDは以下のルール
# | 説明 |
---|---|
1 |
src パスはビルドのコンテキスト内になければなりません。Dockerビルドの最初のステップはコンテキストディレクトリ(およびサブディレクトリ)をdockerデーモンに送信するため、../something /something を追加することができません。 |
2 |
src がURLで、dest が末尾のスラッシュで終わっていない場合、URLからファイルをダウンロードし、dest にコピーします。 |
3 |
src がURLで、dest が末尾のスラッシュで終わっている場合、URLからファイル名が推測され、<dest>/<filename> にファイルがダウンロードされます。例えば、ADD http://example.com/foobar /は、ファイル/foobarを作成します。この場合、適切なファイル名を発見できるように、URLは自明でないパスでなければなりません(http://example.com は機能しません)。 |
4 |
src がディレクトリの場合、ファイルシステムのメタデータを含むディレクトリの全内容がコピーされる。 |
5 |
src が認識された圧縮形式(identity、gzip、bzip2、xz)のローカルtarアーカイブの場合、ディレクトリとして解凍されます。リモートURLからのリソースは解凍されません。ディレクトリがコピーまたは解凍されると、tar -x と同じ動作になり、結果はその組合わせになる: ①デスティネーションパスに存在するもので ②ソースツリーの内容で、ファイル単位で "2. "に有利なようにコンフリクトを解決したものです。 |
6 |
src が他の種類のファイルである場合、メタデータとともに個別にコピーされる。この場合、dest の末尾がスラッシュ/であれば、それはディレクトリとみなされ、src の内容はdest /base(src )に書き込まれます。 |
7 | 複数のsrc リソースが直接またはワイルドカードの使用により指定された場合、dest はディレクトリでなければならず、スラッシュ/ で終わらなければならない。 |
8 |
dest が末尾にスラッシュを持たない場合、通常のファイルとみなされ、src の内容がdest に書き込まれます。 |
9 |
dest が存在しない場合は、そのパスにあるすべての欠落したディレクトリと一緒に作成されます。 |
COPY
COPY [--chown=<user>:<group>] [--chmod=<perms>] <src>... <dest>
COPY [--chown=<user>:<group>] [--chmod=<perms>] ["<src>",... "<dest>"]
この後者の形式は、空白を含むパスの場合に必要です。
COPY命令は、新しいファイルやディレクトリを<src>からコピーし、パス<dest>にあるコンテナのファイルシステムに追加する命令です。
複数の<src>リソースを指定することができますが、ファイルやディレクトリのパスは、ビルドのコンテキストのソースからの相対パスとして解釈されます。
COPYのルール
# | 説明 |
---|---|
1 |
src パスはビルドのコンテキスト内になければなりません。dockerビルドの最初のステップはコンテキストディレクトリ(およびサブディレクトリ)をdockerデーモンに送信するため、COPY ../something /something はできません。 |
2 |
src がディレクトリの場合、ファイルシステムのメタデータを含むディレクトリの全内容がコピーされる。 |
3 |
src が他の種類のファイルである場合、メタデータとともに個別にコピーされる。この場合、dest の末尾がスラッシュ/であれば、それはディレクトリとみなされ、src の内容はdest/base(src) に書き込まれます。 |
4 | 複数のsrc リソースが直接またはワイルドカードの使用により指定された場合、dest はディレクトリでなければならず、スラッシュ/ で終わらなければならない。 |
5 |
dest が末尾にスラッシュを持たない場合、通常のファイルとみなされ、src の内容がdest に書き込まれます。 |
6 |
dest が存在しない場合は、そのパスにあるすべての欠落したディレクトリと一緒に作成されます。 |
ENTRYPOINT
# exec形式: 推奨
ENTRYPOINT ["executable", "param1", "param2"]
# shell形式
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を受け取らない。
Dockerfileの最後のENTRYPOINT命令だけが効果を発揮する。
WORKDIR
WORKDIR /path/to/workdir
WORKDIR
命令は、Dockerfile内でそれに続くRUN
、CMD
、ENTRYPOINT
、COPY
、ADD
命令のための作業ディレクトリを設定します。WORKDIR
が存在しない場合、後続のDockerfile命令で使用されなくても作成されます。
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
になります。 - 指定しない場合、デフォルトの作業ディレクトリは
/
です。実際には、Dockerfileをゼロから構築していない場合、WORKDIR
は使用しているベースイメージによって設定されている可能性が高いでしょう。 - 未知のディレクトリでの意図しない操作を避けるために、
WORKDIR
を明示的に設定するのがベストプラクティスです。
ARG
ARG <name>[=<default value>]
ARG
命令は、ユーザがビルド時にdocker build
コマンドで-build-arg <varname>=<value>
フラグを使ってビルダーに渡すことができる変数を定義しています。
Dockerfileは、1つ以上のARG命令を含むことができる。
FROM busybox
ARG user1
ARG buildno
まとめ
今回は以下の内容をまとめました。現在僕がよく使うものをまずはまとめました。これから少しずつまとめていこうかと思います。
(自分的なまとめ)
命令 | 説明 |
---|---|
FROM | ベースイメージを作成する |
RUN | シェルで実行するコマンドをここで命令する(イメージ) |
CMD | RUNと同様で、制約(最後のCMD命令のみ実行される)がある |
LABEL | イメージにメタデータを付与する |
EXOPOSE | 解放したいポートを指定する(実際は解放されない) |
EMV | 環境変数 |
ADD | 追加したいファイル、ディレクトリ、リモートファイルの URLを指定すると、イメージのファイルシステム上に追加します |
COPY | 追加したいファイル、ディレクトリからイメージのファイルシステム上に追加します |
ENTRYPOINT | CMDと同様で、一つのENTRYPOINTを実行する |
WORKDIR | コンテナが作成された時に作業するディレクトリを指定する |
ARG | 変数として値を代入してDockerfile内で使用することが可能です |
Discussion