docker build

説明

Dockerfile からイメージを 構築(build) します。

使い方

$ docker build [オプション] パス | URL | -

詳細説明

docker build コマンドは、 Dockerfile と「 コンテクスト(context) 」から Docker イメージを構築するコマンドです。構築のコンテクストとは、指定した パスURL に置かれているファイル全てです。構築の過程で、そのコンテクストにある全てのファイルを参照できます。たとえば、 COPY 命令を使う時に、コンテクスト内にあるファイルを参照して構築できます。

URL パラメータでは、3種類のリソースを参照できます: Git リポジトリ、パッケージ済みの tar ボールコンテキスト、テキストファイル。

Git リポジトリ

URL パラメータが Git リポジトリの場所を示す場合、そのリポジトリが構築コンテクストになります。システムはリポジトリとサブモジュールを再帰的に取得します。コミット履歴は保持しません。まず、ローカルホスト上の一時ディレクトリに、リポジトリをダウンロードします。それが成功してから、そのディレクトリをコンテクストとして Docker デーモンに送信されます。ローカルでのコピーであれば、ローカルのユーザ認証や VPN 等を使うプライベート・リポジトリへのアクセスも可能にします。

注釈

URL パラメータにフラグメント(ハッシュ)が含まれている場合、システムはリポジトリを再帰的にクローンし、サブモジュールには git clone --recursive コマンドを使います。

Git の URL には、セクションをコロン( : )で分ける記述ができます。前半部分はチェックアウトする Git を参照し、ブランチ、タグ、リモートリファレンスも表せます。後半部分はリポジトリ内のサブディレクトリを表し、これが構築コンテキストになります。

例えば、 container ブランチを docker という名称のディレクトリで使うには、このコマンドを実行します:

$ docker build https://github.com/docker/rootfs.git#container:docker

次の表は構築コンテクストで有効なサフィックスの一覧です。

構築構文のサフィックス 使用するコミット 構築コンテクストの場所
myrepo.git refs/heads/master /
myrepo.git#mytag refs/heads/mytag /
myrepo.git#mybranch refs/heads/mybranch /
myrepo.git#abcdef sha1 = abcdef /
myrepo.git#:myfolder refs/heads/master /myfolder
myrepo.git#master:myfolder refs/heads/master /myfolder
myrepo.git#mytag:myfolder refs/heads/mytag /myfolder
myrepo.git#mybranch:myfolder refs/heads/mybranch /myfolder
myrepo.git#abcdef:myfolder sha1 = abcdef /myfolder

注釈

BuildKit をビルダとして使う場合( DOCKER_BUILDKIT=1 )、構築コンテキストのディレクトリを指定できません(先の例では myfolder )。この機能のサポートについては buildkit#1684 に経緯があります。

tar ボールのコンテクスト

URL にリモートの tar ボールを指定すると、URL そのものがデーモンに送られます:

$ docker build http://server/context.tar.gz

ダウンロード処理が行われるのは、Docker デーモンが動作しているホスト上です。このホストは build コマンドを実行するホストと同じである必要はありません。Docker デーモンは context.tar.gz を取得し、それを構築コンテクストとして使います。tar ボールコンテクストは、標準の tar UNIX フォーマットに適合している必要があり、そのためには xzbzip2gzipidentity (圧縮なし)のいずれかのフォーマットで圧縮が必要です。

テキストファイル

コンテクストを指定する代わりに、Dockerfile の URLSTDIN (標準入力)のファイルをパイプできます。 STDIN から Dockerfile をパイプするには:

$ docker build - < Dockerfile

Windows 上の Powershell では、次のように実行します:

Get-Content Dockerfile | docker build -

STDIN や URL で単なるテキストファイルを指定すると、システムはコンテクストを Dockerfile という名称のファイルに置き換えるため、 -f および --file オプションは無視されます。今回の例では、コンテクストは指定していません。

デフォルトの docker build コマンドは、構築コンテクストのルートにある Dockerfile を探します。 -f および --file オプションは、内容が含まれている代替ファイルのパスを指定します。これは複数のファイル群を使って、複数の構築をする場合に便利です。パスには構築コンテクスト用のファイルが必要です。相対パスを指定すると、コンテクストのルートからの相対パスとして解釈されます。

多くの場合、それぞれの Dockerfile を空のディレクトに入れるのがベストな方法です。それから、ディレクトリ内には Dockerfile の構築に必要なものしか置きません。構築のパフォーマンスを向上するには、 .dockerignore ファイルを設置し、特定のファイルやディレクトリを除外する設定が使えます。このファイルを作るための詳しい方法は、 .dockerignore ファイル をご覧ください。

Docker クライアントがデーモンと通信できない場合、構築は中止されます。Docker クライアントで ctrl-c を使うか、何らかの理由により Docker クライアントが停止された場合も、構築は中止されます。構築中止の段階で取得処理(pull)が進行している場合は、同様に pull 処理も中止されます。

このコマンドの使用例は、後述の サンプル をご覧ください。

オプション

名前、省略形 デフォルト 説明
--add-host   任意のホストに対し IP を割り当てを追加(host:ip)
--build-arg   構築時の変数を設定
--cache-from   イメージに対してキャッシュ元を指定
--cgroup-parent   コンテナに対する任意の親 cgroup
--compress   構築コンテクストを gzip を使って圧縮
--cpu-period   CPU CFS (completely Fair Scheduler)期間を制限
--cpu-quota   CPU CFS (completely Fair Scheduler)クォータを制限
--cpu-shares-c   CPU 配分(share) (相対ウェイト)
--cpuset-cpus   アクセスを許可する CPU を指定( 0-3, 0, 1 )
--cpuset-mems   アクセスを許可するメモリノードを指定( 0-3, 0, 1 )
--disable-context-trust true イメージの検証を無効化
--file-f   Dockerfile の名前(デフォルトは パス/Dockerfile
--force-rm   中間コンテナを常に削除
--iidfile   イメージ ID をファイルに書き込む
--isolation   コンテナ分離技術
--label   イメージにメタデータを設定
--memory-m   メモリの上限
--memory-swap   スワップの上限は、メモリとスワップの合計と同じ: -1 はスワップを無制限にする
--network   【API 1.25+】 構築中の RUN 命令で使うネットワークモードを指定
--no-cache   イメージの構築時にキャッシュを使用しない
--output-o   【API 1.40+】 アウトプット先を指定(書式:type=local,dest=path)
--platform   【API 1.38+】 サーバがマルチプラットフォーム対応であれば、プラットフォームを指定
--progress auto 進行状況の出力タイプを設定(auto、plain、tty)。plain を使うと、コンテナの出力を表示
--pull   イメージは、常に新しいバージョンのダウンロードを試みる
--quiet-q   構築時の出力と成功時のイメージ ID 表示を抑制
--rm true 構築に成功後、中間コンテナを削除
--secret   【API 1.39+】 構築時に利用するシークレットファイル(BuildKit 有効時のみ): id=mysecret,src=/local/secret
--security-opt   セキュリティのオプション
--shm-size   /dev/shm の容量
--squash   【experimental (daemon) | API 1.25+】 構築するレイヤを、単一の新しいレイヤに 押し込む(squash)
--ssh   【API 1.39+】 構築時に利用する SSH エージェントのソケットやキー(BuildKit 有効時のみ)(書式:default | <id>[=<socket>] | <key>[,<key>]] )
--stream   サーバにアクセスし、構築コンテクストの状況を表示し続ける
--tag-t   名前と、オプションでタグを 名前:タグ の形式で指定
--target   構築する対象の構築ステージを指定
--ulimit   ulimit オプション

PATH で構築

$ docker build .
Uploading context 10240 bytes
Step 1 : FROM busybox
Pulling repository busybox
 ---> e9aa60c60128MB/2.284 MB (100%) endpoint: https://cdn-registry-1.docker.io/v1/
Step 2 : RUN ls -lh /
 ---> Running in 9c9e81692ae9
total 24
drwxr-xr-x    2 root     root        4.0K Mar 12  2013 bin
drwxr-xr-x    5 root     root        4.0K Oct 19 00:19 dev
drwxr-xr-x    2 root     root        4.0K Oct 19 00:19 etc
drwxr-xr-x    2 root     root        4.0K Nov 15 23:34 lib
lrwxrwxrwx    1 root     root           3 Mar 12  2013 lib64 -> lib
dr-xr-xr-x  116 root     root           0 Nov 15 23:34 proc
lrwxrwxrwx    1 root     root           3 Mar 12  2013 sbin -> bin
dr-xr-xr-x   13 root     root           0 Nov 15 23:34 sys
drwxr-xr-x    2 root     root        4.0K Mar 12  2013 tmp
drwxr-xr-x    2 root     root        4.0K Nov 15 23:34 usr
 ---> b35f4035db3f
Step 3 : CMD echo Hello world
 ---> Running in 02071fceb21b
 ---> f52f38b7823e
Successfully built f52f38b7823e
Removing intermediate container 9c9e81692ae9
Removing intermediate container 02071fceb21b

この例では PATH. を指定しています。このローカルディレクトリにある全てのファイルは tar 化され、Docker デーモンに送られます。 PATH で示すのは、Docker デーモンが構築時に使う「コンテクスト」(内容物)としてのファイルを見つけるための場所です。デーモンはリモート上のマシンでも操作できるのを思い出してください。これは、クライアント側( docker build コマンドを実行した場所 )では Dockerfile は何らパース(解析)されません。つまり、 PATH に含まれる すべて のファイルが送信されるだけでなく、Dockerfile の ADD 命令で追加した場所も含みます。

ローカルのマシンから Docker デーモンにコンテクストを送信時、 docker クライアントには「Sending build context」(構築コンテクストの送信中)とメッセージが表示されます。

構築完了後、中間コンテナをそのまま維持したい場合は、 --rm=false の指定が必要です。こちらを指定すると、構築キャッシュに何もしません。

URL で構築

$ docker build github.com/creack/docker-firefox

これは GitHub リポジトリのクローンを作成し、クローンしたリポジトリをコンテクストとして利用します。リポジトリのルートにある Dockerfile を、構築時の Dockerfile として使います。 git://git@ などを使って、その他の Git リポジトリも指定可能です。

$ docker build -f ctx/Dockerfile http://server/ctx.tar.gz

Downloading context: http://server/ctx.tar.gz [===================>]    240 B/240 B
Step 1/3 : FROM busybox
 ---> 8c2e06607696
Step 2/3 : ADD ctx/container.cfg /
 ---> e7829950cee3
Removing intermediate container b35224abf821
Step 3/3 : CMD /bin/ls
 ---> Running in fbc63d321d73
 ---> 3286931702ad
Removing intermediate container fbc63d321d73
Successfully built 377c409b35e4

これは Docker デーモンに対して URL http://server/ctx.tar.gz を送り、Docker デーモンが指定された tar ボールのダウンロードと展開をします。 -f ctx/Dockerfile パラメータが示すのは、 ctx.tar.gz の中にある Dockerfile のパスで、これをイメージ構築時に使います。 Dockerfile 内のあらゆる ADD コマンドは、 ctx.tar.gz 内にあるルートからの相対パスで指定する必要があります。先の例では、 tar ボールには ctx/ ディレクトリを含むので、 ADD ctx/container.cfg / は動作するでしょう。

- で構築

$ docker build - < Dockerfile

これはコンテクストを使わずに STDIN から Dockerfile を読み込みます。コンテクストが無いため、中身の無いローカルのディレクトリが Docker デーモンに送信されます。コンテクストがありませんので、 Dockerfile の ADD はリモートの URL の参照に使えます。

$ docker build - < context.tar.gz

これは STDIN から圧縮されたコンテクストを読み込み、イメージを構築しています。サポートしているフォーマットは、bzip2、gzip、xz です。

.dockerignore の使い方

$ docker build .
Uploading context 18.829 MB
Uploading context
Step 1 : FROM busybox
 ---> 769b9341d937
Step 2 : CMD echo Hello world
 ---> Using cache
 ---> 99cc1ad10469
Successfully built 99cc1ad10469
$ echo ".git" > .dockerignore
$ docker build .
Uploading context  6.76 MB
Uploading context
Step 1 : FROM busybox
 ---> 769b9341d937
Step 2 : CMD echo Hello world
 ---> Using cache
 ---> 99cc1ad10469
Successfully built 99cc1ad10469

この例で表示しているのは、 .dockerignore ファイルを使い、コンテクストから .git ディレクトリを除外しています。この効果により、アップロードされるコンテクストの容量を小さくしています。構築時のリファレンス .dockerignore ファイルの作成 に、より詳しい情報があります。

BuildKit バックエンド の利用時、 docker build は Dockerfile 名に関連する .dockerignore ファイルを探します。たとえば、 docker build -f myapp.Dockerfile . を実行すると、最初に myapp.Dockerfile.dockerignore という名前の無視ファイルを探します。そのようなファイルがない場合、 .dockerignore があれば使います。プロジェクトに複数の Dockerfile がある場合は、様々なファイルと混在しないようにするため、 Dockerfile をベースとする .dockerignore の利用が便利です。

イメージのタグ(-t)

$ docker build -t vieux/apache:2.0 .

これまでの例のように構築していますが、作成されるイメージに対してタグ付けをしています。リポジトリ名は vieux/apache になり、タグは 2.0 になります。詳細は 有効なタグ についてをご覧ください。

イメージに対して複数のタグを適用できます。例えば、最も新しい構築イメージに対して latest タグを付け、他にもバージョンを参照用タグも付けられます。例えば、イメージに対して whenry/fedora-jboss:latestwhenry/fedora-jboss:v2.1 をタグ付けするには、次のコマンドを実行します。

$ docker build -t whenry/fedora-jboss:latest -t whenry/fedora-jboss:v2.1 .

Dockerfile の指定(-f)

$ docker build -f Dockerfile.debug .

構築時の命令は Dockerfile ではなく、 Dockerfile.debug という名前のファイルを使います。

$ curl example.com/remote/Dockerfile | docker build -f - .

この上のコマンドは、現在のディレクトリを構築コンテクストとして使い、標準入力から Dockerfile を読み込みます。

$ docker build -f dockerfiles/Dockerfile.debug -t myapp_debug .
$ docker build -f dockerfiles/Dockerfile.prod  -t myapp_prod .

上記のコマンドは、どちらも現在のディレクトリにあるコンテント( . で場所を指定 )を使い構築するものです。デバッグ用とプロダクション用で別々の Dockerfile を使いますが、コンテクストは同じです。

$ cd /home/me/myapp/some/dir/really/deep
$ docker build -f /home/me/myapp/dockerfiles/debug /home/me/myapp
$ docker build -f ../../../../dockerfiles/debug /home/me/myapp

2つの docker build コマンドは同じことをしています。いずれの Dockerfile にも debug ファイルが含まれており、構築コンテクストのルートとして /home/me/myapp を使います。なお注意点として、 debug は構築コンテクストのサブディレクトリにあるもので、先ほどのコマンドライン上では指定の必要がありませんでした。

注釈

docker buildno such file or directory エラーを返すのは、アップロードすべきコンテクストとしてのファイルやディレクトリが存在しない時です。これは、コンテクストが存在しないか、指定したファイルがホストシステム上に存在していない可能性があります。コンテクストはカレント・ディレクトリ(と、その子ディレクトリ)のみに安全上の理由で制限されています。これはリモートの Docker ホスト上でも、繰り返し構築できるようにするためです。これが ADD ../file が動作しない理由でもあります。

親 cgroup のオプション(--cgroup-parent)

docker build--cgroup-parent オプションを付けて構築すると、構築時の docker run 実行時に 適切なフラグを付けて実行 します。

コンテナの ulimit をセット(--ulimit)

docker build--ulimit オプションを付けて実行したら、コンテナの構築ステップを開始する時、都度 --ulimit フラグの値を設定 します。

構築時の変数を指定(--build-arg)

Dockerfile の ENV 命令を使い、変数を定義できます。これらの値は構築時に一定のものです。しかし、一定の値が必要でない場合もあります。ユーザがイメージを構築するホストによっては、依存性に対する変数が必要になるかもしれません。

良い例が http_proxy や中間ファイルの取得に使うソースのバージョン指定です。 ARG 命令は Dockerfile の作者が定義する値であり、ユーザが構築時に --build-arg フラグを指定できます。

$ docker build --build-arg HTTP_PROXY=http://10.20.30.2:1234 .

このフラグを使うことで、構築時の変数が Dockerfile の RUN 命令で通常の環境変数のように扱えます。それだけでなく、これらの値は ENV のように使えますが、中間ファイルや最終的なイメージでは一定ではありません。

フラグ使用時、Dockerfile で構築プロセスが進行しても ARG 行は画面には表示されません。

ARGENV 命令の詳細については、 Dockerfile リファレンス をご覧ください。

また、値のない --build-arg フラグも使うこともでき、その場合、ローカル環境の値が、構築時の Docker コンテナ内に継承されます。

export HTTP_PROXY=http://10.20.30.2:1234
docker build --build-arg HTTP_PROXY .

これは docker run -e の挙動に似ています。詳しい情報は docker run ドキュメント をご覧ください。

オプションのセキュリティオプション(--security-opt)

このフラグをサポートしているのは、 Windows 上で実行しているデーモンで、かつ credentialspec オプションをサポートしている場合のみです。 credentialspec の形式は file://spec.txtregistry://keyname どちらかの必要があります。

コンテナの隔離技術を指定(--isolation)

このオプションは Windows 上で Docker コンテナを実行する状況で役立ちます。 --isolation=<値> オプションは、コンテナの隔離技術を指定します。Linux 上では Linux 名前空間を使う default オプションしかサポートしていません。Microsoft Windows 上では、これらの値を指定できます。

説明
default Docker デーモンの --exec-opt で指定している値を使います。隔離技術に daemon の指定がなければ、 Microsoft Windows はデフォルトの値として process を使います。
process 名前空間の分離のみです。
hyperv Hyper-V ハイパーバイザ・パーティションをベースとする隔離です。

値の無い --isolation フラグの指定は、 --isolation="default" を指定するのと同じです。

コンテナの hosts ファイルにエントリを追加(--add-host)

1つまたは複数の --add-host を使い、コンテナ内の /etc/hosts ファイルに他のホスト情報を追加できます。

$ docker build --add-host=docker:10.180.0.1 .

構築ステージの対象を指定(--target)

複数の構築ステージがある Dockerfile を使って構築する時に、中間構築ステージを --target の名前で指定すると、そこを最終ステージとするイメージを作成できます。コマンドで指定した対象以降のステージはスキップされます。

FROM debian AS build-env
...

FROM alpine AS production-env
...
docker build -t mybuildimage --target build-env .

構築時の出力を変更

デフォルトでは、構築処理の結果を元に、ローカルのコンテナイメージが作成されます。 --output (あるいは -o )フラグによって、この挙動を変更し、任意の 出力形式(exporter) を指定できます。たとえば、任意の出力指定によって、Docker イメージではなくローカルファイルシステム上にファイルとして構築時の成果物を出力できるため、ローカルでのバイナリ生成やコード生成等に役立てるでしょう。

--output の値は、出力形式とオプションを CSV 形式の文字で定義します。現時点では localtar の出力形式をサポートします。 local 出力形式では、構築結果のファイルをクライアント側ディレクトリ上に書き出します。 tar 出力形式は似ていますが、単一の tar ボール( .tar )としてファイルを書き出します。

出力形式の指定が無ければ、値はデフォルトでローカルのディレクトリに出力します。ハイフン( - )を使えば、tar ボールへの出力を標準出力( STDOUT )に書き出します。

以下の例は、現在のディレクトリ( . )を構築コンテクストとしてイメージを構築し、このディクトリ以下に、 out という名前のディレクトリへファイルを出力します。もしもディレクトリが存在しなければ、Docker はディレクトリを自動的に作成します。

$ docker build -o out .

上の例では type オプションを省略した短い構文を使いましたので、この場合はデフォルト( local )出力形式が使われました。以下の例では同じ内容を、 typedest (出力先のパス)の両方を記載する、 CSV 形式の長い構文を使って表しています。

$ docker build --output type=local,dest=out .

tar タイプを使うと、ファイルを .tar アーカイブとして出力します。

$ docker build --output type=tar,dest=out.tar .

短い構文を使い、同等の処理を行うのが以下の例です。こちらの場合、 - は出力先の指定となり、自動的に tar タイプが選ばれます。そして、 tar ボールへの出力として書き出されるよう、標準出力は out.tar ファイルにリダイレクトします。

docker build -o - . > out.tar

--output オプションは対象となる構築ステージすべてのファイルを書き出します。ファイルを指定して出力する一般的なパターンは、マルチステージでの構築において、 COPY --from でゼロから新しいステージの構築時、必要なファイルをコピーするためです。

以下の Dockerfile 例は、構築による成果物を集めて出力するため、構築ステージを分けています。

FROM golang AS build-stage
RUN go get -u github.com/LK4D4/vndr

FROM scratch AS export-stage
COPY --from=build-stage /go/bin/vndr /

Dockerfile を -o オプションで構築する時は、最終ステージのファイルのみが out ディレクトリに出力されます。この例では nvdr バイナリです。

$ docker build -o out .

[+] Building 2.3s (7/7) FINISHED
 => [internal] load build definition from Dockerfile                                                                          0.1s
 => => transferring dockerfile: 176B                                                                                          0.0s
 => [internal] load .dockerignore                                                                                             0.0s
 => => transferring context: 2B                                                                                               0.0s
 => [internal] load metadata for docker.io/library/golang:latest                                                              1.6s
 => [build-stage 1/2] FROM docker.io/library/golang@sha256:2df96417dca0561bf1027742dcc5b446a18957cd28eba6aa79269f23f1846d3f   0.0s
 => => resolve docker.io/library/golang@sha256:2df96417dca0561bf1027742dcc5b446a18957cd28eba6aa79269f23f1846d3f               0.0s
 => CACHED [build-stage 2/2] RUN go get -u github.com/LK4D4/vndr                                                              0.0s
 => [export-stage 1/1] COPY --from=build-stage /go/bin/vndr /                                                                 0.2s
 => exporting to client                                                                                                       0.4s
 => => copying files 10.30MB                                                                                                  0.3s

$ ls ./out
vndr

注釈

この機能は BuildKit バックエンドが必要です。 BuildKit の有効化buildx プラグインを使うかどちらかにより、さらに出力形式のオプションが使えるようになります。

外部キャッシュ・ソースの指定

ローカルの構築キャッシュに加え、ビルダーは以前のビルドで生成したキャッシュを再利用できます。そのためには、 --cache-from フラグでレジストリのイメージを指定します。

イメージをキャッシュのソースとして使うには、作成するイメージ上にキャッシュのメタデータを書き込めるようにする必要があります。そのためには、イメージの構築時に --build-arg BUILDKIT_INLINE_CACHE=1 を実行します。その後、構築イメージを以降の構築時にキャッシュ元として利用できます。

キャッシュを取り込んだ結果、ビルダはレジストリからは JSON メタデータのみ取得し、その情報を元にキャッシュになりうる可能性があるかどうかを決めます。キャッシュに一致すると、対象のレイヤがローカル環境に渡されます。

イメージに加え、キャッシュは buildx や BuildKit CLI ( buildctl )によって生成された特別なキャッシュ・マニフェストからも取得できます。これらのマニフェスト( type=registrymode=max オプションを指定して構築時 )により、レイヤデータやマルチステージ・ビルドにおける中間ステージから取得できるようになります。

以下の例は、中間キャッシュのメタデータでイメージを構築し、レジストリにそれを送ります。以降は、他のマシンでのキャッシュソースとしてイメージが利用できます。

$ docker build -t myname/myapp --build-arg BUILDKIT_INLINE_CACHE=1 .
$ docker push myname/myapp

イメージの送信後、イメージは他マシンでのキャッシュソースとして利用できます。 BuildKit は必要があれば、自動的にレジストリからイメージを取得します。

他のマシン上で:

$ vdocker build --cache-from myname/myapp .

注釈

この機能には BuildKit バックエンドが必要です。 BuildKit を有効化 するか、 buildx プラグインを使用するかのいずれかです。BuildKit は、必要があればレジストリから自動的にイメージを取得します。

イメージのレイヤを スカッシュ(squash) (--squash) (実験的機能)

概要

イメージを構築次第、新しいレイヤを、新しいイメージの1つのレイヤに スカッシュ(squash) (訳者注:「押し潰す」あるいは「圧縮」の意味合い)します。スカッシュでは既存のレイヤを一切破棄しません。まあ、スカッシュしたレイヤの内容を元に、新しいイメージを作成した場合も同様です。これは事実上、 Dockerfile 命令で全てによって、1つのレイヤを作成したかのように見えます。なおスカッシュ時に構築イメージは保持されます。

--squash オプションは実験的機能です。そのため、安定していないと考えるべきです。

レイヤの圧縮が役立つのは、同じ Dockerfile から複数のレイヤをに修正を加える場合です。たとえば、ステップ1でファイルを作成し、それを他のステップに移動する場合です。一方で、使用例によっては、イメージの圧縮が性能に悪影響をあたえてしまうかもしれません。具体的には、イメージが複数のレイヤで構成されている場合は、各レイヤは並列に取得でき、かつ、イメージ間でレイヤを共有できるためです(容量の節約)。

ほとんどの場合、マルチステージ・ビルドは望ましい手法です。構築における詳細な制御が出来るため、以降の構築を最適化する利点があります。詳しい情報はユーザガイドの マルチステージ・ビルド セクションをご覧ください。

判明している制限

--squash オプションには、いくつかの制限が判明しています:

  • レイヤの圧縮で作成されたイメージは、他のイメージとレイヤを共有できる利点を得られません。また、より多くの容量を必要とする場合もあります。ベース・イメージの共有はサポートしています。
  • このオプションを使うことで、イメージのコピーを2つ持つため、著しく容量を使う場合があります。1つは、各キャッシュレイヤの原型となる構築キャッシュです。もう1つは、圧縮されたイメージです。
  • レイヤの圧縮で小さなイメージが作成できるかもしれませんが、性能に悪影響をあたえる可能性があります。単一のレイヤは以後展開できませんし、並列ダウンロードもできません。
  • イメージ圧縮を試みる時、ファイルシステムの変更を伴わなければ、圧縮ステップは失敗します( issue #33823 をご覧ください)。

動作条件

このページの例は Docker 19.03 の 実験的モード(experimental mode) を使っています。

実験的モードを有効にするには、 Docker デーモンのの起動時に --experimental フラグを付けるか、 daemon.json 設定ファイル内で experimental: true を指定します

デフォルトでは、実験的モードは無効化されています。

Client: Docker Engine - Community
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.12.17
 Git commit:        afacb8b
 Built:             Wed Mar 11 01:21:11 2020
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.17
  Git commit:       afacb8b
  Built:            Wed Mar 11 01:29:16 2020
  OS/Arch:          linux/amd64
  Experimental:     true
 [...]

実験的モードを有効化するには、実験的(experimental)フラグを有効にして Docker デーモンを再起動する必要があります。

Docker 実験的モードの有効化

実験的モードを湯考課するには、 --experimental フラグを付けて Docker デーモンを再起動する必要があります。あるいは、 /etc/docker/daemon.json を通してデーモンのフラグを有効化できます。以下は例です。

{
    "experimental": true
}

それから、実験的フラグの有効化を確認します:

$ docker version -f '{{.Server.Experimental}}'
true

--squash 引数でイメージを構築

以下は、 docker build で --squash 引数を付ける例です。

FROM busybox
RUN echo hello > /hello
RUN echo world >> /hello
RUN touch remove_me /remove_me
ENV HELLO=world
RUN rm /remove_me

イメージ名 test に、 --squash 引数を付けて構築します。

$ docker build --squash -t test .

<...>

すべてが正しければ、history はこのようになります。

$ docker history test

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
4e10cb5b4cac        3 seconds ago                                                       12 B                merge sha256:88a7b0112a41826885df0e7072698006ee8f621c6ab99fca7fe9151d7b599702 to sha256:47bcc53f74dc94b1920f0b34f6036096526296767650f223433fe65c35f149eb
<missing>           5 minutes ago       /bin/sh -c rm /remove_me                        0 B
<missing>           5 minutes ago       /bin/sh -c #(nop) ENV HELLO=world               0 B
<missing>           5 minutes ago       /bin/sh -c touch remove_me /remove_me           0 B
<missing>           5 minutes ago       /bin/sh -c echo world >> /hello                 0 B
<missing>           6 minutes ago       /bin/sh -c echo hello > /hello                  0 B
<missing>           7 weeks ago         /bin/sh -c #(nop) CMD ["sh"]                    0 B
<missing>           7 weeks ago         /bin/sh -c #(nop) ADD file:47ca6e777c36a4cfff   1.113 MB

ここから分かるのは、レイヤ名は <missing> (不明)となり、新しいレイヤにコメント merge があります。

このイメージを調べ、 /remove_me は消失し、 hello\nworld/hello の中にあり、環境変数 HELLO の値が world になっているのを確認しましょう。