BuildKit でイメージ構築¶
Docker Build は Docker Engine で最も使われる機能の1つです。利用者、開発チーム、リリースチームに至る利用者の全てが Docker Build を使います。
リリース 18.09 では、強く求められていた構築方式が見直され、 Docker Build の拡張が導入されました。利用者は
BuildKit が作成した Docker イメージは、これまでの構築で作成した Docker イメージ同様、 Docker Hub に送信可能
Dockerfile の書式は、従来の構築用だけでなく、 BuitKit による構築でも動作
Dockerfile で新しいイメージの構築時、新しい
--secret
コマンドライン オプションを使えば、機微情報 (シークレット)を(コマンドライン上で)渡せるようになる
build オプションに関する詳しい情報は、リファレンスガイド上の コマンドライン build オプション と Dockerfile リファレンス ページ をご覧ください。
BuildKit での構築を有効化するには¶
Docker の新規インストールが最も簡単で、 docker build
コマンドの実行時に DOCKER_BUILDKIT
環境変数を次のように指定します。
$ DOCKER_BUILDKIT=1 docker build .
デフォルトで docker BuildKit を有効化するには、 /etc/docker/daemon.json
にあるデーモンの設定で、(buildkit の)機能を true にしてから、デーモンを再起動します。
{ "features": { "buildkit": true } }
新しい Docker Build コマンドラインによる構築の出力¶
新しい docker build BuildKit TTY 出力(デフォルト):
$ docker build .
[+] Building 70.9s (34/59)
=> [runc 1/4] COPY hack/dockerfile/install/install.sh ./install.sh 14.0s
=> [frozen-images 3/4] RUN /download-frozen-image-v2.sh /build buildpa 24.9s
=> [containerd 4/5] RUN PREFIX=/build/ ./install.sh containerd 37.1s
=> [tini 2/5] COPY hack/dockerfile/install/install.sh ./install.sh 4.9s
=> [vndr 2/4] COPY hack/dockerfile/install/vndr.installer ./ 1.6s
=> [dockercli 2/4] COPY hack/dockerfile/install/dockercli.installer ./ 5.9s
=> [proxy 2/4] COPY hack/dockerfile/install/proxy.installer ./ 15.7s
=> [tomlv 2/4] COPY hack/dockerfile/install/tomlv.installer ./ 12.4s
=> [gometalinter 2/4] COPY hack/dockerfile/install/gometalinter.install 25.5s
=> [vndr 3/4] RUN PREFIX=/build/ ./install.sh vndr 33.2s
=> [tini 3/5] COPY hack/dockerfile/install/tini.installer ./ 6.1s
=> [dockercli 3/4] RUN PREFIX=/build/ ./install.sh dockercli 18.0s
=> [runc 2/4] COPY hack/dockerfile/install/runc.installer ./ 2.4s
=> [tini 4/5] RUN PREFIX=/build/ ./install.sh tini 11.6s
=> [runc 3/4] RUN PREFIX=/build/ ./install.sh runc 23.4s
=> [tomlv 3/4] RUN PREFIX=/build/ ./install.sh tomlv 9.7s
=> [proxy 3/4] RUN PREFIX=/build/ ./install.sh proxy 14.6s
=> [dev 2/23] RUN useradd --create-home --gid docker unprivilegeduser 5.1s
=> [gometalinter 3/4] RUN PREFIX=/build/ ./install.sh gometalinter 9.4s
=> [dev 3/23] RUN ln -sfv /go/src/github.com/docker/docker/.bashrc ~/.ba 4.3s
=> [dev 4/23] RUN echo source /usr/share/bash-completion/bash_completion 2.5s
=> [dev 5/23] RUN ln -s /usr/local/completion/bash/docker /etc/bash_comp 2.1s
新しい docker build BuildKit による、そのままの出力。
$ docker build --progress=plain .
#1 [internal] load .dockerignore
#1 digest: sha256:d0b5f1b2d994bfdacee98198b07119b61cf2442e548a41cf4cd6d0471a627414
#1 name: "[internal] load .dockerignore"
#1 started: 2018-08-31 19:07:09.246319297 +0000 UTC
#1 completed: 2018-08-31 19:07:09.246386115 +0000 UTC
#1 duration: 66.818µs
#1 started: 2018-08-31 19:07:09.246547272 +0000 UTC
#1 completed: 2018-08-31 19:07:09.260979324 +0000 UTC
#1 duration: 14.432052ms
#1 transferring context: 142B done
#2 [internal] load Dockerfile
#2 digest: sha256:2f10ef7338b6eebaf1b072752d0d936c3d38c4383476a3985824ff70398569fa
#2 name: "[internal] load Dockerfile"
#2 started: 2018-08-31 19:07:09.246331352 +0000 UTC
#2 completed: 2018-08-31 19:07:09.246386021 +0000 UTC
#2 duration: 54.669µs
#2 started: 2018-08-31 19:07:09.246720773 +0000 UTC
#2 completed: 2018-08-31 19:07:09.270231987 +0000 UTC
#2 duration: 23.511214ms
#2 transferring dockerfile: 9.26kB done
デフォルトのフロントエンドを上書き¶
# syntax=<frontend image>, e.g. # syntax=docker/dockerfile:1.2
このページの例では、 docker/dockerfile
バージョン 1.2.0 以上で利用可能な機能を使います。ですが、私たちは docker/dockerfile:1
の利用を推奨します。こちらであれば、常にバージョン1構文の最新リリースを示すからです。BuildKit は構築前に構文の更新を自動的に確認し、最新の安定バージョンを使っているかどうかを常に確認します。 syntax
命令について学ぶには、 Dockerfile リファレンス をご覧ください。
Docker Build の新しいシークレット情報¶
docker build の新しい --secret
フラグは、利用者が Dockerfile で
id
とは、 docker build --secret
で(シークレットを)渡すための RUN --mount
識別子と関連付けられます。これは、 Dockerfile の外で持つシークレットがどこにあるのかは、ファイル名が機微情報になり得るため、Docker ではファイル名を(直接)扱いません。
Dockerfile 内の RUN
コマンドの使用時に、シークレット ファイルを dest
で指定するファイルに名称変更します。
たとえば、機微情報の一部をテキストファイル中に保存します。
$ echo 'WARMACHINEROX' > mysecret.txt
そして、Dockerfile 側では、Buildkit フロントエンド docker/dockerfile:1.2
を使う指定をすると、 RUN
命令の処理時にシークレットを利用できます。
# syntax = docker/dockerfile:1.2
FROM alpine
# デフォルトのシークレットの場所から、シークレットを表示
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
# 任意のシークレットの場所から、シークレットを表示
RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
シークレットを使うには、構築時に --secret
フラグを使って渡す必要があります。この Dockerfile はシークレットがアクセス可能であるという実証用途です。ご覧の通り、シークレットは構築時の出力で表示されます。最終イメージの構築では、このシークレット・ファイルを(イメージ内に)保持しません。
$ docker build --no-cache --progress=plain --secret id=mysecret,src=mysecret.txt .
...
#8 [2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
#8 digest: sha256:5d8cbaeb66183993700828632bfbde246cae8feded11aad40e524f54ce7438d6
#8 name: "[2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret"
#8 started: 2018-08-31 21:03:30.703550864 +0000 UTC
#8 1.081 WARMACHINEROX
#8 completed: 2018-08-31 21:03:32.051053831 +0000 UTC
#8 duration: 1.347502967s
#9 [3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
#9 digest: sha256:6c7ebda4599ec6acb40358017e51ccb4c5471dc434573b9b7188143757459efa
#9 name: "[3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar"
#9 started: 2018-08-31 21:03:32.052880985 +0000 UTC
#9 1.216 WARMACHINEROX
#9 completed: 2018-08-31 21:03:33.523282118 +0000 UTC
#9 duration: 1.470401133s
...
構築時に SSH で 内部データ にアクセス¶
参考
Build secrets and SSH forwarding in Docker 18.09 に詳しい情報と例がありますのでご覧ください。
Dockerfile
内のコマンドによっては、プライベート リポジトリをクローンするような、 SSH 認証の指定が必要となる場合があります。秘密鍵をイメージにコピーしてしまうと、一般公開してしまう危険性があります。コピーするのではなく、 docker build
でイメージの構築時に、ホストシステム上の ssh へのアクセスする方法があります。
この手順には、3つの過程があります。
1番目は、 ssh-add
を実行し、認証エージェントに対して秘密鍵(identity)を追加します。もしも複数の SSH 鍵があり、デフォルトの id_rsa
でリソースにアクセスできるかどうか疑わしい場合は、 ssh-add ~/.ssh/<他の何らかの鍵>
で鍵のパスを追加する必要があります(SSH エージェントの詳しい情報は、 OpenSSH の man ページ をご覧ください。)。
2番目は、 docker build
コマンドの実行時、 --ssh
オプションを使い、既存の SSH エージェントへ接続するソケットを指定します。たとえば、 --ssh default=$SSH_AUTH_SOCK
や、同等の省略形の --ssh default
です。
3番目は、その SSH アクセスを Dockerfile
内の RUN
命令で使えるようにするため、 ssh
タイプとしてマウントを定義します。これにより、 docker build
時にホスト上で提供された値が SSH_AUTH_SOCK
環境変数に指定され、結果として RUN
命令内のあらゆるプログラムが、SSH で自動的にそのソケットを使うよう依存します。type=ssh
マウントの定義があれば、 SSH アクセスを明示的に要求する Dockerfile
内のコマンドのみが、SSH エージェントへ接続できます。他のコマンドは、どのような SSH エージェントが利用可能かどうかを一切知りません。
こちらはコンテナ内で SSH を使う Dockerfile
の例です:
# syntax=docker/dockerfile:1
FROM alpine
# ssh クライアントと git をインストール
RUN apk add --no-cache openssh-client git
# github.com のための公開鍵をダウンロード
RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
# プライベート・リポジトリのクローン
RUN --mount=type=ssh git clone git@github.com:myorg/myproject.git myproject
イメージの構築は、以下のようにします。
$ docker build --ssh default .
--mount=type=secret
と同様、構築するたびに複数のソケットを使い分けたい場合には、 id
を指定できます。たとえば、 docker build --ssh main=$SSH_AUTH_SOCK --ssh other=$OTHER_SSH_AUTH_SOCK
のように実行できます。 Dockerfile
内で、これら2つのソケットを使うには RUN --mount=type=ssh,id=main
か RUN --mount=type=ssh,id=other
とします。もしも --mount=type=ssh
のように id
を指定しなければ、 default
が想定されます。
トラブルシューティング:プライベート・レジストリでの問題¶
x509:未知の認証局によって書名された証明書¶
(自己書名した証明書を使う)
[+] Building 0.4s (3/3) FINISHED
=> [internal] load build definition from Dockerfile
=> => transferring dockerfile: 169B
=> [internal] load .dockerignore
=> => transferring context: 2B
=> ERROR resolve image config for docker.io/docker/dockerfile:experimental
------
> resolve image config for docker.io/docker/dockerfile:experimental:
------
failed to do request: Head https://repo.mycompany.com/v2/docker/dockerfile/manifests/experimental: x509: certificate signed by unknown authority
解決策:適切にレジストリを安全にします。 Let's Encrypt の SSL 証明書は無料で取得できます。 レジストリ・サーバのデプロイ をご覧ください。
Sonatype Nexus バージョン 3.15 未満の上でプライベート・レジストリを実行中に、イメージが見つからない¶
Sonatype Nexus バージョン 3.15 未満を使い、プライベート・レジストリを事項中であれば、以下のようなエラーメッセージが表示されるでしょう。
------
> [internal] load metadata for docker.io/library/maven:3.5.3-alpine:
------
------
> [1/4] FROM docker.io/library/maven:3.5.3-alpine:
------
rpc error: code = Unknown desc = docker.io/library/maven:3.5.3-alpine not found
おそらくこのバグに直面しました: NEXUS-12684
解決策は、Nexus をバージョン 3.15 以上にアップグレードします。
参考
- Build images with BuildKit
https://docs.docker.com/develop/develop-images/build_enhancements/