BuildKit でイメージ構築

Docker Build は Docker Engine で最も使われる機能の1つです。利用者の幅は、利用者、開発チーム、リリースチーム、全てが Docker Build を使います。

18.09 のリリースで導入されたのは、構築アーキテクチャの見直しが非常に求められていた、 Docker Build の拡張です。BuildKit (ビルドキット)の統合により、性能、ストレージ管理、特徴的な機能性、セキュリティに関する改善が利用者に分かるでしょう。

  • BuildKit が作成した Docker イメージは、以前のビルドが作成した Docker イメージ同様、 Docker Hub に送信可能です
  • Dockerfile の形式は、以前の Build の動作と同様に、 BuitKit の構築でも動作します
  • ユーザは Dockerfile で指定した新しいイメージの構築は、新しい --secret コマンドライン・オプションでシークレット(機微)情報をパスします(訳者注、イメージに記録しません)

build オプションに関する詳しい情報は、リファレンスガイド上の コマンドライン build オプション をご覧ください。

必要条件

  • Docker の最新版(18.09 以上)
  • カスタム・フロントエンドのイメージをダウンロードするには、ネットワーク接続が必要

制限事項

  • Linux コンテナの構築のみサポート

BuildKit での構築を有効化

Docker の新規インストールが最も簡単で、 docker build コマンドの実行時に DOCKER_BUILDKIT` 環境変数を次のように指定します。

$ DOCKER_BUILDKIT=1 docker build .

デフォルトで docker BuildKit を有効化するには、 /etc/docker/daemon.json のデーモン設定で機能を 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

デフォルトのフロントエンドを上書き

デフォルトのフロントエンドを上書きすると、 Dockerifle で新しい構文機能が利用可能です。デフォルトのフロントエンドを上書きするには、 Dockerfile の1行目に、特定のフロントエンド・イメージをコメントとして指定します。

# syntax = <frontend image>, e.g. # syntax = docker/dockerfile:1.0-experimental

新しい Docker Build シークレット情報

docker build の新しい --secret フラグは、Dockerfile でシークレット情報(機微情報)をユーザが渡す必要があるときに、docker イメージを安全に構築するための方法であり、最終イメージにシークレットを保存しません。

iddocker build --secret を渡すための識別子です。この識別子は Dockerfile 中で使う RUN --mount 識別子と関連付けられます。この情報はセンシティブな情報となりうるため、Docker は secret がどこにあるかをファイル名を使わずに、Dockerfile の外で保持します。

dst はシークレット用のファイルを、 Dockerfile の RUN コマンドで使う特定のファイルに名称変更します。

たとえば、テキストファイル中に秘密情報の一部を保存します。

$ echo 'WARMACHINEROX' > mysecret.txt

そして、Dockerfile 側では、Buildkit フロントエンド docker/dockerfile:1.0-experimental を使う指定をしたら、シークレット機能が利用できます。

例:

# syntax = docker/dockerfile:1.0-experimental
FROM alpine

# デフォルトのシークレットの場所から、シークレットを表示
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret

# 任意のシークレットの場所から、シークレットを表示
RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar

この 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 に詳しい情報と例がありますのでご覧ください。

docker build--ssh オプションを付けると、 Docker Engine は SSH エージェント接続の転送が可能になります。SSH エージェントに関する情報は OpenSSH の man ページ をご覧ください。

Dockerfile 中の命令で、 type=ssh マウントの定義で明確に SSH アクセスを要求すると、SSH エージェントとの接続が可能になります。その他の方法では、SSH エージェントと通信することはできません。

Dockerfile 中で RUN コマンドで SSH アクセスの要求をするには、マウント時のタイプを ssh と定義します。これは SSH_AUTH_SOCK 環境変数をセットアップし、プログラムが SSH でそのソケットを自動的に使うのに依存します。

こちらはコンテナ内で SSH を使う Dockerfile の例です:

# syntax=docker/dockerfile:experimental
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

Dockerfile が作成されれば、 --ssh オプションを使ってで SSH エージェントと接続できます。

$ docker build --ssh default .

トラブルシューティング:プライベート・レジストリでの問題

x509:未知の認証局によって書名された証明書

安全ではない(自己書名した証明書の)レジストリ(insecure registry)からイメージを取得しようとすると、あるいはレジストリをミラーとして使おうとすると、Docker 18.09 では以下の問題に直面します。

[+] 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 以上にアップグレードします。