docker build

読む時間の目安: 14 分

説明

Dockerfile からイメージをビルドします。

利用方法

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

追加説明

docker build コマンドは Dockerfile と「ビルドコンテキスト」から Docker イメージをビルドします。 ビルドコンテキストとは、指定された PATHURL に存在している一連のファイルのことです。 ビルド処理においては、コンテキスト内のどのファイルでも参照できます。 たとえばビルドにおいて COPY 命令を使っている場合に、コンテキスト内のファイルを参照することができます。

URL パラメーターは 3 種類のリソースを参照します。 Git リポジトリ、パッケージングされた tarball コンテキスト、プレーンなテキストファイル、の 3 つです。

Git リポジトリ

URL パラメーターが Git リポジトリの場所を示している場合、そのリポジトリがビルドコンテキストとして扱われます。 システムはリポジトリとサブモジュールを再帰的にフェッチします。 コミット履歴は保持されません。 リポジトリは初めに、ローカルホスト内の一時的なディレクトリにプルされます。 これが正常処理されると、ディレクトリ内容がコンテキストとして Docker デーモンに送信されます。 ローカルにコピーが存在しているなら、プライベートリポジトリにもアクセス可能になります。 その際にはローカルにあるユーザー認証情報、VPN 情報などが用いられます。

メモ

URL パラメーターが部分的なものであった場合、システムは git clone --recursive コマンドを実行して、そのリポジトリやサブモジュールを再帰的にクローンします。

Git URL では、コンテキスト設定にあたって URL の部分指定が可能です。 部分指定にはコロン(:)を使って区切ります。 コロンより前の 1 つめの項目として Git がチェックアウトを行う URL を指定します。 これはブランチ、タグ、リモートリファレンスのいずれでも可能です。 2 つめの項目には、そのリポジトリ内のサブディレクトリを指定します。 このサブディレクトリがビルドコンテキストとして用いられることになります。

たとえば container ブランチ内の docker というディレクトリを利用するには、以下のように実行します。

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

以下に示す表は、ビルドコンテキストとして有効なサフィックス指定の例です。

ビルド時のサフィックス指定例 利用されるコミット 利用されるビルドコンテキスト
myrepo.git refs/heads/master /
myrepo.git#mytag refs/tags/mytag /
myrepo.git#mybranch refs/heads/mybranch /
myrepo.git#pull/42/head refs/pull/42/head /
myrepo.git#:myfolder refs/heads/master /myfolder
myrepo.git#master:myfolder refs/heads/master /myfolder
myrepo.git#mytag:myfolder refs/tags/mytag /myfolder
myrepo.git#mybranch:myfolder refs/heads/mybranch /myfolder

メモ

ビルダーとして BuildKit を利用している(DOCKER_BUILDKIT=1)場合は、ビルドコンテキスト(上の例ではmyfolder)を指定することはできません。 この機能へのサポートは buildkit#1684 において行われています。

Tarball コンテキスト

URL にリモートの tarball を指定した場合、URL がそのままデーモンに送信されます。

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

ダウンロード処理は、Docker デーモンが稼動しているホスト上で実行されます。 このホストは、build コマンドが実行されたホストと同じである必要はありません。 Docker デーモンは context.tar.gz を取得して、これをビルドコンテキストとして利用します。 tarball コンテキストは UNIX tar フォーマット標準に適合した tar アーカイブである必要があります。 これを ‘xz’、’bzip2’、’gzip’ により圧縮したフォーマットも受け付けます。 ‘identity’(圧縮なし)のフォーマットも利用できます。

テキストファイル

コンテキストを指定するのではなく、1 つの Dockerfile を指定することができます。 つまりそのファイル内容を、STDIN を介してパイプ入力します。 DockerfileSTDIN からパイプ入力するには、以下のようにします。

$ 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 クライアントが何か別の理由により異常終了した場合に発生します。 ビルドがキャンセルされる直前の動作中に、プル処理を初期化していた場合、そのプル処理も同じくキャンセルされます。

本コマンドの利用例については、以下に示す 利用例の節 を参照してください。

オプション

名前/省略形 デフォルト 説明
--add-host ホスト-IP マッピングのカスタム設定を追加します。(ホスト名: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 配分。(相対的な重みづけ)
--cpuset-cpus 利用を許容する CPU 数。(0-3、0,1)
--cpuset-mems 利用を許容するメモリ数。(0-3、0,1)
--disable-content-trust true イメージの検証を省略します。
--file , -f Dockerfile 名。(デフォルトは 'PATH/Dockerfile')
--force-rm 中間コンテナーを常に削除します。
--iidfile イメージ ID をファイルに出力します。
--isolation コンテナーの分離技術(isolation technology)方式。
--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 以上
ビルド時に公開する Secret ファイル(BuildKit 有効時のみ)。 id=mysecret,src=/local/secret
--security-opt セキュリティオプション。
--shm-size /dev/shm のサイズ。
--squash 試験的 (デーモン)API 1.25 以上
ビルドしたレイヤーを単一の新レイヤーに押し込みます(squash します)。
--ssh API 1.39 以上
ビルド時に公開する SSH エージェントソケットまたは SSH 鍵(BuildKit 有効時のみ)。(フォーマット: default|<id>[=<socket>|<key\>[,<key>]])
--stream ビルドコンテキストをやり取りするためにサーバーにアタッチするストリーム。
--tag , -t 書式 'name:tag' により名前および任意のタグを指定します。
--target ビルド対象とするビルドステージを指定します。
--ulimit ulimit オプション。

利用例

PATH を使ったビルド

$ docker build .

Uploading context 10240 bytes
Step 1/3 : FROM busybox
Pulling repository busybox
 ---> e9aa60c60128MB/2.284 MB (100%) endpoint: https://cdn-registry-1.docker.io/v1/
Step 2/3 : 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/3 : CMD echo Hello world
 ---> Running in 02071fceb21b
 ---> f52f38b7823e
Successfully built f52f38b7823e
Removing intermediate container 9c9e81692ae9
Removing intermediate container 02071fceb21b

上の例ではPATH.を指定しています。 そこでローカルディレクトリ内のファイルがtarによってまとめられて Docker デーモンに送られます。 PAHTは、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

上では URLhttp://server/ctx.tar.gzを Docker デーモンに送っています。 こうすると、指定された tarball をダウンロードし、伸張(解凍)が行われます。 パラメーター-f ctx/Dockerfileは、イメージをビルドする際に利用するDockerfilectx.tar.gz内部のパスとして指定しています。 そのDockerfile内にADDコマンドがあって、それがローカルパスを参照しているものであれば、それはすべてctx.tar.gz内ファイルのルートからの相対パスでなければなりません。 上の例において tarball はctx/というディレクトリを含むものとしています。 したがってADD ctx/container.cfg /という命令であれば、期待どおりに動作します。

- を使ったビルド

$ docker build - < Dockerfile

上の例ではコンテキストを利用せず、Dockerfile をSTDINから読み込みます。 コンテキストがないわけですから、ローカルディレクトリ内から 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/2 : FROM busybox
 ---> 769b9341d937
Step 2/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/2 : FROM busybox
 ---> 769b9341d937
Step 2/2 : CMD echo Hello world
 ---> Using cache
 ---> 99cc1ad10469
Successfully built 99cc1ad10469

上の例では.dockerignoreファイルを利用して、コンテキストから.gitディレクトリを除外しています。 その効果は、アップロードされたコンテキストの変更後のサイズからわかります。 Dockerfile リファレンスにおいて、.dockerignore ファイルの生成 を詳しく説明しています。

BuildKit バックエンド を利用すると、docker buildコマンドは Dockerfile 名に関連づいた.dockerignoreファイルを検索するようになります。 たとえばdocker build -f myapp.Dockerfile .を実行した場合、最初に検索される ignore ファイルはmyapp.Dockerfile.dockerignoreというファイルです。 そういったファイルがみつからなかったら、次に.dockerignoreファイルがあればこれが利用されます。 .dockerignoreと関連づいて Dockerfile が利用できるのは便利なことです。 たとえばプロジェクト内に複数の Dockerfile があって、それぞれに異なる ignore ファイルの設定が必要な場合です。

イメージへのタグづけ (-t)

$ docker build -t vieux/apache:2.0 .

上のコマンドは前の例と同じようなビルドを行います。 ただし結果となるイメージにタグをつけます。 リポジトリ名がvieux/apacheであり、タグ名が2.0です。 詳しくは 適正なタグ を参照してください。

1 つのイメージに対しては複数のタグをつけることができます。 たとえば最新のビルドイメージに対してlatestというタグをつけ、特定のバージョンを指し示すために別のタグをつけるといった具合です。 例として 2 つのイメージを対象にして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 .

上の 2 つのコマンドは(ピリオド.が指定されているので)カレントディレクトリをビルドコンテキストとして 2 回のビルドを行います。 1 度めはデバッグバージョンのDockerfileを使い、2 度めは本番環境バージョンを使います。

$ 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 buildコマンドはno 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 --build-arg FTP_PROXY=http://40.50.60.5:4567 .

このフラグにはビルド時の変数を設定できます。 ちょうど Dockerfile のRUN命令において、通常の環境変数にアクセスできることと同じです。 またENVにおける値とは違って、これらの値は中間イメージや最終イメージには残りません。 ビルド時の値は、実行のたびに--build-argに与えなければなりません。

Dockerfile によるビルド処理時に Dockerfile 内のARG命令が出力する表示は、このフラグを使っていても変わることはありません。

ARG命令とENV命令に関する詳細は Dockerfile リファレンス を参照してください。

--build-argフラグには値を設定しないこともあります。 その場合は、ビルドされるコンテナーに対して、ローカルの環境変数の値が与えられます。

$ 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.txtまたはregistry://keynameというものでなければなりません。

コンテナーに対する分離技術方式の指定 (--isolation)

このオプションは Docker コンテナーを Windows 上で実行する場合に有用なものです。 --isolation=<設定値>は、コンテナーの分離技術(isolation technology)方式を指定します。 Linux 上においては、Linux 名前空間を利用するdefault指定のみがサポートされます。 Microsoft Windows の場合、以下の値を設定することができます。

設定値 内容説明
default Docker デーモンの--exec-optの指定に従います。daemonに分離技術が指定されていない場合、Microsoft Windows はデフォルトとしてprocessを採用します。
process 名前空間による分離のみを行います。
hyperv ハイパーバイザー Hyper-V によるパーティションベースの分離を行います。

--isolationフラグに値を設定しなかった場合、--isolation="default"と指定したことになります。

コンテナーの hosts ファイルへの項目追加 (--add-host)

コンテナーの/etc/hostsファイルに、別のホストの情報を追加することができます。 これには--add-hostフラグを使います。 その指定は必要な分だけ行うことができます。 以下の例では、dockerという名前のホストに対するスタティックアドレスを加えるものです。

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

ターゲットとするビルドステージの指定 (--target)

Dockerfile のビルドにおいてマルチステージビルドを採用している場合、中間にあるビルドステージ名を指定して、これを結果イメージに対する最終ステージとすることができます。 指定されたステージ以降にある命令は処理されません。

FROM debian AS build-env
# ...

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

独自のビルド出力

ローカルのコンテナーイメージというものは、デフォルトではビルド結果として生成されるものです。 --output-o)フラグを用いると、この動作をオーバーライドすることができます。 これには独自のエクスポーターを指定します。 たとえば独自のエクスポーターによって、ビルド生成結果を Docker イメージとするのではなく、ローカルファイルシステム上のファイルとして出力できるようになります。 こういうものがあれば、ローカルの実行モジュール生成やコードジェネレーターに活用できます。

--outputに指定するのはカンマ区切りの文字列であり、これによってエクスポーターのタイプとオプションを指定します。 今のところサポートされるエクスポーターはlocaltarだけです。 localエクスポーターは、生成されるビルドファイルを、クライアント側のディレクトリに書き込みます。 tarエクスポーターはそれと同様ですが、ファイルの書き込みは 1 つの tarball(.tar)とします。

タイプが指定されていない場合、デフォルトは local エクスポーターの出力ディレクトリになります。 ハイフン(-)を指定すると、出力する tarball を標準出力(STDOUT)に出力します。

以下の例では、ビルドコンテキストをカレントディレクトリ(.)としてイメージをビルドします。 そして出力ファイルを、カレントディレクトリにあるoutというディレクトリにエクスポートします。 そのディレクトリが存在しない場合、Docker はそのディレクトリを自動生成します。

$ docker build -o out .

上の例では短いオプション指定を用いておりtypeオプションは省略していました。 したがってデフォルトの(local)エクスポーターが用いられます。 以下の例では同等の指定を長いオプション指定で行い、CSV によってtypedest(出力パス)を指定しています。

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

タイプとしてtarを指定すると、ファイルを.tarアーカイブとしてエクスポートします。

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

以下の例では同時ことを短いオプション指定により行います。 この場合、出力先として-を指定しているので、タイプとしてtarが自動的に選択され、tarball を標準出力します。 そしてこれを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ディレクトリにエクスポートされます。 それはこの例ではvndrバイナリモジュールとなります。

$ 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 が必要に応じてレジストリからイメージを自動的にプルします。

別マシン上で、以下を実行します。

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

メモ

この機能を利用するためには BuildKit バックエンドが必要です。 BuildKit の有効化 を行ってください。 あるいは buildx プラグインを利用することもできます。 BuildKit には、プルしたイメージをキャッシュとして再利用する機能には制限があります。

イメージへのレイヤーの押し込み (--squash) (試験的機能)

概要

このオプションは 1 度ビルドしたイメージに対して、その新しいレイヤー群を 1 つのイメージ内に単一のレイヤーとして押し込みます(squash します)。 この押し込み処理を行っても、既存のイメージは壊されることはありません。 そうはならずに、新たなイメージが 1 つ生成され、そこに押し込められたレイヤー内容が入ります。 まるでDockerfileのコマンドがすべて、単一のレイヤーとして生成されるようなものです。 この場合もビルドキャッシュは保持されます。

--squashオプションは試験的機能であるため、安定したものとしては捉えないでください。

レイヤーを押し込めらるこの機能は、同一対象のファイルを修正したレイヤーが複数生成されている場合に、便利なものとなります。 たとえば 1 つの処理ステップにおいてファイルが生成され、別ステップにおいて削除された場合です。 ただ利用の仕方によっては、イメージの押し込みが、性能面の低下が起きることがあります。 たとえば複数レイヤーからなるイメージをプルする際には、各レイヤーが同時並行的にプルされますが、複数イメージ間でレイヤーを共有している場合です(保存が節約されます)。

たいていの場合、マルチステージビルドを選んで間違いはありません。 これによって、ビルド処理をきめ細かく制御でき、ビルド処理において将来最適化が行われた際にも活用することができます。 詳しくは、ユーザーガイドにある マルチステージビルドの利用 の節を参照してください。

既知の制約

--squash オプションには多くの制約があることがわかっています。

  • レイヤーの押し込みを行う際には、結果として生成されるイメージは、他のイメージとの間でレイヤーを共有することができません。 そして容量が極端に増えることがあります。 なおベースイメージの共有には対応しています。
  • このオプションを利用すると、確実に保存容量が増えます。 これはイメージの 2 つ分のコピーを保存するためです。 1 つは、キャッシュレイヤーすべてを損なうことなく完全な形で保持するビルドキャッシュ用、そしてもう 1 つは押し込みを行うバージョン用です。
  • レイヤーを押し込むことで、より小さなイメージが生成されますが、性能劣化を引き起こすことがあります。 単一のレイヤーであるために伸張(解凍)には処理時間が余計にかかります。 また単一のレイヤーは、同時並行によるダウンロード処理ができません。
  • イメージの押し込み処理を行うにあたって、そのイメージがファイルシステムへの変更を行っていない場合(たとえば Dockerfile にENV命令しかない場合)、押し込み処理は失敗します。 (issue #33823 を参照してください。)

前提条件

本ページに示す利用例においては、Docker 19.03 の試験的(experimental)モードを利用しています。

試験的モードは、Docker デーモンの起動時に--experimentalフラグをつけることで有効になります。 あるいは設定ファイルdaemon.jsonにおいてexperimental: trueを設定します。

デフォルトで試験的モードは無効になっています。 Docker デーモンの現在の設定を確認するにはdocker versionコマンドを実行してEngineセクションのExperimentalの行に示されています。

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フラグをつけて実行する必要があります。 あるいは/etc/docker/daemon.jsonにおいて、以下のようにしてデーモンフラグを有効にすることもできます。

{
    "experimental": true
}

試験的フラグが有効になっていることを確認します。

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

--squash引数をつけたイメージのビルド

以下では、--squash引数をつけて docker build を実行する例を示します。

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 .

<...>

正常に処理されれば、履歴が以下のように表示されます。

$ 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の中身はhello\nworld、環境変数HELLOの値はworldとなっていることをそれぞれ確認してください。

上位コマンド

コマンド 説明
docker Docker CLI の基本コマンド