More Related Content Similar to Dockerfileを改善するためのBest Practice 2019年版 (20) More from Masahito Zembutsu (20) Dockerfileを改善するためのBest Practice 2019年版2. DockerCon SF19 での発表に基づく内容
• Dockerfile Best Practices
https://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices
2
• 動画もご覧ください
https://www.docker.com/dockercon/2019-videos?watch=dockerfile-best-practices
オリジナルの発表は Tibor Vass 氏( @tiborvass) および Sebastian van Stijin 氏(@thajeztha)
による、 DockerCon 毎回恒例人気セッション"Dockerfile Best Practices" であり、両者に感謝します。
I thank you both for your excellent presentation of DockerCon. I also appreciate your permission to translate the content.
Please refer to this slides. And, this presentation video
will also be helpful.
3. このスライドは何?
3
⚫ DockerCon 19 で発表された人気シリーズ
“Best Practices” を日本訳+解説の追加。
⚫ Dockerfile の改善を通して、現在利用できる
マルチ・ステージ・ビルドや BuildKit 紹介。
以上の内容です。
※ "Docker Meetup Kansai #3" 発表時のスライドをベースに、
スライドそのままでは分かりづらい部分があるため、
一部で発表時と異なる表現・補足説明を用いている場合があります。
ゴール:
「Dockerfileの改善を具体的に理解」
4. Dockerfileのベストプラクティス
• "Best practices for writing Dockerfiles"
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
4
最新の日本語訳を公開しました。
そもそもの基本となるのは、"Dockerfileを書くためのベストプラクティス"です。
7. Dockerfile
• Docker は Dockerfile から命令を読み込み、イメージを自動構築
• テキスト形式のドキュメント
• docker build / docker image build で Dockerfile を読み込み構築
• 「Docker イメージを作るための設計図」
• FROM、ADD、CMD など命令文で構成
• 例) 何のイメージをもとに、何を実行するか?
• 誰でも確実にイメージを構築できる
• イメージの構築過程を確認できる
• Dockerfileは広く使われている
• GitHub上に Dockerfile は100万以上
7
automate build
blueprint
Image by John Dortmunder from Pixabay
「Dockerfile」はDockerイメージを自動構築するために、必ず使うファイルです。
8. BuildKit: builder v2
• docker build は「イメージ・キャッシュ」があるため、素早く開発できる
• しかし、いくつかの制限があったため、buildKit プロジェクトで根本的に構築
• https://github.com/moby/buildkit
• "ゴールは Docker build のデフォルト"
• BuildKit: 特長
• 同時へいれt性(concurrency)
• 断片的なコンテキスト・アップロード (lazy context upload)
• キャッシュの改良
• 新しい Dockerfile 機能の追加
8
⚫並列性が無い
⚫docker run と同様に root で動作する必要性
⚫ボリューム機能が無い
高速にイメージを作れる BuildKit という汎用ツールが開発途上です。
9. Docker BuildKit を使う方法
• クライアントの環境変数
• Docker デーモン設定ファイル /etc/docker/daemon.json
• 現時点では Windows は対応していない
• Windows support coming soon!
9
{ "features": { "buildkit": true }}
export DOCKER_BUILDKIT=1
BiuldKit は Docker とは別のプロジェクト (https://github.com/moby/buildkit ) ですが、
現在の Docker CE v18.09 では、BuildKit の一部機能が既に利用できる状態です。
11. Dockerfile の改善領域
• 増大するbuild 時間
• イメージ容量
• 保守性
• 安全性
• 一貫性・反復性
11
(Incremental) build time
Image size
Maintainability
Security
Consistency/Repetability
ここからは、先日開催された DockerCon SF19での発表サンプルをベースにご紹介します。
サンプルのアプリケーションを使い、5つの視点で Dockerfile を改善する流れをみていきましょう。
12. サンプルの Dockerfile をカイゼンするぞ!
12
FROM debian
COPY . /app
RUN apt-get update
RUN apt-get –y install openjdk-8-jdk ssh emacs
CMD ["java", "-jar", "/app/target/app.jar"]
これは、Javaで"Hello world"を表示するための、サンプルプログラム用の Dockerfile です。
13. サンプルの Dockerfile をカイゼンするぞ!
13
FROM debian
COPY . /app
RUN apt-get update
RUN apt-get –y install openjdk-8-jdk ssh emacs
CMD ["java", "-jar", "/app/target/app.jar"]
vim
まずすべきは、emacs を消して、vim を入れましょう。もちろんジョークですが!
14. サンプルの Dockerfile をカイゼンするぞ!
14
FROM debian
COPY . /app
RUN apt-get update
RUN apt-get –y install openjdk-8-jdk ssh emacs
CMD ["java", "-jar", "/app/target/app.jar"]
vim
まずすべきは、emacs を消して、vim を入れましょう。もちろんジョークですが!
16. キャッシュする順番が重要
16
FROM debian
COPY . /app
RUN apt-get update
RUN apt-get –y install openjdk-8-jdk ssh vim
COPY . /app
CMD ["java", "-jar", "/app/target/app.jar"]
頻繁に変更するものを後ろへ
構築時のキャッシュとは、変更箇所があれば破棄されます。この例の COPY では「.」(カレント)にある
ファイルに変更があれば、毎回「apt-get update」と「install」が走るので、時間がかかってしまいます。
せっかくあrキャッシュを有効活用するには、頻繁に更新する可能性があるものを後ろにおきます。
17. キャッシュする順番が重要
17
FROM debian
COPY . /app
RUN apt-get update
RUN apt-get –y install openjdk-8-jdk ssh vim
COPY . /app
CMD ["java", "-jar", "/app/target/app.jar"]
頻繁に変更するものを後ろへ
構築時のキャッシュとは、変更箇所があれば破棄されます。この例の COPY では「.」(カレント)にある
ファイルに変更があれば、毎回「apt-get update」と「install」が走るので、時間がかかってしまいます。
せっかくあrキャッシュを有効活用するには、頻繁に更新する可能性があるものを後ろにおきます。
キャッシュ有効
キャッシュ破棄 … ホスト側「 ./ 」に変更時
キャッシュ破棄 … ホスト側「 ./ 」に変更時
時間がかかるので、キャッシュ活用すべし
時間かかる
18. キャッシュ破棄の影響を避けるため、範囲を狭く
18
FROM debian
RUN apt-get update
RUN apt-get –y install openjdk-8-jdk ssh vim
COPY . /app
COPY target/app.jar /app
CMD ["java", "-jar", "/app/target/app.jar"]
コピーに必要なものを明示する。
可能であれば "COPY ."を避ける
コピーすべき場所を絞っておけば、キャッシュは破棄されません。
この例では「app.jar」しか「COPY」しませんので、他のファイルに変更があってもキャッシュを保持。
19. キャッシュ破棄の影響を避けるため、範囲を狭く
19
FROM debian
RUN apt-get update
RUN apt-get –y install openjdk-8-jdk ssh vim
COPY . /app
COPY target/app.jar /app
CMD ["java", "-jar", "/app/target/app.jar"]
コピーすべき場所を絞っておけば、キャッシュは破棄されません。
この例では「app.jar」しか「COPY」しませんので、他のファイルに変更があってもキャッシュを保持。
キャッシュ有効
キャッシュ有効
キャッシュ有効
ちょっとキャッシュする範囲が拡がるかもね
キャッシュ対象の明確化
コピーに必要なものを明示する。
可能であれば "COPY ."を避ける
20. 行をまとめる: apt-get update & install
20
FROM debian
RUN apt-get update
RUN apt-get –y install openjdk-8-jdk ssh vim
RUN apt-get update ¥
&& apt-get -y install ¥
openjdk-8-jdk ssh vim
COPY target/app.jar /app
CMD ["java", "-jar", "/app/target/app.jar"]
古いパッケージ情報のキャッシュ利用を避ける
パッケージ・マネージャを使う場合、「古い」パッケージ情報をキャッシュしがちです。
更新したいのに更新できないのを避けるには、情報の更新と、パッケージ追加・削除をまとめること。
21. 行をまとめる: apt-get update & install
21
FROM debian
RUN apt-get update
RUN apt-get –y install openjdk-8-jdk ssh vim
RUN apt-get update ¥
&& apt-get -y install ¥
openjdk-8-jdk ssh vim
COPY target/app.jar /app
CMD ["java", "-jar", "/app/target/app.jar"]
古いパッケージ情報のキャッシュ利用を避ける
パッケージ・マネージャを使う場合、「古い」パッケージ情報をキャッシュしがちです。
更新したいのに更新できないのを避けるには、情報の更新と、パッケージ追加・削除をまとめること。
キャッシュ有効
古いものをキャッシュしてるかも!
時間かかる場合があっても、確実に処理
23. 不要な依存関係を削除
23
FROM debian
RUN apt-get update ¥
&& apt-get -y install --no-install-recommends ¥
openjdk-8-jdk ssh vim
COPY target/app.jar /app
CMD ["java", "-jar", "/app/target/app.jar"]
デプロイを素早くするためには、イメージ容量の削減が重要であり、必須課題。
推奨パッケージ(必須ではない)を避けるためには、「--no-install-recommends」フラグを付ける。
Javaの実行に不要なパッケージも入れないので「ssh」「vim」も消す。
24. 不要なパッケージマネージャのキャッシュ削除
24
FROM debian
RUN apt-get update ¥
&& apt-get -y install –no-install-recommends ¥
openjdk-8-jdk ¥
&& rm –rf /var/lib/apt/lists/*
COPY target/app.jar /app
CMD ["java", "-jar", "/app/target/app.jar"]
パッケージ・マネージャのキャッシュ情報も、アプリケーションの実行に不要なので削除
27. 27
FROM debian
RUN apt-get update ¥
&& apt-get -y install –no-install-recommends ¥
openjdk-8-jdk ¥
&& rm –rf /var/lib/apt/lists/*
FROM openjdk
COPY target/app.jar /app
CMD ["java", "-jar", "/app/target/app.jar"]
できるだけDocker公式(official)パッケージを使う
Javaの実行であれば、「openjdk」イメージがあるため、debianでセットアップする必要はない
30. 必要最小限のものを探す
30
REPOSITORY TAG SIZE
openjdk 8 624MB
openjdk 8-jre 443MB
openjdk 8-jre-slim 204MB
openjdk 8-jre-alpie 83MB
ベース・イメージの変更だけで
540MBも削減
どのイメージ(タグ)を選ぶかによって、容量がかなり異なる。
alpineタグは Alpine Linux という約 5MB の Linux ディストリビューションがベース
33. 一貫した環境を、ソースから構築する
• Dockerfile を設計図(青写真)にしよう:
• ビルド時するための構築環境を Dockerfile に記述
• 正しいバージョンのビルド・ツールをインストール
• 環境ごとの違いを発生させない
• システム依存はあるかもしれない
• "source of truth"(本当のソース)とは、
ソースコードである。ビルド成果物ではない。
33
Image by John Dortmunder from Pixabay
blue print
開発環境、テスト環境、実行環境で共通する Dockerfile を目指す
38. マルチ・ステージ・ビルドで、構築時の部分を削除
38
FROM maven:3.6-jdk-8-alpine AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn –e –B dependency:resolve
COPY src ./src
RUN mvn –e –B package
CMD ["java", "-jar", "/app/target/app.jar"]
FROM openjdk:8-jre-alpine
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app/target/app.jar"]
そこで、マルチ・ステージ・ビルドで複数の「FROM」を使い、構築時(AS bilder)と実行時を分離
←「builder」ステージから
ファイルをコピー
←ステージ「builder」と名前を付ける
39. マルチ・ステージ・ビルドで、構築時の部分を削除
39
FROM maven:3.6-jdk-8-alpine AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn –e –B dependency:resolve
COPY src ./src
RUN mvn –e –B package
FROM openjdk:8-jre-alpine
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app/target/app.jar"]
マルチ・ステージ・ビルドでは、「docker build」は全てのビルドを実行しますし、
「docker build –target builder」と指定すると「AS builder」の「FROM」ステージしか処理しません。
41. プロジェクトごとに多くのステージがある
• Moby: 16 ステージ
https://github.com/moby/moby/blob/master/Dockerfile
• BuildKit: 44 ステージ
https://github.com/moby/buildkit/blob/master/hack/dockerfiles
/test.buildkit.Dockerfile
41Docker 関連プロジェクトの Dockerfile にも、多くのステージ(FROM命令)がある
43. 構築ステージを --target で指定
43
FROM image_or_stage AS stage_name
…
$ docker build --target stage_name
「AS ステージ名」を FROM 命令に書いておけば、「docker build」時に「--target」でステージを指定
44. イメージの flavor を変える
44
FROM maven:3.6-jdk-8-alpine AS builder
...
FROM openjdk:8-jre-jessie AS release-jessie
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app.jar"]
FROM openjdk:8-jre-jessie AS release-alpine
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app.jar"]
$ docker build --target release-jessie .
Debian jessie (8.x) をベースとするイメージと、Alpine Linux をベースとするイメージ。
特色(風味)
45. 45
FROM maven:3.6-jdk-8-alpine AS builder
...
FROM openjdk:8-jre-jessie AS release-jessie
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app.jar"]
FROM openjdk:8-jre-jessie AS release-alpine
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app.jar"]
$ docker build --target release-jessie .
イメージの flavor を変える
特色(風味)
しかし、 Dockerfile をよく見ると問題があり、
46. 46
FROM maven:3.6-jdk-8-alpine AS builder
...
FROM openjdk:8-jre-jessie AS release-jessie
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app.jar"]
FROM openjdk:8-jre-jessie AS release-alpine
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app.jar"]
$ docker build --target release-jessie .
このように各ステージで、同じ命令が重複する箇所がある。
イメージの flavor を変える
特色(風味)
どちらも
同じ
47. 47
ARG flavor=alpine
FROM maven:3.6-jdk-8-alpine AS builder
...
FROM openjdk:8-jre-$flavor AS release
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app.jar"]
$ docker build --target release
--build-arg flavor=jessie .
「ARG」を Dockerfile で指定しておくと、docker build 時に「--build-arg」を通して、変数のように展開
--build-arg で $flavor=xxx があれば、$flavor に xxx 代入
↓何もなければ「flavor=alpine」が適用
イメージの flavor を変える (DRY / 汎用的な ARG)
特色(風味)
※ DRY = “Don’t Repeat Yourself”(自分では繰り返さない)という
ソフトウェア開発の手法
引数
←ARG命令は、docker build時に指定できる変数を定義
書式は「変数名」または「変数名=デフォルト値」。
48. 様々な環境:構築、開発、テスト、構文チェック(lint)…
• ステージとしての検討例:
⁃ builder: 依存関係すべてをビルド
⁃ build(または binary): builder + ビルド成果物
⁃ cross: 複数のプラットフォーム向けに構築
⁃ dev: build(er) + 開発/デバッグツール
⁃ lint: 最小限の構文チェック用依存関係
⁃ test: テストに関係する全ての依存関係 + テスト対象のビルド成果物
⁃ release: ビルド成果物を含む、最終的な最小イメージ
48様々な「ステージ」が検討できる。ここでは定型的な例
各ステージでは、依存関係が最小となるようにする
49. 様々な環境:構築、開発、テスト、構文チェック(lint)…
49
FROM maven:3.6-jdk-8-alpine AS builder
...
FROM openjdk:8-jre-alpine AS lint
RUN wget https://github.com/checkstyle/checkstyle/releases/download/checkstyle-8.15/checkstyle-8.15-all.jar
COPY checks.xml .
COPY src /src
RUN java –jar checkstyle-8.15-all.jar –c checks.xml /src
これはシンプルな Java 構文チェック(リント)の確認用の Dockerfile を「AS lint」と指定
50. 様々な環境:構築、開発、テスト、構文チェック(lint)…
50
FROM maven:3.6-jdk-8-alpine AS builder
...
FROM openjdk:8-jre-alpine AS release
COPY --from=builder /app/target/app.jar /
CMD ["java", "-jar", "/app.jar"]
FROM builder AS dev
RUN apk add --no-cache strace vim tcpdump
ENTRYPOINT ["ash"]
開発用デバッグ環境であれば、「builder」ステージをベースにしながら「AS dev」と明示し
シンプルにエディタ(vim)と tcpdump を入れている
53. 一直線の Dockerfile ステージから …
• 全てのステージが順番(シーケンシャル)に実行
• この図では、上から下に一直線
• BuildKitがなければ、
不要なステージも無駄に実行し、破棄する
(無駄に時間がかかった)
53
s1
s2
s3
s4
s5
s6
デフォルトでは、全てのステージを順番に実行する
54. BuildKit のマルチ・ステージ graph へ
• BuildKit は下(--target のステージ名)から上に辿っていくような流れ
• 右図では s2, s3, s4 ステージを同時並行処理
• 不要なステージは無視できる
• 右図では s5 がビルド時に
不要であれば、何もしない
54
s1
s2 s3 s4
s5s6
Docker 17.05 からマルチ・ステージ・ビルドが利用可能になった。
18.06までは experimental 、18.09 は利用できるように組み込まれている
グラフ
※グラフは点と点とのつながり
(関係性)を表す
55. Multi-srage: 並行ビルド (build concurrently)
55
FROM maven:3.6-jdk-8-alpine AS builder
...
FROM tiborvass/whalesay AS assets
RUN whalesay "Hello DockerCon!" > /out/assets.html
FROM openjdk:8-jre-alpine AS release
COPY --from=builder /app/target/app.jar /
COPY --from=assets /out /assets
CMD ["java", "-jar", "/app.jar"]
「assets」は最終イメージ(release)に必要だが、別のステージとして処理できる
そして、この Dockerfile は「builder」と「assets」のステージからのコピーを並行処理
56. Multi-srage: 並行ビルド (build concurrently)
56
FROM maven:3.6-jdk-8-alpine AS builder-base
…
FROM gcc:8-alpine AS builder-someClib
…
RUN git clone … ¥
./configure --prefix=/out && make && make install
FROM g++:8-alpine AS builder-someCPPlib
…
RUN git clone … ¥
cmake …
FROM builder-base AS builder
COPY --from=builder-someClib /out /
COPY --from=builder-someCPPlib /out /
複数の COPY 命令を使う時には、特に効果を発揮し、時間を節約できる
並行処理が有用な典型的なパターンが
複数の COPY --from … の繰り返し
57. ベンチマーク
• github.com/moby/moby Dockerfile, master ブランチ
• 小さいほうが優れている
57
Dockerfile Best Practices
https://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices/52
v18.03 の docker build と BuiltKit では2倍の速さ
59. ベンチマーク
• github.com/moby/moby Dockerfile, master ブランチ
• 小さいほうが優れている
59
Dockerfile Best Practices
https://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices/52
最も大事なのは、ソースコードの変更時。再構築の速度はマルチ・ステージ・ビルドで 2.5 倍に改善。
63. コンテキスト・マウント(v18.09+ w/ BuildKit)
63
# syntax=docker/dockerfile:1.0-experimental
FROM maven:3.6-jdk-8-alpine AS builder
WORKDIR /app
COPY . /app
RUN --mount=target=. mvn -e –B package -DoutputDirectory=/
FROM openjdk:8-jre-alpine
COPY --from=builder /app/app.jar /
CMD ["java", "-jar", "/app.jar"]
新機能を使って Dockerfile を書き換えていく。まずはマウント・オプション。
実行時に「.」(カレント・ディレクトリ内容)を Build Context として送信せず、マウントできる
※ Docker v18.09 以上かつ、BuildKit 有効化の状態で利用可能
contest mounts
64. Dockerfile
hello
コンテキスト・マウント(v18.09+ w/ BuildKit)
64
ディレクトリ内容をコンテナに COPY しなくても、
ビルド時に docker build コマンドを実行しているディレクトリ(ここでは 「target=.」で指定)を
rw(読み書き可能な状態)で直接コンテナにマウントし、
コンテナ内で「cat hello > /hello.txt」を実行
→ 構築したイメージの“/hello.txt” に “Hello world!” が書かれたファイルが作成される
# syntax=docker/dockerfile:1.0-experimental
FROM alpine
RUN --mount=type=bind,target=.,rw cat hello > /hello.txt
Hello world!
ソースコードなど、ビルド・コンテクストのコピーが不要となり、より早いビルドができる
contest mounts
• Dockerfile の mount 例:
ホスト側の docker build する場所に、
このファイルがあるとします
65. 65
コンテキスト・マウント(v18.09+ w/ BuildKit)
contest mounts
従来 “COPY . /app” BuildKit
Dockerfile
app用ディレクトリ
Build用ディレクトリ
“docker build” 時、 「.」 以下の内容を
Docker イメージ用レイヤとして構築するため
全て Docker に対して送る必要があった
※結果として Docker イメージの不本意な増加
※あるいはマルチ・ステージ・ビルドで回避
Dockerfile
app用ディレクトリ
Build用ディレクトリ
コンテナ
コピー マウント
よいしょ…
みーてーるーだーけー
“docker build” の特定ステップのみ参照するため、
・ build 全体の時間を削減
・ イメージ・レイヤの肥大化を抑制
67. キャッシュの保持(v18.09+ w/ BuildKit)
67
# syntax=docker/dockerfile:1.0-experimental
FROM maven:3.6-jdk-8-alpine AS builder
WORKDIR /app
RUN --mount=target=. --mount=type=cache,target=/root/.m2 ¥
&& mvn package –DoutputDirectory=/
FROM openjdk:8-jre-alpine
COPY --from=builder /app.jar /
CMD ["java", "-jar", "/app.jar"]
apt: /var/lib/apt/lists
go: ~/.cache/go-build
go-modules: $GOPATH/pkg/mod
npm: ~/.npm
pip: ~/.cache/pip
キャッシュ用ディレクトリをマウントできるので、依存関係の準備にかかる時間を削減できる
68. キャッシュの保持
• --mount=type=cache 例:
68
Dockerfile
# syntax=docker/dockerfile:1.0-experimental
FROM ubuntu
RUN --mount=type=cache,target=/var/cache/apt ¥
--mount=type=cache,target=/var/lib/apt ¥
apt-get update && apt-get install -y wget curl
「type=cache」で指定した「target」のディレクトリは、docker build を実行したホスト上でキャッシュ
この例では apt-get install を含む「RUN」命令を書き換えたとしても、
一度キャッシュ(ビルド)済みであれば次回から高速なビルドが可能になる
キャッシュ情報をクリアするには「docker builder prune」コマンドを実行する
70. シークレット(これはダメな方法)
70
FROM baseimage
RUN …
ENV AWS_ACCESS_KEY_ID=…
ENV AWS_SECRET_ACCESS_KEY=…
RUN ./fetch-aseets-from-s3.sh
RUN ./build-scripts.sh
シークレット(secret)とは、パスワードやAPIキー、SSH 鍵などの認証情報(機微情報)
ENV に書くと docker history で丸見えですし、
71. シークレット(これもダメな方法)
71
FROM baseimage
RUN …
ARG AWS_ACCESS_KEY_ID
ARG AWS_SECRET_ACCESS_KEY
RUN ./fetch-aseets-from-s3.sh
RUN ./build-scripts.sh
$ docker build --build-arg ¥
AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID …
ARGでも途中のRUNで変数の情報をダンプできますし、
シェルのhistoryからも辿れるリスクが出てきます(記録しない方法もありますが、運用カバー系作業)
docker history
72. シークレット(v18.09+ w/ BiuldKit では、こうします)
72
# syntax=docker/dockerfile:1-experimental
FROM baseimage
RUN …
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials,
required ./fetch-assets-from-s3.sh
RUN ./build-scripts.sh
$ docker build --secret id=aws,src=~/.aws/credentials .
最終イメージに混入させないための手法が「secret」としてのマウント。
対象ステップのみデータを参照できるよう一時的にマウントし、次のステップではマウントしません。
↓idは docker build 時の –secret オプションで識別するため
↑targetで、この構築ステップのみ、
コンテナ内のこの場所に
一時的にファイルを設置する指示
↑これはホスト側に存在するファイル。
~より、 $HOME や絶対パスのほうが安全かも
↑次のステップでは、先の id=aws でマウントしたシークレットは見えない( 0 byte のファイル残骸のみ)
74. • Dockerfile の mount secret 例:
Dockerfile
$HOME/secret
シークレット・マウント(v18.09+ w/ BiuldKit)
74
# syntax=docker/dockerfile:1.0-experimental
FROM alpine
RUN --mount=type=secret,id=check,target=/root/secret,required ¥
cat /root/secret > /data.txt
MYID=secretpass
Dockerfile で当該 RUN 命令行のビルド時のみ、一時的にホスト側ファイルをマウントできる
secret mounts
ホスト側にIDとパスワードのような、
いわゆるシークレット(機微情報)を記録するファイルを設置
もちろん、パーミッションは 600 にするなど、十分なセキュリティ配慮が必要
$ docker build --secret id=check,src=$HOME/.data/credentials -t myimage .
↑srcで指定したパスはホスト上のファイル
75. プライベート git リポジトリ(ダメぜったい)
75
FROM baseimage
COPY ./keys/private.pem /root/.ssh/private.pem
ARG REPO_REF=19ba8bcd9976ef8a9bd086187df19ba7bcd997f2
RUN git clone git@githubcom:org/repo /work && cd /work ¥
&& git checkout –b $REPO_REF
これもイメージ内に大事なファイルが残ってしまう NG 例
76. プライベート git リポジトリ(v18.09+ w/BuildKitの場合)
76
FROM alpine
RUN apk add --no-cache openssh-client
RUN mkdir –p –m 0700 ~/.ssh && ssh-keyscan github.com >>
~/.ssh/known_hosts
ARG REPO REF=19ba8bcd9976ef8a9bd086187df19ba7bcd997f2
RUN –-mount-type=ssh,required ¥
git clone git@github.com:org/repo /work && cd /work ¥
&& git checkout –b $REPO_REF
$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
$ docker build --ssh=default .
この RUN 命令実行時のみ、
ホスト側の SSH 認証情報を読み込む方法が
利用できる
77. BuildKit
77
SSH マウント(v18.09+ w/ BiuldKit)
mounts
Dockerfile
.ssh
Build用ディレクトリ
コンテナ
鍵情報
参照
このステップがある間だけ
みーてーるーだーけー
“docker build” の対象構築ステップ時のみ、
ホスト側のSSH agent 情報を一時的にマウント
シークレット・マウントに近いけれど
SSH の利用に特化
こんてなから GitHub や SSH 接続したい場合に有用
docker
build
id_rsa ssh-agent
--mount=type=ssh
SSH
リモート・ホストや
GitHub / GitLab 等
78. • Dockerfile の mount=SSH 例:
Dockerfile
SSH マウント(v18.09+ w/ BiuldKit)
78
# syntax=docker/dockerfile:1.0-experimental
FROM alpine
RUN apk update && apk add openssh
RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan <host_IP> > ~/.ssh/known_hosts
RUN --mount=type=ssh,required ¥
ssh <user>@<host_IP> ls -al / > /ls.txt
GitHubやGitLabの認証だけでなk、別のホストにこのようにしてログイン&操作も可能
mounts
$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(パスフレーズを入力)
$ docker build --ssh default=$SSH_AUTH_SOCK -t <image_name> .
79. Dockerfile 改善のまとめ
• 従来
⁃ 構築・開発・テスト環境の矛盾
⁃ 膨れあがるイメージ容量
⁃ 構築時間がマシマシ(キャッシュ無効)になり時間がかかる
⁃ 構築が安全ではない
• これから( BuildKit の活用によって)
⁃ 構築・開発・テスト環境が一致
⁃ イメージ容量は最小
⁃ 構築が非常に速く、構築回数が増えていく
⁃ より安全に構築できる
79
export DOCKER_BUILDKIT=1重要なのは有効化に
新しいビルド時の一時マウント可能な bind、cache、tmpfs、secret、ssh
マルチ・ステージ・ビルドの活用によって、段階ごとの FROM
ステージ間のコピー機能により、最終成果物を小さく
並列ビルドの活用により、従来よりも素早い構築
80. 参考資料
• Advanced multi-stage build patterns – Tõnis Tiigi – Medium
https://medium.com/@tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae
• Build secrets and SSH forwarding in Docker 18.09 – Tõnis Tiigi – Medium
https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-
ae8161d066
• Introducing BuildKit – Moby Blog
https://blog.mobyproject.org/introducing-buildkit-17e056cc5317
• docker builder prune | Docker Documentation
https://docs.docker.com/engine/reference/commandline/builder_prune/
• Docker v18.09 新機能 (イメージビルド&セキュリティ) – nttlabs – Medium
https://medium.com/nttlabs/docker-v18-09-%E6%96%B0%E6%A9%9F%E8%83%BD-
%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%83%93%E3%83%AB%E3%83%89-
%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3-
9534714c26e2
80
82. DockerCon での発表
• Dockerfile Best Practices
https://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices
82
• 動画
https://www.docker.com/dockercon/2019-videos?watch=dockerfile-best-practices
83. Q&A
• 何か気になるところはありますか?
• Twitter: @zembutsu
• https://slideshare.net/zembutsu
• Dockerドキュメント日本語訳
http://docs.docker.jp
• Docker Composeドキュメント日本語訳
http://docs.docker.jp/compose/
• 公式ドキュメント
https://docs.docker.com
83