docker build
読む時間の目安: 14 分
説明
Dockerfile からイメージをビルドします。
利用方法
$ docker build [オプション] PATH | URL | -
追加説明
docker build
コマンドは Dockerfile と「ビルドコンテキスト」から Docker イメージをビルドします。
ビルドコンテキストとは、指定された PATH
や URL
に存在している一連のファイルのことです。
ビルド処理においては、コンテキスト内のどのファイルでも参照できます。
たとえばビルドにおいて 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
を介してパイプ入力します。
Dockerfile
を STDIN
からパイプ入力するには、以下のようにします。
$ 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
は、イメージをビルドする際に利用するDockerfile
をctx.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:latest
とwhenry/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
に指定するのはカンマ区切りの文字列であり、これによってエクスポーターのタイプとオプションを指定します。
今のところサポートされるエクスポーターはlocal
とtar
だけです。
local
エクスポーターは、生成されるビルドファイルを、クライアント側のディレクトリに書き込みます。
tar
エクスポーターはそれと同様ですが、ファイルの書き込みは 1 つの tarball(.tar
)とします。
タイプが指定されていない場合、デフォルトは local エクスポーターの出力ディレクトリになります。
ハイフン(-
)を指定すると、出力する tarball を標準出力(STDOUT
)に出力します。
以下の例では、ビルドコンテキストをカレントディレクトリ(.
)としてイメージをビルドします。
そして出力ファイルを、カレントディレクトリにあるout
というディレクトリにエクスポートします。
そのディレクトリが存在しない場合、Docker はそのディレクトリを自動生成します。
$ docker build -o out .
上の例では短いオプション指定を用いておりtype
オプションは省略していました。
したがってデフォルトの(local
)エクスポーターが用いられます。
以下の例では同等の指定を長いオプション指定で行い、CSV によってtype
とdest
(出力パス)を指定しています。
$ 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=registry
とmode=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 の基本コマンド |