Dockerfile リファレンス 日本語訳

[Dockerfile reference](https://docs.docker.com/engine/reference/builder/) の日本語訳。

Docker は Dockerfile から指示を読み取ることにより、イメージを自動的に構築できます。
Dockerfile はイメージを構築する為のコマンドを記述したテキストドキュメントです。
ユーザーがコマンドラインから呼び出して使用します。
[docker build](https://qiita.com/JhonnyBravo/items/87976fe9de47ed58b8b1) を使用することで、ユーザーは複数のコマンドライン命令を連続して実行する自動ビルドを作成できます。

このページでは Dockerfile で使用できるコマンドについて説明します。
このページを読み終えたら [Dockerfile Best Practices for a tip-oriented guide](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/) を参照してください。

## 使用法

[docker build](https://qiita.com/JhonnyBravo/items/87976fe9de47ed58b8b1) コマンドは Dockerfile とコンテキストからイメージをビルドします。
ビルドのコンテキストは、指定された場所の PATH または URL にあるファイルのセットです。
PATH はローカルファイルシステム上のディレクトリです。
URL は Git リポジトリの場所です。

コンテキストは再帰的に処理されます。
したがって PATH にはサブディレクトリが含まれ、 URL にはリポジトリとそのサブモジュールが含まれます。
次の例は、現在のディレクトリをコンテキストとして使用するビルドコマンドを示しています。

```bash
$ docker build .

Sending build context to Docker daemon  6.51 MB
...
```

ビルドは CLI ではなく Docker デーモンによって実行されます。
ビルドプロセスが最初に行うことは、コンテキスト全体を(再帰的に)デーモンに送信することです。
ほとんどの場合、コンテキストとして空のディレクトリから開始し、Dockerfile をそのディレクトリに保持することをお勧めします。
Dockerfile の構築に必要なファイルのみを追加してください。

>**警告**
>ルートディレクトリ ``/`` を PATH として使用しないでください。
>ビルド実行時にハードドライブの内容全体が Docker デーモンに転送されます。


ビルドコンテキストでファイルを使用する際、 Dockerfile は ``COPY`` 命令などの命令で指定されたファイルを参照します。
ビルドのパフォーマンスを向上させるには、コンテキストディレクトリに ``.dockerignore`` ファイルを追加してファイルとディレクトリを除外します。
``.dockerignore`` ファイルを作成する方法については、このページのドキュメントを参照してください。

慣例として Dockerfile はコンテキストのルートに配置しますが、
[docker build](https://qiita.com/JhonnyBravo/items/87976fe9de47ed58b8b1) で ``-f`` フラグを使用して、ファイルシステム内の任意の場所にある ``Dockerfile`` を指定できます。

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

ビルドが成功した場合に新しいイメージを保存するリポジトリとタグを指定できます。

```bash
$ docker build -t shykes/myapp .
```

ビルド後にイメージを複数のリポジトリにタグ付けするには、ビルドコマンドの実行時に複数の ``-t`` パラメータを追加します。

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

Docker デーモンは Dockerfile の命令を実行する前に、 Dockerfile の事前検証を実行し、構文が正しくない場合はエラーを返します。

```bash
$ 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 ビルドプロセスを大幅に高速化します。
中間イメージの再利用は、コンソール出力の ``Using cache`` メッセージによって示されます。
(詳細については [Dockerfile ベストプラクティスガイド](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/) を参照してください)

```bash
$ 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`` で指定されたイメージは、親チェーンを持つ必要はなく、他のレジストリから取得できます。

ビルドが完了したら、リポジトリをレジストリにプッシュする方法を検討する準備が整います。

## BuildKit

バージョン 18.09 以降の Docker は [moby/buildkit](https://github.com/moby/buildkit) プロジェクトによって提供されるビルドを実行するための新しいバックエンドをサポートします。
BuildKit バックエンドには、古い実装と比較して多くの利点があります。
たとえば BuildKit は次のことができます。

* 未使用のビルドステージの実行を検出してスキップします
* ビルドの独立したビルドステージを並列化します
* ビルド間でビルドコンテキスト内の変更されたファイルのみを段階的に転送します
* ビルドコンテキストで未使用のファイルの転送を検出してスキップします
* 多くの新機能を備えた外部 Dockerfile 実装を使用します
* 残りの API(中間イメージとコンテナー)での副作用を回避します
* 自動プルーニングのためにビルドキャッシュに優先順位を付けます

BuildKit バックエンドを使用するには [docker build](https://qiita.com/JhonnyBravo/items/87976fe9de47ed58b8b1) を呼び出す前に、 CLI で環境変数 ``DOCKER_BUILDKIT=1`` を設定する必要があります。

BuildKit ベースのビルドで使用できる実験的な Dockerfile 構文については [BuildKit リポジトリのドキュメント](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md) を参照してください。

## Format

Dockerfile の形式は次のとおりです。

```bash
# Comment
INSTRUCTION arguments
```

命令では大文字と小文字は区別されません。
ただし、引数と区別しやすいように大文字にするのが慣例です。

Docker は Dockerfile 内の命令を順番に実行します。
Dockerfile は ``FROM`` 命令で始まる必要があります。
これは、パーサーディレクティブ、コメント、およびグローバルスコープの ``ARG`` の後にある可能性があります。
``FROM`` 命令は、構築元の親イメージを指定します。
``FROM`` の前には Dockerfile の ``FROM`` 行で使用される引数を宣言する 1 つ以上の ``ARG`` 命令のみを付けることができます。

Docker は行が有効なパーサーディレクティブでない限り ``#`` で始まる行をコメントとして扱います。
行内の他の場所にある ``#`` マーカーは、引数として扱われます。
これにより、次のようなステートメントが可能になります。

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

Dockerfile 命令が実行される前にコメント行が削除されます。
つまり次の例のコメントは、 ``echo`` コマンドを実行するシェルによって処理されません。
以下の両方の例は同等です。

```bash
RUN echo hello \
# comment
world
```

```bash
RUN echo hello \
world
```

行継続文字はコメントではサポートされていません。


>**空白に関する注意**

>下位互換性のために、コメント( ``#`` )および命令( ``RUN`` など)の前の先頭の空白は無視されますが、推奨されません。
>これらの場合、先頭の空白は保持されないため、次の例は同等です。

>```bash
>          # this is a comment-line
>    RUN echo hello
>RUN echo world
>```

>```bash
># this is a comment-line
>RUN echo hello
>RUN echo world
>```

>ただし ``RUN`` に続くコマンドなど、命令引数の空白は保持されるため、次の例では、先頭に空白を指定して ``    hello    world`` を出力します。

>```bash
>RUN echo "\
>     hello\
>     world"
>```

## パーサーディレクティブ

パーサーディレクティブはオプションであり、 Dockerfile の後続の行が処理される方法に影響を与えます。
パーサーディレクティブはビルドにレイヤーを追加せず、ビルドステップとして表示されません。
パーサーディレクティブは ``# directive=value`` の形式で特別なタイプのコメントとして記述されます。
1 つのディレクティブは 1 回だけ使用できます。

コメント、空の行、またはビルダー命令が処理されると、 Docker はパーサーディレクティブを検索しなくなります。
パーサーディレクティブとして記述されたものをコメントとして扱い、パーサーディレクティブである可能性があるかどうかの検証を試みません。
したがって、すべてのパーサーディレクティブは Dockerfile の最上部にある必要があります。

パーサーディレクティブでは大文字と小文字は区別されません。
ただし慣例では小文字にする必要があります。
慣例ではパーサーディレクティブの後に空白行を含めることもできます。
行継続文字は、パーサーディレクティブではサポートされていません。

これらの規則により、次の例はすべて無効です。

行継続のため無効

```bash
# direc \
tive=value
```

2 回表示されるため無効

```bash
# directive=value1
# directive=value2

FROM ImageName
```

ビルダーの指示の後に表示されるため、コメントとして扱われます。

```bash
FROM ImageName
# directive=value
```

パーサーディレクティブではないコメントの後に表示されるため、コメントとして扱われます。

```bash
# About my dockerfile
# directive=value
FROM ImageName
```

``unknowndirective`` は、認識されないためコメントとして扱われます。
さらに ``knowndirective`` は、パーサーディレクティブではないコメントの後に表示されるため、コメントとして扱われます。

```bash
# unknowndirective=value
# knowndirective=value
```

パーサーディレクティブでは、改行のない空白が許可されています。
したがって、次の行はすべて同じように扱われます。

```bash
#directive=value
# directive =value
#	directive= value
# directive = value
#	  dIrEcTiVe=value
```

次のパーサーディレクティブがサポートされています。

* syntax
* escape

### syntax

```bash
# syntax=[remote image reference]
```

例

```bash
# syntax=docker/dockerfile
# syntax=docker/dockerfile:1.0
# syntax=docker.io/docker/dockerfile:1
# syntax=docker/dockerfile:1.0.0-experimental
# syntax=example.com/user/repo:tag@sha256:abcdef...
```

この機能は BuildKit バックエンドが使用されている場合にのみ有効になります。

``syntax`` ディレクティブは、現在の Dockerfile のビルドに使用される Dockerfile ビルダーの場所を定義します。
BuildKit バックエンドを使用すると Docker イメージとして配布され、コンテナーサンドボックス環境内で実行されるビルダーの外部実装をシームレスに使用できます。

カスタム Dockerfile 実装により、次のことが可能になります。

* デーモンを更新せずにバグ修正を自動的に取得する
* すべてのユーザーが同じ実装を使用して Dockerfile をビルドしていることを保証できる
* デーモンを更新せずに最新の機能を使用することができる
* 新しい実験的またはサードパーティの機能を試すことができる

#### 公式リリース

Docker は DockerHub の docker/dockerfile リポジトリーに Dockerfile を構築するために使用できるイメージの公式バージョンを配布しています。
新しいイメージがリリースされるチャネルは、安定版と実験版の 2 つです。

安定版チャネルは、セマンティックバージョニングに従います。

例:

* docker/dockerfile:1.0.0 - 不変バージョン 1.0.0 のみを許可する
* docker/dockerfile:1.0 - バージョン 1.0.* を許可する
* docker/dockerfile:1 - versions 1.*.* を許可する
* docker/dockerfile:latest - 安定版チャネルの最新リリース

実験版チャネルは、リリース時の安定版チャネルからのメジャーコンポーネントとマイナーコンポーネントを使用したインクリメンタルバージョン管理を使用します。

例:

* docker/dockerfile:1.0.1-experimental - 不変バージョン 1.0.1-experimental のみを許可する
* docker/dockerfile:1.0-experimental - 1.0 以降の最新の実験版リリース
* docker/dockerfile:experimental - 実験版チャネルの最新リリース

ニーズに適したチャネルを選択する必要があります。
バグ修正のみが必要な場合は docker/dockerfile:1.0 を使用する必要があります。
実験的な機能を活用したい場合は、実験版チャネルを使用する必要があります。
実験チャネルを使用している場合、新しいリリースには下位互換性がない可能性があるため、不変のフルバージョンバリアントを使用することをお勧めします。

マスタービルドとナイトリー機能リリースについては [ソースリポジトリの説明](https://github.com/moby/buildkit/blob/master/README.md) を参照してください。

### escape

```bash
# escape=\ (backslash)
```

または

```bash
# escape=` (backtick)
```

エスケープディレクティブは Dockerfile 内の文字をエスケープするために使用される文字を設定します。
指定しない場合、デフォルトのエスケープ文字は ``\`` です。

エスケープ文字は、行内の文字をエスケープするためと、改行をエスケープするための両方に使用されます。
これにより Dockerfile 命令を複数行にまたがることができます。
``escape`` パーサーディレクティブが Dockerfile に含まれているかどうかに関係なく、エスケープは、行の終わりを除いて、 ``RUN`` コマンドでは実行されないことに注意してください。

エスケープ文字を「 \` 」に設定すると Windows で特に役立ちます。
ここでは ``\`` はディレクトリパスの区切り文字です。
「 \` 」は Windows PowerShell と一貫性があります。

Windows で自明ではない方法で失敗する次の例を考えてみましょう。
2 行目の終わりにある 2 番目の ``\`` は、最初の ``\`` からのエスケープのターゲットではなく、改行のエスケープとして解釈されます。
同様に 3 行目の終わりにある ``\`` は、実際に命令として処理されたとすると、行の継続として扱われます。
この dockerfile の結果は 2 行目と 3 行目が単一の命令と見なされることです。

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

実行結果:

```bash
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>
```

上記の解決策の 1 つは ``COPY`` 命令と ``dir`` の両方のターゲットとして ``/`` を使用することです。
ただし、この構文は Windows のパスでは自然ではないため混乱を招きます。
最悪の場合 Windows のすべてのコマンドがパス区切り文字として ``/`` をサポートしているわけではないため、エラーが発生しやすくなります。

``escape`` パーサーディレクティブを追加することにより、次の Dockerfile は Windows のファイルパスに自然なプラットフォームセマンティクスを使用して期待どおりに成功します。

```bash
# escape=`

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

実行結果:

```bash
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>
```

## 環境変数の置換

環境変数( ``ENV`` ステートメントで宣言)は、 Dockerfile によって解釈される変数として特定の命令で使用することもできます。
エスケープは、変数に似た構文をそのままステートメントに含めるためにも処理されます。

環境変数は Dockerfile で ``$variable_name`` または ``${variable_name}`` のいずれかで表記されます。
それらは同等に扱われ、中括弧構文は通常 ``${foo} _bar`` のように空白のない変数名の問題に対処するために使用されます。

``${variable_name}`` 構文は、以下に指定されている標準の bash 修飾子のいくつかもサポートしています。

* ``${variable:-word}`` は変数が設定されている場合、結果がその値になることを示します。
  変数が設定されていない場合 ``word`` が結果になります。
* ``${variable:+word}`` は、変数が設定されている場合は ``word`` が結果になり、それ以外の場合は結果が空の文字列になることを示します。

すべての場合において ``word`` は、追加の環境変数を含む任意の文字列にすることができます。

エスケープは変数の前に ``\`` を追加することで可能です。
たとえば  ``\$ foo`` または ``\${foo}`` は、 ``$foo`` と ``${foo}`` に変換されます。

例(解析された表現は ``#`` の後に表示されます):

```bash
FROM busybox
ENV FOO=/bar
WORKDIR ${FOO}   # WORKDIR /bar
ADD . $FOO       # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux
```

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

* [ADD](#add)
* [COPY](#copy)
* [ENV](#env)
* [EXPOSE](#expose)
* [FROM](#from)
* [LABEL](#label)
* [STOPSIGNAL](#stopsignal)
* [USER](#user)
* [VOLUME](#volume)
* [WORKDIR](#workdir)
* [ONBUILD](#onbuild) (上記のサポートされている手順の 1 つと組み合わせた場合)

環境変数の置換では、命令全体を通じて各変数に同じ値が使用されます。
言い換えると、この例では次のようになります。

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

結果は ``bye`` ではなく ``hello`` の値を持つ ``def`` になります。
ただし ``ghi`` は ``abc`` を ``bye`` に設定したのと同じ命令の一部ではないため、 ``bye`` の値になります。

## .dockerignore ファイル

docker CLI はコンテキストを docker デーモンに送信する前に、コンテキストのルートディレクトリで ``.dockerignore`` という名前のファイルを探します。
このファイルが存在する場合 CLI はコンテキストを変更して、その中のパターンに一致するファイルとディレクトリを除外します。
これにより、大きなファイルや機密性の高いファイルやディレクトリをデーモンに不必要に送信したり、 ``ADD`` または ``COPY`` を使用してイメージに追加したりすることを回避できます。

CLIは ``.dockerignore`` ファイルを Unix シェルのファイルグロブに似た改行で区切られたパターンのリストとして解釈します。
照合の目的で、コンテキストのルートは作業ディレクトリとルートディレクトリの両方であると見なされます。
たとえば、パターン ``/foo/bar`` と ``foo/bar`` はどちらも、 ``PATH`` の ``foo`` サブディレクトリまたは URL にある git リポジトリのルートにある ``bar`` という名前のファイルまたはディレクトリを除外します。
どちらも他のものを除外しません。

``.dockerignore`` ファイルの行が 1 列目の ``#`` で始まる場合、この行はコメントと見なされ、 CLI によって解釈される前に無視されます。

``.dockerignore`` ファイルの記述例を示します:

```bash
# comment
*/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`` ファイルの例です。

```bash
*.md
!README.md
```

``README.md`` を除くすべてのマークダウンファイルはコンテキストから除外されます。

``!`` 例外ルールの配置は、動作に影響を与えます。
特定のファイルに一致する ``.dockerignore`` の最後の行は、そのファイルが含まれるか除外されるかを決定します。
次の例を考えてみましょう。

```bash
*.md
!README*.md
README-secret.md
```

``README-secret.md`` 以外の ``README`` ファイルを除いて、マークダウンファイルはコンテキストに含まれていません。

ここで、この例を検討します。

```bash
*.md
README-secret.md
!README*.md
```

すべての ``README`` ファイルが含まれています。
``!README*.md`` は ``README-secret.md`` と一致し、最後に来るため、真ん中の行は効果がありません。

``.dockerignore`` ファイルを使用して Dockerfile ファイルと ``.dockerignore`` ファイルを除外することもできます。
これらのファイルは、そのジョブを実行する必要があるため、引き続きデーモンに送信されます。
ただし ``ADD`` および ``COPY`` 命令はそれらをイメージにコピーしません。

最後に、除外するファイルではなく、コンテキストに含めるファイルを指定することをお勧めします。
これを実現するには、最初のパターンとして ``*`` を指定し、その後に 1 つ以上の ``!`` 例外パターンを指定します。

>**注意**
>
>歴史的な理由から、パターン ``.`` は無視されます。


## FROM

```bash
FROM [--platform=<platform>] <image> [AS <name>]
```

または

```bash
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
```

または

```bash
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
```

``FROM`` 命令は、新しいビルドステージを初期化し、後続の命令のベースイメージを設定します。
そのため、有効な Dockerfile は ``FROM`` 命令で始まる必要があります。
イメージは任意の有効なイメージを指定することができます。
パブリックリポジトリからイメージを取得することから始めるのは特に簡単です。

* ``ARG`` は Dockerfile の ``FROM`` の前にある可能性がある唯一の命令です。
  [ ``ARG`` と ``FROM`` の相互作用を理解する](#arg-と-from-の相互作用を理解する) を参照してください。
* ``FROM`` は、単一の Dockerfile 内に複数回出現して、複数のイメージを作成したり、あるビルドステージを別のビルドステージの依存関係として使用したりできます。
  新しい ``FROM`` 命令の前に、 ``commit`` によって出力された最後のイメージ ID をメモするだけです。
  各 ``FROM`` 命令は、前の命令によって作成されたすべての状態をクリアします。
* オプションで ``FROM`` 命令に ``AS name`` を追加することにより、新しいビルドステージに名前を付けることができます。
  この名前は、後続の ``FROM`` および ``COPY --from=<name>`` 命令で使用して、このステージで作成されたイメージを参照できます。
* タグまたはダイジェスト値はオプションです。
  いずれかを省略すると、ビルダーはデフォルトで最新のタグを想定します。
  タグ値が見つからない場合、ビルダーはエラーを返します。

オプションの ``--platform`` フラグを使用して、 ``FROM`` がマルチプラットフォームイメージを参照する場合にイメージのプラットフォームを指定できます。
たとえば、 ``linux/amd64`` 、 ``linux/arm64`` 、または ``windows/amd64`` です。
デフォルトでは、ビルドリクエストのターゲットプラットフォームが使用されます。
このフラグの値にはグローバルビルド引数を使用できます。
たとえば、自動プラットフォーム引数を使用すると、ステージをネイティブビルドプラットフォームに強制し、それを使用してステージ内のターゲットプラットフォームにクロスコンパイルできます。
( ``--platform=$BUILDPLATFORM`` )

### ``ARG`` と ``FROM`` の相互作用を理解する

``FROM`` 命令は、最初の ``FROM`` の前に発生する ``ARG`` 命令によって宣言される変数をサポートします。

```bash
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`` 命令を使用します。

```bash
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`` コマンドを使用して変更できます。

シェル形式では、 ``\`` (バックスラッシュ)を使用して、単一の ``RUN`` 命令を次の行に続けることができます。
たとえば、次の 2 行について考えてみます。

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

これらを合わせると、次の 1 行に相当します。

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

``/bin/sh`` 以外の別のシェルを使用するには、目的のシェルを渡す ``exec`` 形式を使用します。例えば:

```bash
RUN ["/bin/bash", "-c", "echo hello"]
```


>**注意**
>
>``exec`` 形式は JSON 配列として解析されます。
>つまり一重引用符( ``'`` )ではなく、単語の前後に二重引用符( ``"`` )を使用する必要があります。

シェル形式とは異なり、 ``exec`` 形式はコマンドシェルを呼び出しません。
これは、通常のシェル処理が行われないことを意味します。
たとえば、 ``RUN ["echo", "$HOME"]`` は、 ``$HOME`` の変数置換を行いません。
シェル処理が必要な場合は、シェル形式を使用するか、シェルを直接実行します。
例: ``RUN ["sh", "-c", "echo $ HOME"]`` 。
シェル形式の場合のように、 ``exec`` 形式を使用してシェルを直接実行する場合、環境変数の展開を行うのは Docker ではなく、シェルです。

>**注意**
>
>JSON 形式では、バックスラッシュをエスケープする必要があります。
>これは、バックスラッシュがパス区切り文字である Windows に特に関係があります。
>次の行は、有効な JSON ではないため、シェル形式として扱われ、予期しない方法で失敗します:
>
>```bash
>RUN ["c:\windows\system32\tasklist.exe"]
>```
>
>この例の正しい構文は次のとおりです:
>
>```bash
>RUN ["c:\\windows\\system32\\tasklist.exe"]
>```

``RUN`` 命令のキャッシュは、次のビルド中に自動的に無効になることはありません。
``RUN apt-get dist-upgrade -y`` のような命令のキャッシュは、次のビルドで再利用されます。
``RUN`` 命令のキャッシュは ``--no-cache `` フラグを使用して無効にすることができます(例: ``docker build --no-cache`` )。

詳細については [Dockerfile ベストプラクティスガイド](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/) を参照してください。

``RUN`` 命令のキャッシュは、 ``ADD`` および ``COPY`` 命令によって無効にすることができます。

### 既知の問題( ``RUN`` )

* [イシュー 783](https://github.com/docker/docker/issues/783) は、 AUFS ファイルシステムの使用時に発生する可能性のあるファイル権限の問題に関するものです。
  たとえば、ファイルを ``rm`` しようとしたときに気付くかもしれません。
  最近の aufs バージョンがあるシステム(つまり ``dirperm1`` マウントオプションを設定できる)の場合、 docker は ``dirperm1`` オプションを使用してレイヤーをマウントすることで問題を自動的に修正しようとします。
  ``dirperm1`` オプションの詳細については [aufs の man ページ](https://github.com/sfjro/aufs3-linux/tree/aufs3.18/Documentation/filesystems/aufs) を参照してください。
  システムで ``dirperm1`` がサポートされていない場合、 [イシュー 783](https://github.com/docker/docker/issues/783) は回避策を説明しています。

## CMD

``CMD`` 命令は 3 つの形式を持ちます:

* ``CMD ["executable","param1","param2"]`` ( ``exec`` 形式。これが推奨される形式です)
* ``CMD ["param1","param2"]`` ( ``ENTRYPOINT`` へのデフォルトパラメータとして使用します)
* ``CMD command param1 param2`` (シェル形式)

Dockerfile には 1 つの ``CMD`` 命令しか存在できません。
複数の ``CMD`` を列記すると、最後の ``CMD`` のみが有効になります。

``CMD`` の主な目的は、実行中のコンテナに既定の動作を提供することです。
これらの既定の動作には、 ``executable`` を含めることも、 ``executable`` を省略することもできます。
``executable`` を省略する場合は ``ENTRYPOINT`` 命令も指定する必要があります。

``CMD`` を使用して ``ENTRYPOINT`` 命令のデフォルトの引数を提供する場合は、``CMD`` 命令と ``ENTRYPOINT`` 命令の両方を JSON 配列形式で指定する必要があります。


>**注意**
>
>``exec`` 形式は JSON 配列として解析されます。
>つまり単語の前後に一重引用符( ``'`` )ではなく、二重引用符( ``"`` )を使用する必要があります。

シェル形式とは異なり、 ``exec`` 形式はコマンドシェルを呼び出しません。
これは、通常のシェル処理が行われないことを意味します。
たとえば ``CMD ["echo", "$HOME"]`` は、 ``$HOME`` で変数置換を行いません。
シェル処理が必要な場合は、シェル形式を使用するか、シェルを直接実行します。
例: ``CMD ["sh"、 "-c"、 "echo $ HOME"]``
シェル形式の場合のように、 ``exec`` 形式を使用してシェルを直接実行する場合、環境変数の展開を行うのは Docker ではなく、シェルです。

シェル形式または ``exec`` 形式で使用する場合、 ``CMD`` 命令は、イメージの実行時に実行されるコマンドを設定します。

``CMD`` のシェル形式を使用する場合、 ``<command>`` は ``/bin/sh -c`` で実行されます:

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

シェルなしで ``<command>`` を実行したい場合は、コマンドを JSON 配列として表現し、 ``executable`` へのフルパスを指定する必要があります。
この配列形式は、 ``CMD`` の推奨フォーマットです。
追加のパラメータは、配列内の文字列として個別に表現する必要があります。

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

コンテナで毎回同じ ``executable`` を実行したい場合は、``ENTRYPOINT`` を ``CMD`` と組み合わせて使用​​することを検討する必要があります。
``ENTRYPOINT`` を参照してください。

ユーザーが [docker run](https://qiita.com/JhonnyBravo/items/eee5a91682f1d7c72f6e) の引数を指定すると、 ``CMD`` で指定された既定値が上書きされます。

>**注意**
>
>``RUN`` と ``CMD`` を混同しないでください。
>``RUN`` は実際にコマンドを実行し、結果をコミットします。
>``CMD`` はビルド時に何も実行しませんが、イメージに実行させたいコマンドを指定します。

## LABEL

```bash
LABEL <key>=<value> <key>=<value> <key>=<value> ...
```

``LABEL`` 命令はメタデータをイメージに追加します。
``LABEL`` はキーと値のペアです。
``LABEL`` の値にスペースを含めるには、コマンドライン解析の場合と同じように引用符とバックスラッシュを使用します。

使用例:

```bash
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."
```

イメージには複数のラベルを付けることができます。
1 行に複数のラベルを指定できます。
Docker 1.10 より前は、これにより最終イメージのサイズが小さくなりましたが、現在はそうではありません。
次の 2 つの方法のいずれかで、 1 つの命令で複数のラベルを指定することもできます。

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

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

ベースイメージまたは親イメージ( ``FROM`` 行のイメージ)に含まれるラベルは、子イメージに継承されます。
ラベルがすでに存在するが値が異なる場合、最後に適用された値が以前に設定された値を上書きします。

イメージのラベルを表示するには ``docker image inspect`` コマンドを使用します。
``--format`` オプションを使用してラベルのみを表示できます。

```bash
docker image inspect --format='' myimage
```

```bash
{
  "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 (非推奨)

```bash
MAINTAINER <name>
```

``MAINTAINER`` 命令は、生成されたイメージの ``Author`` フィールドを設定します。
``LABEL`` 命令は ``MAINTAINER`` よりもはるかに柔軟に必要なメタデータを設定できます。
代わりに ``LABEL`` を使用してください。
たとえば ``docker inspect`` を使用して簡単に表示できます。
``MAINTAINER`` フィールドに対応するラベルを設定するには:

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

これは、他のラベルとともに ``docker inspect`` から表示されます。

## EXPOSE

```bash
EXPOSE <port> [<port>/<protocol>...]
```

``EXPOSE`` 命令は、コンテナ実行時に指定されたネットワークポートで待受けすることを Docker に通知します。
ポートが TCP と UDP のどちらで待受けするかを指定できます。
プロトコルが指定されていない場合、既定値は TCP です。

``EXPOSE`` 命令は、実際にはポートを公開しません。
これは、イメージを作成する人とコンテナーを実行する人の間の一種のドキュメントとして機能し、ポートの公開が意図されています。
コンテナの実行時に実際にポートを公開するには、 [docker run](https://qiita.com/JhonnyBravo/items/eee5a91682f1d7c72f6e) で ``-p`` フラグを使用して 1 つ以上のポートを公開して紐づけするか、 ``-P`` フラグを使用して公開されたすべてのポートを公開し、それらを上位ポートに紐づけします。

デフォルトでは  ``EXPOSE`` は TCP を想定していますが、
UDP を指定することもできます。

```bash
EXPOSE 80/udp
```

TCP と UDP の両方で公開するには、次の 2 行を記述します。

```bash
EXPOSE 80/tcp
EXPOSE 80/udp
```

この場合 [docker run](https://qiita.com/JhonnyBravo/items/eee5a91682f1d7c72f6e) で ``-P`` を使用すると、ポートは TCP 用に 1 回、 UDP 用に 1 回公開されます。
``-P`` はホスト上で一時的な上位ホストポートを使用するため、ポートは TCP と UDP で同じではないことに注意してください。

``EXPOSE`` 設定に関係なく ``-p`` フラグを使用して実行時にそれらをオーバーライドできます。

例:

```bash
docker run -p 80:80/tcp -p 80:80/udp ...
```

ホストシステムでポートリダイレクションを設定するには ``-P`` フラグの使用を参照してください。
``docker network`` コマンドは、特定のポートを公開(expose または publish)する必要なしに、コンテナー間の通信用のネットワークの作成をサポートします。
これは、ネットワークに接続されたコンテナーが任意のポートを介して相互に通信できるためです。
詳細については、 [docker network 機能の概要](https://docs.docker.com/engine/userguide/networking/) を参照してください。

## ENV

```bash
ENV <key>=<value> ...
```

``ENV`` 命令は、環境変数 ``<key>`` を値 ``<value>`` に設定します。
この値は、ビルドステージの後続のすべての命令の環境にあり、多くの場合、インラインで置き換えることができます。
値は他の環境変数に対して解釈されるため、引用符がエスケープされていない場合は削除されます。
コマンドライン解析と同様に、引用符とバックスラッシュを使用して値にスペースを含めることができます。

例:

```bash
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
```

``ENV`` 命令では、複数の ``<key>=<value> ...`` 変数を一度に設定できます。
以下の例では、最終的なイメージで同じ最終結果が得られます。

```bash
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
    MY_CAT=fluffy
```

``ENV`` を使用して設定された環境変数は、結果のイメージからコンテナが実行されたときに保持されます。
``docker inspect`` を使用して値を表示し、 ``docker run --env <key>=<value>`` を使用して値を変更できます。

環境変数の永続性は、予期しない副作用を引き起こす可能性があります。
たとえば ``ENV DEBIAN_FRONTEND=noninteractive`` を設定すると、``apt-get`` の動作が変更され、イメージのユーザーを混乱させる可能性があります。

環境変数がビルド中にのみ必要であり、最終イメージでは必要ない場合は、代わりに単一のコマンドの値を設定することを検討してください。

```bash
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...
```

または最終的なイメージに保持されない ``ARG`` を使用します。

```bash
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y ...
```

>**代替記法**
>
>``ENV`` 命令では代替構文 ``ENV <key> <value>`` を使用でき、 ``=`` を省略できます。
>
>例:
>
>```bash
>ENV MY_VAR my-value
>```
>
>この構文では複数の環境変数を 1 つの ``ENV`` 命令に設定することはできず、混乱を招く可能性があります。
>たとえば次のように、単一の環境変数 ``ONE`` を値 ``"TWO = THREE = world"`` で設定します。
>
>```bash
>ENV ONE TWO= THREE=world
>```
>
>代替構文は下位互換性のためにサポートされていますが、上記の理由により推奨されておらず、将来のリリースで削除される可能性があります。

## ADD

``ADD`` は 2 つの形式を持ちます:

```bash
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
```

空白を含むパスには後者の形式が必要です。

>**注意**
>
>``--chown`` 機能は Linux コンテナの構築に使用される Dockerfile でのみサポートされており、 Windows コンテナでは機能しません。
>ユーザーとグループの所有権の概念は Linux と Windows の間で変換されないため、ユーザー名とグループ名を ID に変換するために ``/etc/passwd`` と ``/etc/group`` を使用すると、この機能は Linux OS ベースのコンテナである場合に限り実行可能に制限されます。

``ADD`` 命令は、新しいファイル、ディレクトリ、またはリモートファイルの URL を ``<src>`` からコピーし、パス ``<dest>`` でイメージのファイルシステムに追加します。

複数の ``<src>`` リソースを指定できますが、それらがファイルまたはディレクトリの場合、パスはビルドのコンテキストのソースからの相対パスとして解釈されます。

各 ``<src>`` にはワイルドカードを含めることができ、照合は Go の ``filepath.Match`` ルールを使用して行われます。
例えば ``hom`` で始まるすべてのファイルを追加するには:

```bash
ADD hom* /mydir/
```

以下の例では ``?`` は ``home.txt`` などの任意の 1 文字に置き換えられています。

```bash
ADD hom?.txt /mydir/
```

``<dest>`` は絶対パス、または ``WORKDIR`` から見た相対パスであり、ソースは宛先コンテナ内にコピーされます。

以下の例では、相対パスを使用して ``test.txt`` を ``<WORKDIR>/relativeDir/`` に追加しています:

```bash
ADD test.txt relativeDir/
```

この例では絶対パスを使用して ``test.txt`` を ``/abstractDir/`` に追加します。

```bash
ADD test.txt /absoluteDir/
```

特殊文字( ``[`` や ``]`` など)を含むファイルやディレクトリを追加する場合は、一致するパターンとして扱われないように、 Go 言語のルールに従ってこれらのパスをエスケープする必要があります。
たとえば、 ``arr[0].txt`` という名前のファイルを追加するには、次を使用します。

```bash
ADD arr[[]0].txt /mydir/
```

追加されたコンテンツの特定の所有権を要求するために、オプションの ``--chown`` フラグが特定のユーザー名、グループ名、またはUID / GIDの組み合わせを指定しない限り、すべての新しいファイルとディレクトリは UID と GID が 0 で作成されます。
``--chown`` フラグの形式では、ユーザー名とグループ名の文字列、または直接整数の UID と GID を任意の組み合わせで使用できます。
グループ名なしのユーザー名または GID なしの UID を指定すると、 GID と同じ数値の UID が使用されます。
ユーザー名またはグループ名が指定されている場合、コンテナのルートファイルシステムの ``/etc/passwd`` ファイルと``/etc/group`` ファイルを使用して、名前から整数の UID または GID への変換がそれぞれ実行されます。
次の例は、 ``--chown`` フラグの有効な定義を示しています。

```bash
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
```

コンテナルートファイルシステムに ``/etc/passwd`` または ``/etc/group``ファイルが含まれておらず、ユーザー名またはグループ名が ``--chown``フラグで使用されている場合、 ``ADD`` 操作でビルドは失敗します。
数値 ID の使用はルックアップを必要とせず、コンテナルートファイルシステムのコンテンツに依存しません。

``<src>`` がリモートファイルの URL の場合、宛先には 600 の権限があります。
取得するリモートファイルに HTTP Last-Modified ヘッダーがある場合、そのヘッダーのタイムスタンプを使用して、宛先ファイルの mtime を設定します。
ただし ``ADD`` 中に処理される他のファイルと同様に、 mtime は、ファイルが変更されたかどうかの判断には含まれず、キャッシュを更新する必要があります。

>**注意**
>
>Dockerfile を ``STDIN`` ( `` docker build- <somefile`` )に渡してビルドする場合、ビルドコンテキストがないため、 Dockerfile には URL ベースの ``ADD`` 命令のみを含めることができます。
>圧縮されたアーカイブを ``STDIN`` : ( ``docker build- <archive.tar.gz`` )を介して渡すこともできます。アーカイブのルートにある Dockerfile と、アーカイブの残りの部分がビルドのコンテキストとして使用されます。

URL ファイルが認証を使用して保護されている場合、 ``ADD`` 命令は認証をサポートしていないため、 ``RUN wget`` や ``RUN curl`` を使用するか、コンテナ内から別のツールを使用する必要があります。

>**注意**
>
>最初に検出された ``ADD`` 命令は、 ``<src>`` の内容が変更された場合、 Dockerfile からの後続のすべての命令のキャッシュを無効にします。
>これには ``RUN`` 命令のキャッシュの無効化が含まれます。
>詳細については [Dockerfile ベストプラクティスガイド – ビルドキャッシュを活用する](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache) を参照してください。

``ADD`` は次のルールに従います。

* ``<src>`` パスはビルドのコンテキスト内にある必要があります。
  [docker build](https://qiita.com/JhonnyBravo/items/87976fe9de47ed58b8b1) の最初のステップはコンテキストディレクトリ(およびサブディレクトリ)を docker デーモンに送信することであるため、 ``ADD ../something / something`` はできません。
* ``<src>`` が URL であり、 ``<dest>`` が末尾のスラッシュで終わっていない場合、ファイルは URL からダウンロードされ、 ``<dest>`` にコピーされます。
* ``<src>`` が URL で、 ``<dest>`` が末尾にスラッシュで終わっている場合、ファイル名は URL から推測され、ファイルは ``<dest>/<filename>`` にダウンロードされます。
  たとえば、 ``ADD http://example.com/foobar /`` はファイル ``/foobar``を作成します。
  この場合、適切なファイル名を検出できるように URL には重要なパスが必要です( ``http://example.com`` は機能しません)。
* ``<src>`` がディレクトリの場合、ファイルシステムのメタデータを含むディレクトリの内容全体がコピーされます。

>**注意**
>
>ディレクトリ自体はコピーされず、その内容だけがコピーされます。

* ``<src>`` が認識された圧縮形式( ``gzip`` , ``bzip2`` または ``xz`` )のローカル tar アーカイブである場合、ディレクトリとして解凍されます。
  リモート URL からのリソースは解凍されません。
  ディレクトリがコピーまたは解凍されると ``tar -x`` と同じ動作になり、結果は次の和集合になります。
  1. 宛先パスに存在するものは何でも
  2. 競合するソースツリーの内容はファイルごとに ``2`` を優先して解決されます。

>**注意**
>
>ファイルが認識された圧縮形式として識別されるかどうかは、ファイルの名前ではなく、ファイルの内容のみに基づいて行われます。
>たとえば、空のファイルがたまたま ``.tar.gz`` で終わっている場合、これは圧縮ファイルとして認識されず、解凍エラーメッセージは生成されず、ファイルは単に宛先にコピーされます。

* ``<src>`` が他の種類のファイルの場合、メタデータとともに個別にコピーされます。
  この場合 ``<dest>`` の末尾にスラッシュ ``/`` が付いていると、ディレクトリと見なされ、 ``<src>`` の内容は ``<dest>/base(<src>)`` に書き込まれます。
* 直接またはワイルドカードの使用により複数の ``<src>`` リソースが指定されている場合、 ``<dest>`` はディレクトリである必要があり、スラッシュ ``/`` で終了する必要があります。
* ``<dest>`` が末尾のスラッシュで終わっていない場合、それは通常のファイルと見なされ、 ``<src>`` の内容は ``<dest>`` に書き込まれます。
* ``<dest>`` が存在しない場合は、パスに欠落しているすべてのディレクトリとともに作成されます。

## COPY

``COPY`` は 2 つの形式を持ちます:

```bash
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
```

後者の形式は、空白を含むパスに必要です。

>**注意**
>
>``--chown`` 機能は Linux コンテナの構築に使用される Dockerfile でのみサポートされており、 Windows コンテナでは機能しません。
>ユーザーとグループの所有権の概念は Linux と Windows の間で変換されないため、ユーザー名とグループ名を ID に変換するために ``/etc/passwd`` と ``/etc/group`` を使用します。
>この機能は Linux OS ベースのコンテナである場合に限り実行可能に制限されます。 

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

複数の ``<src>`` リソースを指定できますが、ファイルとディレクトリのパスは、ビルドのコンテキストのソースから見た相対パスとして解釈されます。

各 ``<src>`` にはワイルドカードを含めることができ、照合は Go の ``filepath.Match`` ルールを使用して行われます。
例えば ``hom`` で始まるすべてのファイルを追加するには:

```bash
COPY hom* /mydir/
```

以下の例では ``?`` は ``home.txt`` などの任意の 1 文字に置き換えられています。

```bash
COPY hom?.txt /mydir/
```

``<dest>`` は絶対パス、または ``WORKDIR`` に相対的なパスであり、ソースは宛先コンテナ内にコピーされます。

以下の例では相対パスを使用して ``test.txt`` を ``<WORKDIR>/relativeDir/`` に追加しています。

```bash
COPY test.txt relativeDir/
```

この例では絶対パスを使用して ``test.txt`` を ``/abstractDir/`` に追加します。

```bash
COPY test.txt /absoluteDir/
```

特殊文字( ``[`` や ``]`` など)を含むファイルやディレクトリをコピーする場合は、Go 言語のルールに従ってこれらのパスをエスケープして、一致するパターンとして扱われないようにする必要があります。
たとえば、 ``arr[0].txt`` という名前のファイルをコピーするには、次を使用します。

```bash
COPY arr[[]0].txt /mydir/
```

オプションの ``--chown`` フラグが、コピーされたコンテンツの特定の所有権を要求するために特定のユーザー名、グループ名、またはUID / GIDの組み合わせを指定しない限り、すべての新しいファイルとディレクトリは UID と GID が 0 で作成されます。
``--chown`` フラグの形式では、ユーザー名とグループ名の文字列、または直接整数の UID と GID を任意の組み合わせで使用できます。
グループ名なしのユーザー名または GID なしの UID を指定すると、 GID と同じ数値の UID が使用されます。
ユーザー名またはグループ名が指定されている場合、コンテナのルートファイルシステムの ``/etc/passwd`` ファイルと ``/etc/group`` ファイルを使用して、名前から整数の UID または GID への変換がそれぞれ実行されます。
次の例は、 ``--chown`` フラグの有効な定義を示しています。

```bash
COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/
```

コンテナのルートファイルシステムに ``/etc/passwd`` または ``/etc/group`` ファイルが含まれておらず、ユーザー名またはグループ名が ``--chown`` フラグで使用されている場合、ビルドは ``COPY`` 操作で失敗します。
数値 ID の使用はルックアップを必要とせず、コンテナルートファイルシステムのコンテンツに依存しません。

>**注意**
>
>``STDIN`` ( ``docker build- < somefile`` )を使用してビルドする場合、ビルドコンテキストがないため ``COPY`` は使用できません。

オプションで ``COPY`` は、ソースの場所を前のビルドステージ( ``FROM .. AS <name>`` で作成)に設定するために使用できるフラグ ``--from=<name>`` を受け入れます。
ユーザーが送信するビルドコンテキストの代わりに使用されます。
指定された名前のビルドステージが見つからない場合は、代わりに同じ名前のイメージが使用されます。

``COPY`` は次のルールに従います:

* ``<src>`` パスはビルドのコンテキスト内にある必要があります。
  ``dockerbuild`` の最初のステップはコンテキストディレクトリ(およびサブディレクトリ)を docker デーモンに送信することであるため、``COPY ../something /something`` はできません。
* ``<src>`` がディレクトリの場合、ファイルシステムのメタデータを含むディレクトリの内容全体がコピーされます。

>**注意**
>
>ディレクトリ自体はコピーされず、その内容だけがコピーされます。

* ``<src>`` がディレクトリ以外の種類のファイルの場合、メタデータとともに個別にコピーされます。
  この場合 ``<dest>`` の末尾にスラッシュ ``/`` が付いていると、ディレクトリと見なされ、 ``<src>`` の内容は ``<dest>/base(<src>)`` に書き込まれます。
* 直接またはワイルドカードの使用により複数の ``<src>`` リソースが指定されている場合、 ``<dest>`` はディレクトリである必要があり、スラッシュ ``/`` で終了する必要があります。
* ``<dest>`` が末尾のスラッシュで終わっていない場合、それは通常のファイルと見なされ、 ``<src>`` の内容は ``<dest>`` に書き込まれます。
* ``<dest>`` が存在しない場合は、パスに欠落しているすべてのディレクトリとともに作成されます。

>**注意**
>
>最初に検出された ``COPY`` 命令は ``<src>`` の内容が変更された場合、 Dockerfile からの後続のすべての命令のキャッシュを無効にします。
>これには ``RUN`` 命令のキャッシュの無効化が含まれます。
>詳細については [Dockerfile ベストプラクティスガイド – ビルドキャッシュを活用する](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache) を参照してください。

## ENTRYPOINT

``ENTRYPOINT`` は 2 つの形式を持ちます:

推奨形式は ``exec`` 形式です:

```bash
ENTRYPOINT ["executable", "param1", "param2"]
```

シェル形式:

```bash
ENTRYPOINT command param1 param2
```

``ENTRYPOINT`` を使用すると、 ``executable`` が実行されるコンテナを構成できます。

たとえば次の例では、 nginx をデフォルトのコンテンツで開始し、ポート 80 で待受けます。

```bash
$ 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`` またはコマンドライン引数の実行が使用されなくなりますが、 ``ENTRYPOINT`` が信号を渡さない ``/bin/sh -c`` のサブコマンドとして開始されるという欠点があります。
これは ``executable`` がコンテナの PID 1 ではなく、 Unix シグナルを受信しないことを意味します。
したがって ``executable`` は ``docker stop <container>`` から``SIGTERM`` を受信しません。

Dockerfile の最後の ``ENTRYPOINT`` 命令のみが有効になります。

### Exec 形式の ``ENTRYPOINT`` の例

``exec`` 形式の ``ENTRYPOINT`` を使用して、かなり安定したデフォルトのコマンドと引数を設定してから、いずれかの形式の ``CMD`` を使用して、変更される可能性が高い追加の既定動作を設定できます。

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

コンテナを実行すると ``top`` が唯一のプロセスであることがわかります。

```bash
$ 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`` を使用できます。

```bash
$ 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 として)実行する方法を示しています。

```bash
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"]
```

単一の ``executable`` のスタータースクリプトを作成する必要がある場合は ``exec`` および ``gosu`` コマンドを使用して、最後の ``executable``が Unix シグナルを確実に受信できるようにすることができます。

```bash
#!/usr/bin/env 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 "$@"
```

最後に、シャットダウン時に追加のクリーンアップを実行する(または他のコンテナと通信する)必要がある場合、または複数の ``executable`` を調整する場合は、 ``ENTRYPOINT`` スクリプトが Unix シグナルを送受信してさらにいくつかの作業を実行することを確認する必要があります。

```bash
#!/bin/sh
# Note: I've written this using sh so it works in the busybox container too

# USE the trap if you need to also do manual cleanup after the service is stopped,
#     or need to start multiple services in the one container
trap "echo TRAPed signal" HUP INT QUIT TERM

# start service in background here
/usr/sbin/apachectl start

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

# stop service and clean up here
echo "stopping apache"
/usr/sbin/apachectl stop

echo "exited $0"
```

このイメージを ``dockerrun -it --rm -p 80:80 --name test apache`` で実行すると、 ``docker exec`` または ``docker top`` でコンテナーのプロセスを調べることができ、後続のスクリプトに Apache を停止するように依頼します。

```bash
$ 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`` 設定を上書きできますが、これは ``binary`` を ``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](https://qiita.com/JhonnyBravo/items/eee5a91682f1d7c72f6e) コマンドライン引数を無視します。
長時間実行されている ``ENTRYPOINT executable`` を ``docker stop`` が正しく通知するようにするには、 ``exec`` で開始することを忘れないでください。

```bash
FROM ubuntu
ENTRYPOINT exec top -b
```

このイメージを実行すると単一の PID 1 プロセスが表示されます。

```bash
$ 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`` できれいに終了します:

```bash
$ /usr/bin/time docker stop test

test
real	0m 0.20s
user	0m 0.02s
sys	0m 0.04s
```

``ENTRYPOINT`` の先頭に ``exec`` を追加するのを忘れた場合:

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

次にそれを実行できます(次のステップの名前を付けます)。

```bash
$ 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`` を送信します。

```bash
$ 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`` 命令はどちらも、コンテナの実行時に実行されるコマンドを定義します。
``CMD`` と ``ENTRYPOINT`` の協業を説明する規則を示します。

1. Dockerfile は少なくとも 1 つの ``CMD`` または ``ENTRYPOINT`` コマンドを指定する必要があります。
2. コンテナで ``executable`` を使用する場合は ``ENTRYPOINT`` を定義する必要があります。
3. ``CMD`` は ``ENTRYPOINT`` コマンドのデフォルト引数を定義する方法として、またはコンテナでアドホックコマンドを実行する方法として使用する必要があります。
4. 代替引数を使用してコンテナーを実行すると ``CMD`` が上書きされます。

次の表はさまざまな ``ENTRYPOINT`` / ``CMD`` の組み合わせに対して実行されるコマンドを示しています。

| No ENTRYPOINT | ENTRYPOINT exec_entry p1_entry | ENTRYPOINT [“exec_entry”, “p1_entry”] |
|---------------|--------------------------------|-------------------------------------------|
| No CMD | error, not allowed | /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_entry p1_entry exec_cmd p1_cmd |
| CMD [“p1_cmd”, “p2_cmd”] | p1_cmd p2_cmd | /bin/sh -c exec_entry p1_entry | 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 | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |

>**注意**
>
>ベースイメージから ``CMD`` が定義されている場合、 ``ENTRYPOINT`` を設定すると ``CMD`` が空の値にリセットされます。
>このシナリオで値を設定するには現在のイメージで ``CMD`` を定義する必要があります。

## VOLUME

```bash
VOLUME ["/data"]
```

``VOLUME`` 命令は、指定された名前でマウントポイントを作成し、ネイティブホストまたは他のコンテナーから外部にマウントされたボリュームを保持するものとしてマークします。
値は JSON 配列 ``VOLUME ["/var/log/"]``、または ``VOLUME /var/log`` や 
 ``VOLUME /var/log/ var/db`` などの複数の引数を持つプレーン文字列にすることができます。
Docker クライアントを介した詳細、使用例とマウント手順については [ボリュームを介したディレクトリの共有](https://docs.docker.com/storage/volumes/) を参照してください。

[docker run](https://qiita.com/JhonnyBravo/items/eee5a91682f1d7c72f6e) コマンドは、新しく作成されたボリュームをベースイメージ内の指定された場所に存在するデータで初期化します。
たとえば、次の Dockerfile スニペットについて考えてみます。

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

この Dockerfile は [docker run](https://qiita.com/JhonnyBravo/items/eee5a91682f1d7c72f6e) が ``/myvol`` に新しいマウントポイントを作成し、新しく作成されたボリュームに ``greeting`` ファイルをコピーするイメージになります。

### ボリュームの指定についての注意事項

Dockerfile のボリュームについては、次の点に注意してください。

* Windows ベースのコンテナー上のボリューム: Windows ベースのコンテナーを使用する場合、コンテナー内のボリュームの宛先は次のいずれかである必要があります。
  * 存在しない、または空のディレクトリ
  * ``C:`` 以外のドライブ
* Dockerfile 内からのボリュームの変更: ビルドステップで宣言後にボリューム内のデータが変更された場合、それらの変更は破棄されます。
* JSON フォーマット: リストは JSON 配列として解析されます。
  単語は一重引用符（ ``'`` ）ではなく二重引用符（ ``"`` ）で囲む必要があります。
* ホストディレクトリはコンテナの実行時に宣言されます。
  ホストディレクトリ(マウントポイント)はその性質上、ホストに依存します。
  特定のホストディレクトリがすべてのホストで使用可能であるとは限らないため、これはイメージの移植性を維持するためです。
  このため Dockerfile 内からホストディレクトリをマウントすることはできません。
  ``VOLUME`` 命令は ``host-dir`` パラメーターの指定をサポートしていません。
  コンテナを作成または実行するときに、マウントポイントを指定する必要があります。

## USER

```bash
USER <user>[:<group>]
```

または

```bash
USER <UID>[:<GID>]
```

``USER`` 命令はイメージの実行時と、 Dockerfileで ``RUN`` 、 ``CMD`` 、 ``ENTRYPOINT`` に続く命令で使用するユーザー名(または UID)とオプションでユーザーグループ(またはGID)を設定します。

ユーザーのグループを指定する場合、ユーザーは指定されたグループメンバーシップのみを持つことに注意してください。
その他の構成済みグループメンバーシップは無視されます。

>**警告**
>
>ユーザーがプライマリグループを持っていない場合、イメージ(または次の手順)はルートグループで実行されます。
>
>Windows では、組み込みアカウントでない場合は最初にユーザーを作成する必要があります。
>これは Dockerfile の一部として呼び出される ``netuser`` コマンドを使用して実行できます。

```bash
FROM microsoft/windowsservercore
# Create Windows user in the container
RUN net user /add patrick
# Set it for subsequent commands
USER patrick
```

## WORKDIR

```bash
WORKDIR /path/to/workdir
```

``WORKDIR`` 命令は、 Dockerfile でそれに続くすべての ``RUN`` 、 ``CMD`` 、 ``ENTRYPOINT`` 、 ``COPY`` 、および` ``ADD`` 命令の作業ディレクトリを設定します。
``WORKDIR`` が存在しない場合は、後続の Dockerfile 命令で使用されていなくても作成されます。

``WORKDIR`` 命令は Dockerfile で複数回使用できます。
相対パスが指定されている場合、それは前の ``WORKDIR`` 命令のパスから見た相対パスになります。例えば:

```bash
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
```

この Dockerfile の最後の ``pwd`` コマンドの出力は ``/a/b/c`` になります。

``WORKDIR`` 命令は、以前に ``ENV`` を使用して設定された環境変数を解決できます。
Dockerfile で明示的に設定された環境変数のみを使用できます。
例えば:

```bash
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
```

この Dockerfile の最後の ``pwd`` コマンドの出力は ``/path/$DIRNAME`` になります。

## ARG

```bash
ARG <name>[=<default value>]
```

``ARG`` 命令はユーザーがビルド時に ``--build-arg <varname>=<value>` ` フラグを使用して [docker build](https://qiita.com/JhonnyBravo/items/87976fe9de47ed58b8b1) コマンドでビルダーに渡すことができる変数を定義します。
ユーザーが Dockerfile で定義されていないビルド引数を指定すると、ビルドは警告を出力します。

```bash
[Warning] One or more build-args [foo] were not consumed.
```

Dockerfile には 1 つ以上の ``ARG`` 命令が含まれる場合があります。
たとえば以下は有効な Dockerfile です。

```bash
FROM busybox
ARG user1
ARG buildno
# ...
```


>**警告**
>
>github のキー、ユーザー資格情報などの秘密情報を渡すためにビルド時変数を使用することはお勧めしません。
>ビルド時の変数値は ``docker history`` コマンドを使用してイメージのすべてのユーザーに表示されます。
>
>イメージをビルドするときに秘密情報を使用する安全な方法については [BuildKit を使用してイメージをビルドする](https://docs.docker.com/develop/develop-images/build_enhancements/#new-docker-build-secret-information) を参照してください。


### 既定値

``ARG`` 命令には、オプションでデフォルト値を含めることができます。

```bash
FROM busybox
ARG user1=someuser
ARG buildno=1
# ...
```

``ARG`` 命令にデフォルト値があり、ビルド時に値が渡されない場合、ビルダーはデフォルトを使用します。

### Scope

``ARG`` 変数の定義は、コマンドラインや他の場所での引数の使用からではなく、 Dockerfile で定義されている行から有効になります。
たとえば、次の Dockerfile について考えてみます。

```bash
FROM busybox
USER ${user:-some_user}
ARG user
USER $user
# ...
```

ユーザーは、次のコマンドを呼び出してこのファイルをビルドします。

```bash
$ docker build --build-arg user=what_user .
```

2 行目の ``USER`` は、次の 3 行目でユーザー変数が定義されているため ``some_user`` と評価されます。
4 行目の ``USER`` は、ユーザーが定義され、 ``what_user`` 値がコマンドラインに渡されたときに ``what_user`` と評価されます。
``ARG`` 命令で定義される前は、変数を使用すると文字列が空になります。

``ARG`` 命令は、それが定義されたビルドステージの最後でスコープ外になります。
複数のステージで ``arg`` を使用するには、各ステージに ``ARG`` 命令を含める必要があります。

```bash
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 について考えてみます。

```bash
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=v1.0.0
RUN echo $CONT_IMG_VER
```

次に、このイメージが次のコマンドで作成されていると仮定します。

```bash
$ docker build --build-arg CONT_IMG_VER=v2.0.1 .
```

この場合 ``RUN`` 命令は ``user:v2.0.1`` によって渡された ``ARG`` 設定の代わりに v1.0.0 を使用します。
この動作は、ローカルスコープの変数が引数として渡された変数または環境から継承された変数を定義の観点から上書きするシェルスクリプトに似ています。

上記の例を使用しますが、異なる ``ENV`` 仕様を使用すると、 ``ARG`` と ``ENV`` 命令の間にさらに便利な相互作用を作成できます。

```bash
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](https://qiita.com/JhonnyBravo/items/87976fe9de47ed58b8b1) を考えてみましょう:

```bash
$ docker build .
```

この Dockerfile の例を使用すると ``CONT_IMG_VER`` は引き続きイメージに保持されますが、 ``ENV`` 命令によって 3 行目で設定された既定値であるため、その値は v1.0.0 になります。

この例の変数展開手法を使用すると、コマンドラインから引数を渡し、 
 ``ENV`` 命令を利用してそれらを最終イメージに永続化できます。
変数展開は Dockerfile 命令の限られた組合せでのみサポートされます。

### 定義済み ``ARG``

Docker には Dockerfile 内の対応する ``ARG`` 命令なしで使用できる定義済み ``ARG`` 変数のセットがあります。

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

これらを使用するには、フラグを使用してコマンドラインで渡すだけです。

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

デフォルトでは、これらの定義済み変数は ``docker history`` の出力から除外されます。
定義済み変数を除外すると、 ``HTTP_PROXY`` 変数内の機密認証情報が誤って漏洩するリスクが軽減されます。

たとえば ``--build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com`` を使用して次の Dockerfile をビルドすることを検討してください。

```bash
FROM ubuntu
RUN echo "Hello World"
```

この場合 ``HTTP_PROXY`` 変数の値は、 ``docker history`` で使用できず、キャッシュされません。
場所を変更し、プロキシサーバーが ``http://user:pass@proxy.sfo.example.com`` に変更された場合、後続のビルドでキャッシュミスが発生することはありません。

この動作を上書きする必要がある場合は、次のように Dockerfile に ``ARG`` ステートメントを追加することで上書きできます。

```bash
FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"
```

この Dockerfile をビルドすると、 ``HTTP_PROXY`` は ``docker history`` に保存され、その値を変更するとビルドキャッシュが無効になります。

### グローバルスコープの自動プラットフォーム ARG

この機能は BuildKit バックエンドを使用している場合にのみ使用できます。

Docker は、ビルドを実行するノードのプラットフォーム(ビルドプラットフォーム)と結果のイメージのプラットフォーム(ターゲットプラットフォーム)に関する情報を使用して、一連の ``ARG`` 変数を事前定義します。
ターゲットプラットフォームは [docker build](https://qiita.com/JhonnyBravo/items/87976fe9de47ed58b8b1) の ``--platform`` フラグで指定できます。

次の ``ARG`` 変数が自動的に設定されます。


* TARGETPLATFORM - ビルド結果のプラットフォーム。
  例: linux/amd64, linux/arm/v7, windows/amd64.
* TARGETOS - TARGETPLATFORM の OS コンポーネント
* TARGETARCH - TARGETPLATFORM のアーキテクチャーコンポーネント
* TARGETVARIANT - TARGETPLATFORM の変数コンポーネント
* BUILDPLATFORM - ビルドを実行するノードのプラットフォーム。
* BUILDOS - BUILDPLATFORM の OS コンポーネント
* BUILDARCH - BUILDPLATFORM のアーキテクチャーコンポーネント
* BUILDVARIANT - BUILDPLATFORM の変数コンポーネント

これらの引数はグローバルスコープで定義されているため、ビルドステージ内や ``RUN`` コマンドで自動的に使用することはできません。
ビルドステージ内でこれらの引数の 1 つを公開するには、値なしで再定義します。

例えば:

```bash
FROM alpine
ARG TARGETPLATFORM
RUN echo "I'm building for $TARGETPLATFORM"
```

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

``ARG`` 変数は、 ``ENV`` 変数のようにビルドされたイメージに永続化されません。
ただし ``ARG`` 変数は同様の方法でビルドキャッシュに影響を与えます。
Dockerfile が以前のビルドとは値が異なる ``ARG`` 変数を定義している場合、その定義ではなく、最初の使用時に ``cache miss`` が発生します。
特に ``ARG`` 命令に続くすべての ``RUN`` 命令は、 ``ARG`` 変数を暗黙的に(環境変数として)使用するため、キャッシュミスを引き起こす可能性があります。
Dockerfile に一致する ``ARG`` ステートメントがない限り、すべての定義済み ``ARG`` 変数はキャッシュから除外されます。

たとえば次の 2 つの Dockerfile について考えてみます。

```bash
FROM ubuntu
ARG CONT_IMG_VER
RUN echo $CONT_IMG_VER
```

```bash
FROM ubuntu
ARG CONT_IMG_VER
RUN echo hello
```

コマンドラインで ``--build-arg CONT_IMG_VER=<value>`` を指定した場合、どちらの場合も、 2 行目の指定でキャッシュミスは発生しません。
3 行目はキャッシュミスを引き起こします。
``ARG CONT_IMG_VER`` により、 ``RUN`` 行は ``CONT_IMG_VER=<value> echo hello`` の実行と同じものとして識別されるため、 ``<value>`` が変更されるとキャッシュミスが発生します。

同じコマンドラインで別の例を考えてみましょう。

```bash
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=$CONT_IMG_VER
RUN echo $CONT_IMG_VER
```

この例ではキャッシュミスは 3 行目で発生します。
キャッシュミスは ``ENV`` 変数の値が ``ARG`` 変数を参照し、その変数がコマンドラインで変更されるために発生します。
この例では ``ENV`` コマンドにより、イメージに値が含まれます。

この Dockerfile のように、 ``ENV`` 命令が同じ名前の ``ARG`` 命令を上書きする場合:

```bash
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=hello
RUN echo $CONT_IMG_VER
```

3 行目では ``CONT_IMG_VER`` の値が定数(hello)であるため、キャッシュミスは発生しません。
その結果 ``RUN`` (4 行目)で使用される環境変数と値はビルド間で変更されません。

## ONBUILD

```bash
ONBUILD <INSTRUCTION>
```

``ONBUILD`` 命令はイメージが別のビルドのベースとして使用されるときに、後で実行されるトリガー命令をイメージに追加します。
トリガーは、ダウンストリーム Dockerfile の ``FROM`` 命令の直後に挿入されたかのように、ダウンストリームビルドのコンテキストで実行されます。

任意のビルド命令をトリガーとして登録できます。

これは他のイメージをビルドするためのベースとして使用されるイメージをビルドする場合に役立ちます。
たとえばアプリケーションビルド環境や、ユーザー固有の構成でカスタマイズできるデーモンなどです。

たとえばイメージが再利用可能な Python アプリケーションビルダーである場合、特定のディレクトリにアプリケーションソースコードを追加する必要があり、その後にビルドスクリプトを呼び出す必要がある場合があります。
アプリケーションのソースコードにはまだアクセスできず、アプリケーションのビルドごとに異なるため、今は単純に ``ADD`` と ``RUN`` を呼び出すことはできません。
アプリケーション開発者にボイラープレート Dockerfile を提供して、アプリケーションにコピーアンドペーストすることもできますが、
これは非効率的で、エラーが発生しやすく、アプリケーション固有のコードと混在するため、更新が困難です。

解決策は ``ONBUILD`` を使用して、次のビルドステージで後で実行する事前命令を登録することです。

仕組みは次のとおりです。

1. ``ONBUILD`` 命令が発生すると、ビルダーはビルド中のイメージのメタデータにトリガーを追加します。
   それ以外の場合、命令は現在のビルドに影響を与えません。
2. ビルドの最後に、すべてのトリガーのリストがイメージマニフェストの ``OnBuild`` キーの下に保存されます。
   それらは ``docker inspect`` コマンドで検査できます。
3. 後で ``FROM`` 命令を使用して、イメージを新しいビルドのベースとして使用できます。
   ``FROM`` 命令の処理の一環として、ダウンストリームビルダーは ``ONBUILD`` トリガーを探し、登録されたのと同じ順序でそれらを実行します。
   いずれかのトリガーが失敗すると、 ``FROM`` 命令が中止され、ビルドが失敗します。
   すべてのトリガーが成功すると、 ``FROM`` 命令が完了し、ビルドは通常どおり続行されます。
4. トリガーは、実行後に最終イメージからクリアされます。
   言い換えれば、それらは「孫」ビルドによって継承されません。

たとえば次のようなものを追加できます。

```bash
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
```

>**警告**
>
>``ONBUILD ONBUILD`` を使用して ``ONBUILD`` 命令を連鎖させることは許可されていません。
>
>``ONBUILD`` 命令は ``FROM`` または ``MAINTAINER`` 命令をトリガーしない場合があります。

## STOPSIGNAL

```bash
STOPSIGNAL signal
```

``STOPSIGNAL`` 命令は、終了するためにコンテナに送信されるシステムコール信号を設定します。
このシグナルは、カーネルの ``syscall`` テーブル内の位置(たとえば 9)と一致する有効な符号なしの番号、または ``SIGNAME`` 形式のシグナル名(たとえば ``SIGKILL`` )にすることができます。

## HEALTHCHECK

``HEALTHCHECK`` 命令には 2 種類の形式があります:


* ``HEALTHCHECK [OPTIONS] CMD command`` (コンテナ内でコマンドを実行して、コンテナの状態を確認します)
* ``HEALTHCHECK NONE`` (ベースイメージから継承されたヘルスチェックを無効にする)


``HEALTHCHECK`` 命令は、コンテナをテストしてコンテナがまだ機能していることを確認する方法を Docker に指示します。
これにより、サーバープロセスがまだ実行されていても Web サーバーが無限ループに陥り、新しい接続を処理できないなどのケースを検出できます。

コンテナにヘルスチェックが指定されている場合、通常のステータスに加えてヘルスステータスがあります。
このステータスは最初は「開始中」です。
ヘルスチェックに合格すると、ヘルスチェックが「正常」になります(以前の状態に関係なく)。
一定数の連続した失敗の後、「異常」となります。

``CMD`` の前に表示されるオプションは次のとおりです。


* ``--interval=DURATION`` (既定値: 30s)
* ``--timeout=DURATION`` (既定値: 30s)
* ``--start-period=DURATION`` (既定値: 0s)
* ``--retries=N`` (既定値: 3)


ヘルスチェックは、最初にコンテナが開始されてから数秒後に実行され、次に前の各チェックが完了してから数秒後に再度実行されます。

チェックの 1 回の実行にタイムアウト秒より長い時間がかかる場合、チェックは失敗したと見なされます。

コンテナが異常であると見なされるには、ヘルスチェックの連続した失敗を再試行する必要があります。

開始期間はブートストラップに時間が必要なコンテナーの初期化時間を提供します。
その期間中のプローブ障害は、最大再試行回数にはカウントされません。
ただし、開始期間中にヘルスチェックが成功した場合、コンテナーは開始されたと見なされ、連続するすべての失敗は最大再試行回数にカウントされます。

Dockerfile には 1 つの ``HEALTHCHECK`` 命令しか存在できません。
複数列記すると最後の ``HEALTHCHECK`` のみが有効になります。

``CMD`` キーワードの後のコマンドは、シェルコマンド(例:  ``HEALTHCHECK CMD /bin/check-running`` )または ``exec`` 配列(他の Dockerfile コマンドと同様)のいずれかです。
(詳細については ``ENTRYPOINT`` を参照してください)

コマンドの終了ステータスは、コンテナのヘルスステータスを示します。
有効な値は次のとおりです。


* 0: success - コンテナは正常ですぐに使用できます
* 1: unhealthy - コンテナが正しく機能していません
* 2: reserved - この終了コードは使用しないでください


たとえば 5 分ごとにチェックして、ウェブサーバーが 3 秒以内にサイトのメインページにサービスを提供できるようにするには、次のようにします。

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

失敗したプローブのデバッグを支援するために、コマンドが ``stdout``または ``stderr`` に書き込む出力テキスト(UTF-8 エンコード)はヘルスステータスに保存され ``docker inspect`` で検索できます。
このような出力は短くする必要があります(現在、最初の 4096 バイトのみが格納されています)。

コンテナのヘルスステータスが変更されると、新しいステータスで ``health_status`` イベントが生成されます。

``HEALTHCHECK`` 機能は Docker 1.12 から追加されました。

## SHELL

```bash
SHELL ["executable", "parameters"]
```

``SHELL`` 命令を使用すると、シェル形式のコマンドに使用されるデフォルトのシェルを上書きできます。
Linux のデフォルトシェルは ``["/bin/sh", "-c"]`` です。
Windows のデフォルトシェルは ``["cmd", "/S", "/C"]`` です。
``SHELL`` 命令は Dockerfile に JSON 形式で記述する必要があります。

``SHELL`` 命令は一般的に使用されているまったく異なる 2 つのネイティブシェル( ``cmd`` と ``powershell`` )と、 ``sh`` を含む代替シェルが利用可能な Windows で特に役立ちます。

``SHELL`` 命令は複数回表示される可能性があります。
各 ``SHELL`` 命令は、以前のすべての ``SHELL`` 命令を上書きし、後続のすべての命令に影響を与えます。
例:

```bash
FROM microsoft/windowsservercore

# Executed as cmd /S /C echo default
RUN echo default

# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default

# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello

# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S", "/C"]
RUN echo hello
```

次の命令はシェル形式が Dockerfile で使用されている場合に ``SHELL`` 命令の影響を受ける可能性があります: 

* ``RUN``
* ``CMD``
* ``ENTRYPOINT``

次の例は ``SHELL`` 命令を使用して合理化できる Windows で見られる一般的なパターンです。

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

docker によって呼び出されるコマンドは次のようになります。

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

これは 2 つの理由で非効率的です。
まず、不要な ``cmd.exe`` コマンドプロセッサ(別名シェル)が呼び出されています。
次に、シェル形式の各 ``RUN`` 命令には、コマンドの前に追加の ``powershell -command``が必要です。

これをより効率的にするために 2 つのメカニズムのうちの 1 つを使用することができます。
1 つは次のような ``RUN`` コマンドの JSON 形式を使用することです。

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

JSON 形式は明確であり、不要な ``cmd.exe`` を使用しませんが、二重引用符とエスケープにより、より詳細な情報が必要になります。
別のメカニズムは ``SHELL`` 命令とシェル形式を使用することです。
これにより、特にエスケープパーサーディレクティブと組み合わせると Windows ユーザーにとってより自然な構文になります。

```bash
# 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'
```

実行結果:

```bash
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`` 命令は zsh, csh, tcsh などの代替シェルが必要な場合に Linux でも使用できます。

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

## 外部実装機能

この機能は BuildKit バックエンドを使用している場合にのみ使用できます。

[docker build](https://qiita.com/JhonnyBravo/items/87976fe9de47ed58b8b1) は、構文ディレクティブを使用してビルダーの外部実装を使用することで有効になる、キャッシュマウント、ビルドシークレット、 ssh 転送などの実験的な機能をサポートします。
これらの機能については [BuildKit リポジトリのドキュメント](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md) を参照してください。

## Dockerfile 記述例

以下に Dockerfile 構文の例をいくつか示します。

```bash
# Nginx
#
# VERSION               0.0.1

FROM      ubuntu
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
```

```bash
# Firefox over VNC
#
# VERSION               0.3

FROM ubuntu

# Install vnc, xvfb in order to create a 'fake' display and firefox
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir ~/.vnc
# Setup a password
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc'

EXPOSE 5900
CMD    ["x11vnc", "-forever", "-usepw", "-create"]
```

```bash
# Multiple images example
#
# VERSION               0.1

FROM ubuntu
RUN echo foo > bar
# Will output something like ===> 907ad6c2736f

FROM ubuntu
RUN echo moo > oink
# Will output something like ===> 695d7793cbe4

# You'll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
# /oink.
```