Movatterモバイル変換


[0]ホーム

URL:


PDF, PPTX65,956 views

Dockerfileを改善するためのBest Practice 2019年版

2019年5月24日(金)の発表資料をベースに解説等を加えたバージョンです。Docker Meetup Kansai #3https://dockerkansai.connpass.com/event/129089/

Embed presentation

Download as PDF, PPTX
DockerCon SF19 で発表の、基礎→マルチ・ステージ・ビルド→最新動向までSakura Internet, Inc.Masahito Zembutsu @zembutsuDocker Meetup Kansai #3 #dockerkansaiMay 24, 2019Dockerfileを改善するためのBest Practice 2019年版
DockerCon SF19 での発表に基づく内容• Dockerfile Best Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices2• 動画もご覧ください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 videowill also be helpful.
このスライドは何?3⚫ DockerCon 19 で発表された人気シリーズ“Best Practices” を日本訳+解説の追加。⚫ Dockerfile の改善を通して、現在利用できるマルチ・ステージ・ビルドや BuildKit 紹介。以上の内容です。※ "Docker Meetup Kansai #3" 発表時のスライドをベースに、スライドそのままでは分かりづらい部分があるため、一部で発表時と異なる表現・補足説明を用いている場合があります。ゴール:「Dockerfileの改善を具体的に理解」
Dockerfileのベストプラクティス• "Best practices for writing Dockerfiles"https://docs.docker.com/develop/develop-images/dockerfile_best-practices/4最新の日本語訳を公開しました。そもそもの基本となるのは、"Dockerfileを書くためのベストプラクティス"です。
Dockerfile解説スライドもご覧ください• ベストプラクティス日本語版に解説・図解を加えたバージョンを作りました5https://www.slideshare.net/zembutsu/explaining-best-practices-for-writing-dockerfilesもし、Dockerfileに慣れていないのであれば、前提として、こちらのスライドをご覧ください。
Dockerfile とは?6ド ッ カ ー フ ァ イ ル
Dockerfile• Docker は Dockerfile から命令を読み込み、イメージを自動構築• テキスト形式のドキュメント• docker build / docker image build で Dockerfile を読み込み構築• 「Docker イメージを作るための設計図」• FROM、ADD、CMD など命令文で構成• 例) 何のイメージをもとに、何を実行するか?• 誰でも確実にイメージを構築できる• イメージの構築過程を確認できる• Dockerfileは広く使われている• GitHub上に Dockerfile は100万以上7automate buildblueprintImage by John Dortmunder from Pixabay「Dockerfile」はDockerイメージを自動構築するために、必ず使うファイルです。
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 という汎用ツールが開発途上です。
Docker BuildKit を使う方法• クライアントの環境変数• Docker デーモン設定ファイル /etc/docker/daemon.json• 現時点では Windows は対応していない• Windows support coming soon!9{ "features": { "buildkit": true }}export DOCKER_BUILDKIT=1BiuldKit は Docker とは別のプロジェクト (https://github.com/moby/buildkit ) ですが、現在の Docker CE v18.09 では、BuildKit の一部機能が既に利用できる状態です。
カイゼン Dockerfile10
Dockerfile の改善領域• 増大するbuild 時間• イメージ容量• 保守性• 安全性• 一貫性・反復性11(Incremental) build timeImage sizeMaintainabilitySecurityConsistency/Repetabilityここからは、先日開催された DockerCon SF19での発表サンプルをベースにご紹介します。サンプルのアプリケーションを使い、5つの視点で Dockerfile を改善する流れをみていきましょう。
サンプルの Dockerfile をカイゼンするぞ!12FROM debianCOPY . /appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh emacsCMD ["java", "-jar", "/app/target/app.jar"]これは、Javaで"Hello world"を表示するための、サンプルプログラム用の Dockerfile です。
サンプルの Dockerfile をカイゼンするぞ!13FROM debianCOPY . /appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh emacsCMD ["java", "-jar", "/app/target/app.jar"]vimまずすべきは、emacs を消して、vim を入れましょう。もちろんジョークですが!
サンプルの Dockerfile をカイゼンするぞ!14FROM debianCOPY . /appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh emacsCMD ["java", "-jar", "/app/target/app.jar"]vimまずすべきは、emacs を消して、vim を入れましょう。もちろんジョークですが!
増大する構築(build)時間ビルド・キャッシュと友達になろう15課題と対策
キャッシュする順番が重要16FROM debianCOPY . /appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimCOPY . /appCMD ["java", "-jar", "/app/target/app.jar"]頻繁に変更するものを後ろへ構築時のキャッシュとは、変更箇所があれば破棄されます。この例の COPY では「.」(カレント)にあるファイルに変更があれば、毎回「apt-get update」と「install」が走るので、時間がかかってしまいます。せっかくあrキャッシュを有効活用するには、頻繁に更新する可能性があるものを後ろにおきます。
キャッシュする順番が重要17FROM debianCOPY . /appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimCOPY . /appCMD ["java", "-jar", "/app/target/app.jar"]頻繁に変更するものを後ろへ構築時のキャッシュとは、変更箇所があれば破棄されます。この例の COPY では「.」(カレント)にあるファイルに変更があれば、毎回「apt-get update」と「install」が走るので、時間がかかってしまいます。せっかくあrキャッシュを有効活用するには、頻繁に更新する可能性があるものを後ろにおきます。キャッシュ有効キャッシュ破棄 … ホスト側「 ./ 」に変更時キャッシュ破棄 … ホスト側「 ./ 」に変更時時間がかかるので、キャッシュ活用すべし時間かかる
キャッシュ破棄の影響を避けるため、範囲を狭く18FROM debianRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimCOPY . /appCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]コピーに必要なものを明示する。可能であれば "COPY ."を避けるコピーすべき場所を絞っておけば、キャッシュは破棄されません。この例では「app.jar」しか「COPY」しませんので、他のファイルに変更があってもキャッシュを保持。
キャッシュ破棄の影響を避けるため、範囲を狭く19FROM debianRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimCOPY . /appCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]コピーすべき場所を絞っておけば、キャッシュは破棄されません。この例では「app.jar」しか「COPY」しませんので、他のファイルに変更があってもキャッシュを保持。キャッシュ有効キャッシュ有効キャッシュ有効ちょっとキャッシュする範囲が拡がるかもねキャッシュ対象の明確化コピーに必要なものを明示する。可能であれば "COPY ."を避ける
行をまとめる: apt-get update & install20FROM debianRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimRUN apt-get update ¥&& apt-get -y install ¥openjdk-8-jdk ssh vimCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]古いパッケージ情報のキャッシュ利用を避けるパッケージ・マネージャを使う場合、「古い」パッケージ情報をキャッシュしがちです。更新したいのに更新できないのを避けるには、情報の更新と、パッケージ追加・削除をまとめること。
行をまとめる: apt-get update & install21FROM debianRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimRUN apt-get update ¥&& apt-get -y install ¥openjdk-8-jdk ssh vimCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]古いパッケージ情報のキャッシュ利用を避けるパッケージ・マネージャを使う場合、「古い」パッケージ情報をキャッシュしがちです。更新したいのに更新できないのを避けるには、情報の更新と、パッケージ追加・削除をまとめること。キャッシュ有効古いものをキャッシュしてるかも!時間かかる場合があっても、確実に処理
イメージ容量を減らすより速くデプロイするには、イメージを小さく22課題と対策
不要な依存関係を削除23FROM debianRUN apt-get update ¥&& apt-get -y install --no-install-recommends ¥openjdk-8-jdk ssh vimCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]デプロイを素早くするためには、イメージ容量の削減が重要であり、必須課題。推奨パッケージ(必須ではない)を避けるためには、「--no-install-recommends」フラグを付ける。Javaの実行に不要なパッケージも入れないので「ssh」「vim」も消す。
不要なパッケージマネージャのキャッシュ削除24FROM debianRUN apt-get update ¥&& apt-get -y install –no-install-recommends ¥openjdk-8-jdk ¥&& rm –rf /var/lib/apt/lists/*COPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]パッケージ・マネージャのキャッシュ情報も、アプリケーションの実行に不要なので削除
保守性できるだけシンプルに保つ25課題と対策
できるだけDocker公式(official)パッケージを使う• メンテナンスにかける時間を減らす(問題があるたびに、繰り返す更新)• 容量を減らす(イメージ間でのレイヤ共有によって)• コンテナとして使うために、予め設定済み• 賢い人達が構築している26パッケージ・マネージャのキャッシュ情報も、アプリケーションの実行に不要なので削除
27FROM debianRUN apt-get update ¥&& apt-get -y install –no-install-recommends ¥openjdk-8-jdk ¥&& rm –rf /var/lib/apt/lists/*FROM openjdkCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]できるだけDocker公式(official)パッケージを使うJavaの実行であれば、「openjdk」イメージがあるため、debianでセットアップする必要はない
タグを明示28FROM openjdk:latestFROM openjdk:8COPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]"latest"タグは常に入れ替わる。タグを指定しておけば、想定外のベース・イメージ変更発生を防止。何も指定しなければ「latest」(最新)になるため、常にタグ(主にバージョン)指定を忘れずに
適切なタグを探す29Docker Hub のドキュメントを読もうhttps://hub.docker.com/_/openjdkどのようなタグがあるかは、Docker Hub上のドキュメントで確認
必要最小限のものを探す30REPOSITORY TAG SIZEopenjdk 8 624MBopenjdk 8-jre 443MBopenjdk 8-jre-slim 204MBopenjdk 8-jre-alpie 83MBベース・イメージの変更だけで540MBも削減どのイメージ(タグ)を選ぶかによって、容量がかなり異なる。alpineタグは Alpine Linux という約 5MB の Linux ディストリビューションがベース
再利用性Dockerfileは青写真であり、ソースコードこそが本当の源(ソース)31課題と対策
32
一貫した環境を、ソースから構築する• Dockerfile を設計図(青写真)にしよう:• ビルド時するための構築環境を Dockerfile に記述• 正しいバージョンのビルド・ツールをインストール• 環境ごとの違いを発生させない• システム依存はあるかもしれない• "source of truth"(本当のソース)とは、ソースコードである。ビルド成果物ではない。33Image by John Dortmunder from Pixabayblue print開発環境、テスト環境、実行環境で共通する Dockerfile を目指す
一貫した環境を、ソースから構築する34FROM openjdk:8-jre-alpineFROM maven:3.6-jdk-8-alpineWORKDIR /appCOPY app.jar/appCOPY pom.xml .COPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]openjdk にかわり、Javaプロジェクト管理ツールであるMavenを開発環境として入れる
一貫した環境を、ソースから構築する35FROM maven:3.6-jdk-8-alpineWORKDIR /appCOPY pom.xml .COPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]このように、開発環境向けの Dockerfile を整えていく。
依存関係の解決は、ステップを分ける36FROM maven:3.6-jdk-8-alpineWORKDIR /appCOPY pom.xml .RUN mvn –e –B dependency:resolveCOPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]開発関係だけに必要な依存関係を追加。
構築時のみの依存関係が判明37FROM maven:3.6-jdk-8-alpineWORKDIR /appCOPY pom.xml .RUN mvn –e –B dependency:resolveCOPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]しかし、この黄色い部分は「開発環境の構築」段階しか使わないものであり、本番稼働では無駄
マルチ・ステージ・ビルドで、構築時の部分を削除38FROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appCOPY pom.xml .RUN mvn –e –B dependency:resolveCOPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]FROM openjdk:8-jre-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app/target/app.jar"]そこで、マルチ・ステージ・ビルドで複数の「FROM」を使い、構築時(AS bilder)と実行時を分離←「builder」ステージからファイルをコピー←ステージ「builder」と名前を付ける
マルチ・ステージ・ビルドで、構築時の部分を削除39FROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appCOPY pom.xml .RUN mvn –e –B dependency:resolveCOPY src ./srcRUN mvn –e –B packageFROM openjdk:8-jre-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app/target/app.jar"]マルチ・ステージ・ビルドでは、「docker build」は全てのビルドを実行しますし、「docker build –target builder」と指定すると「AS builder」の「FROM」ステージしか処理しません。
マルチ・ステージ Dockerfile単に容量を減らすためだけではない40応用
プロジェクトごとに多くのステージがある• Moby: 16 ステージhttps://github.com/moby/moby/blob/master/Dockerfile• BuildKit: 44 ステージhttps://github.com/moby/buildkit/blob/master/hack/dockerfiles/test.buildkit.Dockerfile41Docker 関連プロジェクトの Dockerfile にも、多くのステージ(FROM命令)がある
マルチ・ステージの利用例• 実行環境と構築(ビルド)環境を分ける(イメージ容量の縮小)• イメージに対する影響を最小限に(DRY)• 構築・開発・テスト・構文チェック…のような環境を明示• 依存関係を一直線に処理しない(並列化)• プラットフォーム固有のステージ42一般的な目的は、最終成果物の容量を削減
構築ステージを --target で指定43FROM image_or_stage AS stage_name…$ docker build --target stage_name「AS ステージ名」を FROM 命令に書いておけば、「docker build」時に「--target」でステージを指定
イメージの flavor を変える44FROM maven:3.6-jdk-8-alpine AS builder...FROM openjdk:8-jre-jessie AS release-jessieCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]FROM openjdk:8-jre-jessie AS release-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]$ docker build --target release-jessie .Debian jessie (8.x) をベースとするイメージと、Alpine Linux をベースとするイメージ。特色(風味)
45FROM maven:3.6-jdk-8-alpine AS builder...FROM openjdk:8-jre-jessie AS release-jessieCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]FROM openjdk:8-jre-jessie AS release-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]$ docker build --target release-jessie .イメージの flavor を変える特色(風味)しかし、 Dockerfile をよく見ると問題があり、
46FROM maven:3.6-jdk-8-alpine AS builder...FROM openjdk:8-jre-jessie AS release-jessieCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]FROM openjdk:8-jre-jessie AS release-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]$ docker build --target release-jessie .このように各ステージで、同じ命令が重複する箇所がある。イメージの flavor を変える特色(風味)どちらも同じ
47ARG flavor=alpineFROM maven:3.6-jdk-8-alpine AS builder...FROM openjdk:8-jre-$flavor AS releaseCOPY --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時に指定できる変数を定義書式は「変数名」または「変数名=デフォルト値」。
様々な環境:構築、開発、テスト、構文チェック(lint)…• ステージとしての検討例:⁃ builder: 依存関係すべてをビルド⁃ build(または binary): builder + ビルド成果物⁃ cross: 複数のプラットフォーム向けに構築⁃ dev: build(er) + 開発/デバッグツール⁃ lint: 最小限の構文チェック用依存関係⁃ test: テストに関係する全ての依存関係 + テスト対象のビルド成果物⁃ release: ビルド成果物を含む、最終的な最小イメージ48様々な「ステージ」が検討できる。ここでは定型的な例各ステージでは、依存関係が最小となるようにする
様々な環境:構築、開発、テスト、構文チェック(lint)…49FROM maven:3.6-jdk-8-alpine AS builder...FROM openjdk:8-jre-alpine AS lintRUN wget https://github.com/checkstyle/checkstyle/releases/download/checkstyle-8.15/checkstyle-8.15-all.jarCOPY checks.xml .COPY src /srcRUN java –jar checkstyle-8.15-all.jar –c checks.xml /srcこれはシンプルな Java 構文チェック(リント)の確認用の Dockerfile を「AS lint」と指定
様々な環境:構築、開発、テスト、構文チェック(lint)…50FROM maven:3.6-jdk-8-alpine AS builder...FROM openjdk:8-jre-alpine AS releaseCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]FROM builder AS devRUN apk add --no-cache strace vim tcpdumpENTRYPOINT ["ash"]開発用デバッグ環境であれば、「builder」ステージをベースにしながら「AS dev」と明示しシンプルにエディタ(vim)と tcpdump を入れている
様々な環境:構築、開発、テスト、構文チェック(lint)…51FROM maven:3.6-jdk-8-alpine AS builder...RUN mvn –e –B package –DskipTestsFROM builder AS unit-testRUN mvn –e –B testFROM release AS integration-testRUN apk add --no-cache curlRUN ./test/run.sh他にも単体テスト、統合テスト用の環境も作れます。
並行性(Concurrency)52応用
一直線の Dockerfile ステージから …• 全てのステージが順番(シーケンシャル)に実行• この図では、上から下に一直線• BuildKitがなければ、不要なステージも無駄に実行し、破棄する(無駄に時間がかかった)53s1s2s3s4s5s6デフォルトでは、全てのステージを順番に実行する
BuildKit のマルチ・ステージ graph へ• BuildKit は下(--target のステージ名)から上に辿っていくような流れ• 右図では s2, s3, s4 ステージを同時並行処理• 不要なステージは無視できる• 右図では s5 がビルド時に不要であれば、何もしない54s1s2 s3 s4s5s6Docker 17.05 からマルチ・ステージ・ビルドが利用可能になった。18.06までは experimental 、18.09 は利用できるように組み込まれているグラフ※グラフは点と点とのつながり(関係性)を表す
Multi-srage: 並行ビルド (build concurrently)55FROM maven:3.6-jdk-8-alpine AS builder...FROM tiborvass/whalesay AS assetsRUN whalesay "Hello DockerCon!" > /out/assets.htmlFROM openjdk:8-jre-alpine AS releaseCOPY --from=builder /app/target/app.jar /COPY --from=assets /out /assetsCMD ["java", "-jar", "/app.jar"]「assets」は最終イメージ(release)に必要だが、別のステージとして処理できるそして、この Dockerfile は「builder」と「assets」のステージからのコピーを並行処理
Multi-srage: 並行ビルド (build concurrently)56FROM maven:3.6-jdk-8-alpine AS builder-base…FROM gcc:8-alpine AS builder-someClib…RUN git clone … ¥./configure --prefix=/out && make && make installFROM g++:8-alpine AS builder-someCPPlib…RUN git clone … ¥cmake …FROM builder-base AS builderCOPY --from=builder-someClib /out /COPY --from=builder-someCPPlib /out /複数の COPY 命令を使う時には、特に効果を発揮し、時間を節約できる並行処理が有用な典型的なパターンが複数の COPY --from … の繰り返し
ベンチマーク• github.com/moby/moby Dockerfile, master ブランチ• 小さいほうが優れている57Dockerfile Best Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices/52v18.03 の docker build と BuiltKit では2倍の速さ
ベンチマーク• github.com/moby/moby Dockerfile, master ブランチ• 小さいほうが優れている58Dockerfile Best Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices/52キャッシュを有効にすると、7倍も速くなる
ベンチマーク• github.com/moby/moby Dockerfile, master ブランチ• 小さいほうが優れている59Dockerfile Best Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices/52最も大事なのは、ソースコードの変更時。再構築の速度はマルチ・ステージ・ビルドで 2.5 倍に改善。
Dockerfileの最新機能60新機能
新機能を有効にするには?61# syntax=docker/dockerfile:1.0-experimentalFROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appCOPY . /appRUN mvn -e –B packageFROM openjdk:8-jre-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]Dockerfile の新機能を有効にするには、この行を1行目に追加する必要がある※experimental というのは、まだDockerfile の正式な構文ではないため
詳細• https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md62構文の詳細は、こちらのドキュメントを参照
コンテキスト・マウント(v18.09+ w/ BuildKit)63# syntax=docker/dockerfile:1.0-experimentalFROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appCOPY . /appRUN --mount=target=. mvn -e –B package -DoutputDirectory=/FROM openjdk:8-jre-alpineCOPY --from=builder /app/app.jar /CMD ["java", "-jar", "/app.jar"]新機能を使って Dockerfile を書き換えていく。まずはマウント・オプション。実行時に「.」(カレント・ディレクトリ内容)を Build Context として送信せず、マウントできる※ Docker v18.09 以上かつ、BuildKit 有効化の状態で利用可能contest mounts
Dockerfilehelloコンテキスト・マウント(v18.09+ w/ BuildKit)64ディレクトリ内容をコンテナに COPY しなくても、ビルド時に docker build コマンドを実行しているディレクトリ(ここでは 「target=.」で指定)をrw(読み書き可能な状態)で直接コンテナにマウントし、コンテナ内で「cat hello > /hello.txt」を実行→ 構築したイメージの“/hello.txt” に “Hello world!” が書かれたファイルが作成される# syntax=docker/dockerfile:1.0-experimentalFROM alpineRUN --mount=type=bind,target=.,rw cat hello > /hello.txtHello world!ソースコードなど、ビルド・コンテクストのコピーが不要となり、より早いビルドができるcontest mounts• Dockerfile の mount 例:ホスト側の docker build する場所に、このファイルがあるとします
65コンテキスト・マウント(v18.09+ w/ BuildKit)contest mounts従来 “COPY . /app” BuildKitDockerfileapp用ディレクトリBuild用ディレクトリ“docker build” 時、 「.」 以下の内容をDocker イメージ用レイヤとして構築するため全て Docker に対して送る必要があった※結果として Docker イメージの不本意な増加※あるいはマルチ・ステージ・ビルドで回避Dockerfileapp用ディレクトリBuild用ディレクトリコンテナコピー マウントよいしょ…みーてーるーだーけー“docker build” の特定ステップのみ参照するため、・ build 全体の時間を削減・ イメージ・レイヤの肥大化を抑制
キャッシュの保持(BuildKitが無ければ)66FROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appCOPY pom.xml .RUN mvn -e –B dependency: resolveCOPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app.jar"]docker build 時にキャッシュが破棄されると、毎回依存関係の準備に時間がかかる
キャッシュの保持(v18.09+ w/ BuildKit)67# syntax=docker/dockerfile:1.0-experimentalFROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appRUN --mount=target=. --mount=type=cache,target=/root/.m2 ¥&& mvn package –DoutputDirectory=/FROM openjdk:8-jre-alpineCOPY --from=builder /app.jar /CMD ["java", "-jar", "/app.jar"]apt: /var/lib/apt/listsgo: ~/.cache/go-buildgo-modules: $GOPATH/pkg/modnpm: ~/.npmpip: ~/.cache/pipキャッシュ用ディレクトリをマウントできるので、依存関係の準備にかかる時間を削減できる
キャッシュの保持• --mount=type=cache 例:68Dockerfile# syntax=docker/dockerfile:1.0-experimentalFROM ubuntuRUN --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」コマンドを実行する
BuildKitキャッシュはホスト側で保持69Dockerfileapp用ディレクトリBuild用ディレクトリコンテナマウントキャッシュしたあとはみーてーるーだーけーDockerのキャッシュ用ディレクトリ“docker build” の対象構築ステップ時のみ、ホスト側のキャッシュ用ディレクトリを一時的にマウント何度 build しても、キャッシュを有効活用できるので高速にイメージを作りやすいまた、イメージ全体の容量も削減できるdocker build※ docker builder prune で消せる
シークレット(これはダメな方法)70FROM baseimageRUN …ENV AWS_ACCESS_KEY_ID=…ENV AWS_SECRET_ACCESS_KEY=…RUN ./fetch-aseets-from-s3.shRUN ./build-scripts.shシークレット(secret)とは、パスワードやAPIキー、SSH 鍵などの認証情報(機微情報)ENV に書くと docker history で丸見えですし、
シークレット(これもダメな方法)71FROM baseimageRUN …ARG AWS_ACCESS_KEY_IDARG AWS_SECRET_ACCESS_KEYRUN ./fetch-aseets-from-s3.shRUN ./build-scripts.sh$ docker build --build-arg ¥AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID …ARGでも途中のRUNで変数の情報をダンプできますし、シェルのhistoryからも辿れるリスクが出てきます(記録しない方法もありますが、運用カバー系作業)docker history
シークレット(v18.09+ w/ BiuldKit では、こうします)72# syntax=docker/dockerfile:1-experimentalFROM baseimageRUN …RUN --mount=type=secret,id=aws,target=/root/.aws/credentials,required ./fetch-assets-from-s3.shRUN ./build-scripts.sh$ docker build --secret id=aws,src=~/.aws/credentials .最終イメージに混入させないための手法が「secret」としてのマウント。対象ステップのみデータを参照できるよう一時的にマウントし、次のステップではマウントしません。↓idは docker build 時の –secret オプションで識別するため↑targetで、この構築ステップのみ、コンテナ内のこの場所に一時的にファイルを設置する指示↑これはホスト側に存在するファイル。~より、 $HOME や絶対パスのほうが安全かも↑次のステップでは、先の id=aws でマウントしたシークレットは見えない( 0 byte のファイル残骸のみ)
BuildKit73Dockerfile大事なディレクトリBuild用ディレクトリコンテナid指定対象をマウント構築ステップの間だけみーてーるーだーけー“docker build” の対象構築ステップ時のみ、ホスト側のシークレット(機微情報)ファイルを一時的にマウント環境変数などで取り込んで認証などに利用する一時的にホスト側を参照するだけなのでイメージ内に大事な情報を残さないdockerbuildSECRET_FILEシークレット・マウント(v18.09+ w/ BiuldKit)secret mountsid指定
• Dockerfile の mount secret 例:Dockerfile$HOME/secretシークレット・マウント(v18.09+ w/ BiuldKit)74# syntax=docker/dockerfile:1.0-experimentalFROM alpineRUN --mount=type=secret,id=check,target=/root/secret,required ¥cat /root/secret > /data.txtMYID=secretpassDockerfile で当該 RUN 命令行のビルド時のみ、一時的にホスト側ファイルをマウントできるsecret mountsホスト側にIDとパスワードのような、いわゆるシークレット(機微情報)を記録するファイルを設置もちろん、パーミッションは 600 にするなど、十分なセキュリティ配慮が必要$ docker build --secret id=check,src=$HOME/.data/credentials -t myimage .↑srcで指定したパスはホスト上のファイル
プライベート git リポジトリ(ダメぜったい)75FROM baseimageCOPY ./keys/private.pem /root/.ssh/private.pemARG REPO_REF=19ba8bcd9976ef8a9bd086187df19ba7bcd997f2RUN git clone git@githubcom:org/repo /work && cd /work ¥&& git checkout –b $REPO_REFこれもイメージ内に大事なファイルが残ってしまう NG 例
プライベート git リポジトリ(v18.09+ w/BuildKitの場合)76FROM alpineRUN apk add --no-cache openssh-clientRUN mkdir –p –m 0700 ~/.ssh && ssh-keyscan github.com >>~/.ssh/known_hostsARG REPO REF=19ba8bcd9976ef8a9bd086187df19ba7bcd997f2RUN –-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 認証情報を読み込む方法が利用できる
BuildKit77SSH マウント(v18.09+ w/ BiuldKit)mountsDockerfile.sshBuild用ディレクトリコンテナ鍵情報参照このステップがある間だけみーてーるーだーけー“docker build” の対象構築ステップ時のみ、ホスト側のSSH agent 情報を一時的にマウントシークレット・マウントに近いけれどSSH の利用に特化こんてなから GitHub や SSH 接続したい場合に有用dockerbuildid_rsa ssh-agent--mount=type=sshSSHリモート・ホストやGitHub / GitLab 等
• Dockerfile の mount=SSH 例:DockerfileSSH マウント(v18.09+ w/ BiuldKit)78# syntax=docker/dockerfile:1.0-experimentalFROM alpineRUN apk update && apk add opensshRUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan <host_IP> > ~/.ssh/known_hostsRUN --mount=type=ssh,required ¥ssh <user>@<host_IP> ls -al / > /ls.txtGitHubやGitLabの認証だけでなk、別のホストにこのようにしてログイン&操作も可能mounts$ eval $(ssh-agent)$ ssh-add ~/.ssh/id_rsa(パスフレーズを入力)$ docker build --ssh default=$SSH_AUTH_SOCK -t <image_name> .
Dockerfile 改善のまとめ• 従来⁃ 構築・開発・テスト環境の矛盾⁃ 膨れあがるイメージ容量⁃ 構築時間がマシマシ(キャッシュ無効)になり時間がかかる⁃ 構築が安全ではない• これから( BuildKit の活用によって)⁃ 構築・開発・テスト環境が一致⁃ イメージ容量は最小⁃ 構築が非常に速く、構築回数が増えていく⁃ より安全に構築できる79export DOCKER_BUILDKIT=1重要なのは有効化に新しいビルド時の一時マウント可能な bind、cache、tmpfs、secret、sshマルチ・ステージ・ビルドの活用によって、段階ごとの FROMステージ間のコピー機能により、最終成果物を小さく並列ビルドの活用により、従来よりも素早い構築
参考資料• Advanced multi-stage build patterns – Tõnis Tiigi – Mediumhttps://medium.com/@tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae• Build secrets and SSH forwarding in Docker 18.09 – Tõnis Tiigi – Mediumhttps://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066• Introducing BuildKit – Moby Bloghttps://blog.mobyproject.org/introducing-buildkit-17e056cc5317• docker builder prune | Docker Documentationhttps://docs.docker.com/engine/reference/commandline/builder_prune/• Docker v18.09 新機能 (イメージビルド&セキュリティ) – nttlabs – Mediumhttps://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-9534714c26e280
参考資料• BuildKitによる高速でセキュアなイメージビルドhttps://www.slideshare.net/AkihiroSuda/buildkit81
DockerCon での発表• Dockerfile Best Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices82• 動画https://www.docker.com/dockercon/2019-videos?watch=dockerfile-best-practices
Q&A• 何か気になるところはありますか?• Twitter: @zembutsu• https://slideshare.net/zembutsu• Dockerドキュメント日本語訳http://docs.docker.jp• Docker Composeドキュメント日本語訳http://docs.docker.jp/compose/• 公式ドキュメントhttps://docs.docker.com83

Recommended

PDF
Dockerfile を書くためのベストプラクティス解説編
PDF
Docker Compose 徹底解説
PPTX
kubernetes初心者がKnative Lambda Runtime触ってみた(Kubernetes Novice Tokyo #13 発表資料)
PDF
オススメのJavaログ管理手法 ~コンテナ編~(Open Source Conference 2022 Online/Spring 発表資料)
PDF
Docker道場オンライン#1 Docker基礎概念と用語の理解
PDF
Dockerイメージの理解とコンテナのライフサイクル
PDF
Mavenの真実とウソ
PDF
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
PPTX
イベント・ソーシングを知る
PDF
ドメイン駆動設計 ( DDD ) をやってみよう
PDF
コンテナの作り方「Dockerは裏方で何をしているのか?」
PDF
例外設計における大罪
PDF
コンテナ未経験新人が学ぶコンテナ技術入門
PDF
Dockerからcontainerdへの移行
PDF
こわくない Git
PPT
Glibc malloc internal
PDF
ドメイン駆動設計(DDD)の実践Part2
PPTX
BuildKitによる高速でセキュアなイメージビルド
PDF
イミュータブルデータモデル(世代編)
PDF
文字コードに起因する脆弱性とその対策(増補版)
PPTX
Docker超入門
PPTX
ワタシハ Azure Functions チョットデキル
PDF
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
PDF
リッチなドメインモデル 名前探し
PDF
オブジェクト指向できていますか?
PDF
Spring Boot の Web アプリケーションを Docker に載せて AWS ECS で動かしている話
PPTX
世界一わかりやすいClean Architecture
PPTX
SPAセキュリティ入門~PHP Conference Japan 2021
PDF
Introduce that Best practices for writing Dockerfiles
PDF
Dockerライフサイクルの基礎 地雷を踏み抜けろ!

More Related Content

PDF
Dockerfile を書くためのベストプラクティス解説編
PDF
Docker Compose 徹底解説
PPTX
kubernetes初心者がKnative Lambda Runtime触ってみた(Kubernetes Novice Tokyo #13 発表資料)
PDF
オススメのJavaログ管理手法 ~コンテナ編~(Open Source Conference 2022 Online/Spring 発表資料)
PDF
Docker道場オンライン#1 Docker基礎概念と用語の理解
PDF
Dockerイメージの理解とコンテナのライフサイクル
PDF
Mavenの真実とウソ
PDF
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
Dockerfile を書くためのベストプラクティス解説編
Docker Compose 徹底解説
kubernetes初心者がKnative Lambda Runtime触ってみた(Kubernetes Novice Tokyo #13 発表資料)
オススメのJavaログ管理手法 ~コンテナ編~(Open Source Conference 2022 Online/Spring 発表資料)
Docker道場オンライン#1 Docker基礎概念と用語の理解
Dockerイメージの理解とコンテナのライフサイクル
Mavenの真実とウソ
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか

What's hot

PPTX
イベント・ソーシングを知る
PDF
ドメイン駆動設計 ( DDD ) をやってみよう
PDF
コンテナの作り方「Dockerは裏方で何をしているのか?」
PDF
例外設計における大罪
PDF
コンテナ未経験新人が学ぶコンテナ技術入門
PDF
Dockerからcontainerdへの移行
PDF
こわくない Git
PPT
Glibc malloc internal
PDF
ドメイン駆動設計(DDD)の実践Part2
PPTX
BuildKitによる高速でセキュアなイメージビルド
PDF
イミュータブルデータモデル(世代編)
PDF
文字コードに起因する脆弱性とその対策(増補版)
PPTX
Docker超入門
PPTX
ワタシハ Azure Functions チョットデキル
PDF
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
PDF
リッチなドメインモデル 名前探し
PDF
オブジェクト指向できていますか?
PDF
Spring Boot の Web アプリケーションを Docker に載せて AWS ECS で動かしている話
PPTX
世界一わかりやすいClean Architecture
PPTX
SPAセキュリティ入門~PHP Conference Japan 2021
イベント・ソーシングを知る
ドメイン駆動設計 ( DDD ) をやってみよう
コンテナの作り方「Dockerは裏方で何をしているのか?」
例外設計における大罪
コンテナ未経験新人が学ぶコンテナ技術入門
Dockerからcontainerdへの移行
こわくない Git
Glibc malloc internal
ドメイン駆動設計(DDD)の実践Part2
BuildKitによる高速でセキュアなイメージビルド
イミュータブルデータモデル(世代編)
文字コードに起因する脆弱性とその対策(増補版)
Docker超入門
ワタシハ Azure Functions チョットデキル
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
リッチなドメインモデル 名前探し
オブジェクト指向できていますか?
Spring Boot の Web アプリケーションを Docker に載せて AWS ECS で動かしている話
世界一わかりやすいClean Architecture
SPAセキュリティ入門~PHP Conference Japan 2021

Similar to Dockerfileを改善するためのBest Practice 2019年版

PDF
Introduce that Best practices for writing Dockerfiles
PDF
Dockerライフサイクルの基礎 地雷を踏み抜けろ!
PDF
Docker for Windows & Web Apps for Containers 実践活用技法
PDF
Dockerで遊んでみよっかー YAPC::Asia Tokyo 2014
PPTX
~Dockerfileの開発を劇的に楽にする~ Dockerfile開発環境 EDGE
PPTX
DockerCon参加報告 (`docker build`が30倍以上速くなる話など)
PDF
Docker handson
 
PDF
Dockerハンズオン
PPTX
Docker & Kubernetes基礎
PDF
Docker実践入門
PPTX
BuildKitによる高速でセキュアなイメージビルド (LT)
PDF
Webアプリケーション開発者のためのDockerハンズオン20210519
PDF
Webアプリケーション開発者のためのDockerハンズオン
PDF
Docker事始めと最新動向 2015年6月
PPTX
Jenkins x Kubernetesが簡単だと思ったら大変だった話
PPTX
Dockerハンズオン
PDF
捕鯨!詳解docker
PDF
Building production server on docker
ODP
Building production server on docker
PDF
今だからこそ知りたい Docker Compose/Swarm 入門
Introduce that Best practices for writing Dockerfiles
Dockerライフサイクルの基礎 地雷を踏み抜けろ!
Docker for Windows & Web Apps for Containers 実践活用技法
Dockerで遊んでみよっかー YAPC::Asia Tokyo 2014
~Dockerfileの開発を劇的に楽にする~ Dockerfile開発環境 EDGE
DockerCon参加報告 (`docker build`が30倍以上速くなる話など)
Docker handson
 
Dockerハンズオン
Docker & Kubernetes基礎
Docker実践入門
BuildKitによる高速でセキュアなイメージビルド (LT)
Webアプリケーション開発者のためのDockerハンズオン20210519
Webアプリケーション開発者のためのDockerハンズオン
Docker事始めと最新動向 2015年6月
Jenkins x Kubernetesが簡単だと思ったら大変だった話
Dockerハンズオン
捕鯨!詳解docker
Building production server on docker
Building production server on docker
今だからこそ知りたい Docker Compose/Swarm 入門

More from Masahito Zembutsu

PDF
忙しい人のための Rocky Linux 入門〜Rocky LinuxはCentOSの後継者たり得るか?〜
PDF
自由検証環境提供宣言+Docker Compose V2 GA
PDF
CentOS Linux 8 の EOL と対応策の検討
PDF
さくらインターネットのコミュニティ with COVID-19
PDF
Docker Chronicle 2021.09
PDF
ブックトーク@CROSS ~SF編~ 発表資料「攻殻機動隊」「導きの星」
PDF
インターネットでウェブサイトを表示している裏側の話
PDF
3分で分かる「プログラミング教育・情報教育」
PDF
ようこそオンラインの展示会場へ
PDF
小学校プログラミング教育に対する企業の取り組みと課題 #KOF2020
PDF
オンライン発表で気を付けているポイント~姿勢編
PDF
Jitsi Meetとは?
PDF
Docker 9 tips~意外と知られていない日常で役立つ便利技
PDF
クリスマスに工場(Factorio)を作るゲームをしよう
PDF
2020年から始まる小学校プログラミング教育の話 #osc19os
PDF
CNCF Updates 2019 Winter version and Knative
PDF
[1C5] Docker Comose & Swarm mode Orchestration (Japan Container Days - Day1)
PDF
CNCFアップデート情報~2018年のCNCFを振り返る
PDF
Docker道場「Dockerの基本概念」0825インフラ勉強会資料
PDF
コンテナ導入概要資料2018
忙しい人のための Rocky Linux 入門〜Rocky LinuxはCentOSの後継者たり得るか?〜
自由検証環境提供宣言+Docker Compose V2 GA
CentOS Linux 8 の EOL と対応策の検討
さくらインターネットのコミュニティ with COVID-19
Docker Chronicle 2021.09
ブックトーク@CROSS ~SF編~ 発表資料「攻殻機動隊」「導きの星」
インターネットでウェブサイトを表示している裏側の話
3分で分かる「プログラミング教育・情報教育」
ようこそオンラインの展示会場へ
小学校プログラミング教育に対する企業の取り組みと課題 #KOF2020
オンライン発表で気を付けているポイント~姿勢編
Jitsi Meetとは?
Docker 9 tips~意外と知られていない日常で役立つ便利技
クリスマスに工場(Factorio)を作るゲームをしよう
2020年から始まる小学校プログラミング教育の話 #osc19os
CNCF Updates 2019 Winter version and Knative
[1C5] Docker Comose & Swarm mode Orchestration (Japan Container Days - Day1)
CNCFアップデート情報~2018年のCNCFを振り返る
Docker道場「Dockerの基本概念」0825インフラ勉強会資料
コンテナ導入概要資料2018

Dockerfileを改善するためのBest Practice 2019年版

  • 1.
    DockerCon SF19 で発表の、基礎→マルチ・ステージ・ビルド→最新動向までSakuraInternet, Inc.Masahito Zembutsu @zembutsuDocker Meetup Kansai #3 #dockerkansaiMay 24, 2019Dockerfileを改善するためのBest Practice 2019年版
  • 2.
    DockerCon SF19 での発表に基づく内容•Dockerfile Best Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices2• 動画もご覧ください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 videowill also be helpful.
  • 3.
    このスライドは何?3⚫ DockerCon 19で発表された人気シリーズ“Best Practices” を日本訳+解説の追加。⚫ Dockerfile の改善を通して、現在利用できるマルチ・ステージ・ビルドや BuildKit 紹介。以上の内容です。※ "Docker Meetup Kansai #3" 発表時のスライドをベースに、スライドそのままでは分かりづらい部分があるため、一部で発表時と異なる表現・補足説明を用いている場合があります。ゴール:「Dockerfileの改善を具体的に理解」
  • 4.
    Dockerfileのベストプラクティス• "Best practicesfor writing Dockerfiles"https://docs.docker.com/develop/develop-images/dockerfile_best-practices/4最新の日本語訳を公開しました。そもそもの基本となるのは、"Dockerfileを書くためのベストプラクティス"です。
  • 5.
  • 6.
    Dockerfile とは?6ド ッカ ー フ ァ イ ル
  • 7.
    Dockerfile• Docker はDockerfile から命令を読み込み、イメージを自動構築• テキスト形式のドキュメント• docker build / docker image build で Dockerfile を読み込み構築• 「Docker イメージを作るための設計図」• FROM、ADD、CMD など命令文で構成• 例) 何のイメージをもとに、何を実行するか?• 誰でも確実にイメージを構築できる• イメージの構築過程を確認できる• Dockerfileは広く使われている• GitHub上に Dockerfile は100万以上7automate buildblueprintImage 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=1BiuldKit は Docker とは別のプロジェクト (https://github.com/moby/buildkit ) ですが、現在の Docker CE v18.09 では、BuildKit の一部機能が既に利用できる状態です。
  • 10.
  • 11.
    Dockerfile の改善領域• 増大するbuild時間• イメージ容量• 保守性• 安全性• 一貫性・反復性11(Incremental) build timeImage sizeMaintainabilitySecurityConsistency/Repetabilityここからは、先日開催された DockerCon SF19での発表サンプルをベースにご紹介します。サンプルのアプリケーションを使い、5つの視点で Dockerfile を改善する流れをみていきましょう。
  • 12.
    サンプルの Dockerfile をカイゼンするぞ!12FROMdebianCOPY . /appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh emacsCMD ["java", "-jar", "/app/target/app.jar"]これは、Javaで"Hello world"を表示するための、サンプルプログラム用の Dockerfile です。
  • 13.
    サンプルの Dockerfile をカイゼンするぞ!13FROMdebianCOPY . /appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh emacsCMD ["java", "-jar", "/app/target/app.jar"]vimまずすべきは、emacs を消して、vim を入れましょう。もちろんジョークですが!
  • 14.
    サンプルの Dockerfile をカイゼンするぞ!14FROMdebianCOPY . /appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh emacsCMD ["java", "-jar", "/app/target/app.jar"]vimまずすべきは、emacs を消して、vim を入れましょう。もちろんジョークですが!
  • 15.
  • 16.
    キャッシュする順番が重要16FROM debianCOPY ./appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimCOPY . /appCMD ["java", "-jar", "/app/target/app.jar"]頻繁に変更するものを後ろへ構築時のキャッシュとは、変更箇所があれば破棄されます。この例の COPY では「.」(カレント)にあるファイルに変更があれば、毎回「apt-get update」と「install」が走るので、時間がかかってしまいます。せっかくあrキャッシュを有効活用するには、頻繁に更新する可能性があるものを後ろにおきます。
  • 17.
    キャッシュする順番が重要17FROM debianCOPY ./appRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimCOPY . /appCMD ["java", "-jar", "/app/target/app.jar"]頻繁に変更するものを後ろへ構築時のキャッシュとは、変更箇所があれば破棄されます。この例の COPY では「.」(カレント)にあるファイルに変更があれば、毎回「apt-get update」と「install」が走るので、時間がかかってしまいます。せっかくあrキャッシュを有効活用するには、頻繁に更新する可能性があるものを後ろにおきます。キャッシュ有効キャッシュ破棄 … ホスト側「 ./ 」に変更時キャッシュ破棄 … ホスト側「 ./ 」に変更時時間がかかるので、キャッシュ活用すべし時間かかる
  • 18.
    キャッシュ破棄の影響を避けるため、範囲を狭く18FROM debianRUN apt-getupdateRUN apt-get –y install openjdk-8-jdk ssh vimCOPY . /appCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]コピーに必要なものを明示する。可能であれば "COPY ."を避けるコピーすべき場所を絞っておけば、キャッシュは破棄されません。この例では「app.jar」しか「COPY」しませんので、他のファイルに変更があってもキャッシュを保持。
  • 19.
    キャッシュ破棄の影響を避けるため、範囲を狭く19FROM debianRUN apt-getupdateRUN apt-get –y install openjdk-8-jdk ssh vimCOPY . /appCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]コピーすべき場所を絞っておけば、キャッシュは破棄されません。この例では「app.jar」しか「COPY」しませんので、他のファイルに変更があってもキャッシュを保持。キャッシュ有効キャッシュ有効キャッシュ有効ちょっとキャッシュする範囲が拡がるかもねキャッシュ対象の明確化コピーに必要なものを明示する。可能であれば "COPY ."を避ける
  • 20.
    行をまとめる: apt-get update& install20FROM debianRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimRUN apt-get update ¥&& apt-get -y install ¥openjdk-8-jdk ssh vimCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]古いパッケージ情報のキャッシュ利用を避けるパッケージ・マネージャを使う場合、「古い」パッケージ情報をキャッシュしがちです。更新したいのに更新できないのを避けるには、情報の更新と、パッケージ追加・削除をまとめること。
  • 21.
    行をまとめる: apt-get update& install21FROM debianRUN apt-get updateRUN apt-get –y install openjdk-8-jdk ssh vimRUN apt-get update ¥&& apt-get -y install ¥openjdk-8-jdk ssh vimCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]古いパッケージ情報のキャッシュ利用を避けるパッケージ・マネージャを使う場合、「古い」パッケージ情報をキャッシュしがちです。更新したいのに更新できないのを避けるには、情報の更新と、パッケージ追加・削除をまとめること。キャッシュ有効古いものをキャッシュしてるかも!時間かかる場合があっても、確実に処理
  • 22.
  • 23.
    不要な依存関係を削除23FROM debianRUN apt-getupdate ¥&& apt-get -y install --no-install-recommends ¥openjdk-8-jdk ssh vimCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]デプロイを素早くするためには、イメージ容量の削減が重要であり、必須課題。推奨パッケージ(必須ではない)を避けるためには、「--no-install-recommends」フラグを付ける。Javaの実行に不要なパッケージも入れないので「ssh」「vim」も消す。
  • 24.
    不要なパッケージマネージャのキャッシュ削除24FROM debianRUN apt-getupdate ¥&& apt-get -y install –no-install-recommends ¥openjdk-8-jdk ¥&& rm –rf /var/lib/apt/lists/*COPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]パッケージ・マネージャのキャッシュ情報も、アプリケーションの実行に不要なので削除
  • 25.
  • 26.
    できるだけDocker公式(official)パッケージを使う• メンテナンスにかける時間を減らす(問題があるたびに、繰り返す更新)• 容量を減らす(イメージ間でのレイヤ共有によって)•コンテナとして使うために、予め設定済み• 賢い人達が構築している26パッケージ・マネージャのキャッシュ情報も、アプリケーションの実行に不要なので削除
  • 27.
    27FROM debianRUN apt-getupdate ¥&& apt-get -y install –no-install-recommends ¥openjdk-8-jdk ¥&& rm –rf /var/lib/apt/lists/*FROM openjdkCOPY target/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]できるだけDocker公式(official)パッケージを使うJavaの実行であれば、「openjdk」イメージがあるため、debianでセットアップする必要はない
  • 28.
    タグを明示28FROM openjdk:latestFROM openjdk:8COPYtarget/app.jar /appCMD ["java", "-jar", "/app/target/app.jar"]"latest"タグは常に入れ替わる。タグを指定しておけば、想定外のベース・イメージ変更発生を防止。何も指定しなければ「latest」(最新)になるため、常にタグ(主にバージョン)指定を忘れずに
  • 29.
  • 30.
    必要最小限のものを探す30REPOSITORY TAG SIZEopenjdk8 624MBopenjdk 8-jre 443MBopenjdk 8-jre-slim 204MBopenjdk 8-jre-alpie 83MBベース・イメージの変更だけで540MBも削減どのイメージ(タグ)を選ぶかによって、容量がかなり異なる。alpineタグは Alpine Linux という約 5MB の Linux ディストリビューションがベース
  • 31.
  • 32.
  • 33.
    一貫した環境を、ソースから構築する• Dockerfile を設計図(青写真)にしよう:•ビルド時するための構築環境を Dockerfile に記述• 正しいバージョンのビルド・ツールをインストール• 環境ごとの違いを発生させない• システム依存はあるかもしれない• "source of truth"(本当のソース)とは、ソースコードである。ビルド成果物ではない。33Image by John Dortmunder from Pixabayblue print開発環境、テスト環境、実行環境で共通する Dockerfile を目指す
  • 34.
    一貫した環境を、ソースから構築する34FROM openjdk:8-jre-alpineFROM maven:3.6-jdk-8-alpineWORKDIR/appCOPY app.jar/appCOPY pom.xml .COPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]openjdk にかわり、Javaプロジェクト管理ツールであるMavenを開発環境として入れる
  • 35.
    一貫した環境を、ソースから構築する35FROM maven:3.6-jdk-8-alpineWORKDIR /appCOPYpom.xml .COPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]このように、開発環境向けの Dockerfile を整えていく。
  • 36.
    依存関係の解決は、ステップを分ける36FROM maven:3.6-jdk-8-alpineWORKDIR /appCOPYpom.xml .RUN mvn –e –B dependency:resolveCOPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]開発関係だけに必要な依存関係を追加。
  • 37.
    構築時のみの依存関係が判明37FROM maven:3.6-jdk-8-alpineWORKDIR /appCOPYpom.xml .RUN mvn –e –B dependency:resolveCOPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]しかし、この黄色い部分は「開発環境の構築」段階しか使わないものであり、本番稼働では無駄
  • 38.
    マルチ・ステージ・ビルドで、構築時の部分を削除38FROM maven:3.6-jdk-8-alpine ASbuilderWORKDIR /appCOPY pom.xml .RUN mvn –e –B dependency:resolveCOPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app/target/app.jar"]FROM openjdk:8-jre-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app/target/app.jar"]そこで、マルチ・ステージ・ビルドで複数の「FROM」を使い、構築時(AS bilder)と実行時を分離←「builder」ステージからファイルをコピー←ステージ「builder」と名前を付ける
  • 39.
    マルチ・ステージ・ビルドで、構築時の部分を削除39FROM maven:3.6-jdk-8-alpine ASbuilderWORKDIR /appCOPY pom.xml .RUN mvn –e –B dependency:resolveCOPY src ./srcRUN mvn –e –B packageFROM openjdk:8-jre-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app/target/app.jar"]マルチ・ステージ・ビルドでは、「docker build」は全てのビルドを実行しますし、「docker build –target builder」と指定すると「AS builder」の「FROM」ステージしか処理しません。
  • 40.
  • 41.
    プロジェクトごとに多くのステージがある• Moby: 16ステージhttps://github.com/moby/moby/blob/master/Dockerfile• BuildKit: 44 ステージhttps://github.com/moby/buildkit/blob/master/hack/dockerfiles/test.buildkit.Dockerfile41Docker 関連プロジェクトの Dockerfile にも、多くのステージ(FROM命令)がある
  • 42.
    マルチ・ステージの利用例• 実行環境と構築(ビルド)環境を分ける(イメージ容量の縮小)• イメージに対する影響を最小限に(DRY)•構築・開発・テスト・構文チェック…のような環境を明示• 依存関係を一直線に処理しない(並列化)• プラットフォーム固有のステージ42一般的な目的は、最終成果物の容量を削減
  • 43.
    構築ステージを --target で指定43FROMimage_or_stage AS stage_name…$ docker build --target stage_name「AS ステージ名」を FROM 命令に書いておけば、「docker build」時に「--target」でステージを指定
  • 44.
    イメージの flavor を変える44FROMmaven:3.6-jdk-8-alpine AS builder...FROM openjdk:8-jre-jessie AS release-jessieCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]FROM openjdk:8-jre-jessie AS release-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]$ docker build --target release-jessie .Debian jessie (8.x) をベースとするイメージと、Alpine Linux をベースとするイメージ。特色(風味)
  • 45.
    45FROM maven:3.6-jdk-8-alpine ASbuilder...FROM openjdk:8-jre-jessie AS release-jessieCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]FROM openjdk:8-jre-jessie AS release-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]$ docker build --target release-jessie .イメージの flavor を変える特色(風味)しかし、 Dockerfile をよく見ると問題があり、
  • 46.
    46FROM maven:3.6-jdk-8-alpine ASbuilder...FROM openjdk:8-jre-jessie AS release-jessieCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]FROM openjdk:8-jre-jessie AS release-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]$ docker build --target release-jessie .このように各ステージで、同じ命令が重複する箇所がある。イメージの flavor を変える特色(風味)どちらも同じ
  • 47.
    47ARG flavor=alpineFROM maven:3.6-jdk-8-alpineAS builder...FROM openjdk:8-jre-$flavor AS releaseCOPY --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)…49FROM maven:3.6-jdk-8-alpine ASbuilder...FROM openjdk:8-jre-alpine AS lintRUN wget https://github.com/checkstyle/checkstyle/releases/download/checkstyle-8.15/checkstyle-8.15-all.jarCOPY checks.xml .COPY src /srcRUN java –jar checkstyle-8.15-all.jar –c checks.xml /srcこれはシンプルな Java 構文チェック(リント)の確認用の Dockerfile を「AS lint」と指定
  • 50.
    様々な環境:構築、開発、テスト、構文チェック(lint)…50FROM maven:3.6-jdk-8-alpine ASbuilder...FROM openjdk:8-jre-alpine AS releaseCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]FROM builder AS devRUN apk add --no-cache strace vim tcpdumpENTRYPOINT ["ash"]開発用デバッグ環境であれば、「builder」ステージをベースにしながら「AS dev」と明示しシンプルにエディタ(vim)と tcpdump を入れている
  • 51.
    様々な環境:構築、開発、テスト、構文チェック(lint)…51FROM maven:3.6-jdk-8-alpine ASbuilder...RUN mvn –e –B package –DskipTestsFROM builder AS unit-testRUN mvn –e –B testFROM release AS integration-testRUN apk add --no-cache curlRUN ./test/run.sh他にも単体テスト、統合テスト用の環境も作れます。
  • 52.
  • 53.
    一直線の Dockerfile ステージから…• 全てのステージが順番(シーケンシャル)に実行• この図では、上から下に一直線• BuildKitがなければ、不要なステージも無駄に実行し、破棄する(無駄に時間がかかった)53s1s2s3s4s5s6デフォルトでは、全てのステージを順番に実行する
  • 54.
    BuildKit のマルチ・ステージ graphへ• BuildKit は下(--target のステージ名)から上に辿っていくような流れ• 右図では s2, s3, s4 ステージを同時並行処理• 不要なステージは無視できる• 右図では s5 がビルド時に不要であれば、何もしない54s1s2 s3 s4s5s6Docker 17.05 からマルチ・ステージ・ビルドが利用可能になった。18.06までは experimental 、18.09 は利用できるように組み込まれているグラフ※グラフは点と点とのつながり(関係性)を表す
  • 55.
    Multi-srage: 並行ビルド (buildconcurrently)55FROM maven:3.6-jdk-8-alpine AS builder...FROM tiborvass/whalesay AS assetsRUN whalesay "Hello DockerCon!" > /out/assets.htmlFROM openjdk:8-jre-alpine AS releaseCOPY --from=builder /app/target/app.jar /COPY --from=assets /out /assetsCMD ["java", "-jar", "/app.jar"]「assets」は最終イメージ(release)に必要だが、別のステージとして処理できるそして、この Dockerfile は「builder」と「assets」のステージからのコピーを並行処理
  • 56.
    Multi-srage: 並行ビルド (buildconcurrently)56FROM maven:3.6-jdk-8-alpine AS builder-base…FROM gcc:8-alpine AS builder-someClib…RUN git clone … ¥./configure --prefix=/out && make && make installFROM g++:8-alpine AS builder-someCPPlib…RUN git clone … ¥cmake …FROM builder-base AS builderCOPY --from=builder-someClib /out /COPY --from=builder-someCPPlib /out /複数の COPY 命令を使う時には、特に効果を発揮し、時間を節約できる並行処理が有用な典型的なパターンが複数の COPY --from … の繰り返し
  • 57.
    ベンチマーク• github.com/moby/moby Dockerfile,master ブランチ• 小さいほうが優れている57Dockerfile Best Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices/52v18.03 の docker build と BuiltKit では2倍の速さ
  • 58.
    ベンチマーク• github.com/moby/moby Dockerfile,master ブランチ• 小さいほうが優れている58Dockerfile Best Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices/52キャッシュを有効にすると、7倍も速くなる
  • 59.
    ベンチマーク• github.com/moby/moby Dockerfile,master ブランチ• 小さいほうが優れている59Dockerfile Best Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices/52最も大事なのは、ソースコードの変更時。再構築の速度はマルチ・ステージ・ビルドで 2.5 倍に改善。
  • 60.
  • 61.
    新機能を有効にするには?61# syntax=docker/dockerfile:1.0-experimentalFROM maven:3.6-jdk-8-alpineAS builderWORKDIR /appCOPY . /appRUN mvn -e –B packageFROM openjdk:8-jre-alpineCOPY --from=builder /app/target/app.jar /CMD ["java", "-jar", "/app.jar"]Dockerfile の新機能を有効にするには、この行を1行目に追加する必要がある※experimental というのは、まだDockerfile の正式な構文ではないため
  • 62.
  • 63.
    コンテキスト・マウント(v18.09+ w/ BuildKit)63#syntax=docker/dockerfile:1.0-experimentalFROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appCOPY . /appRUN --mount=target=. mvn -e –B package -DoutputDirectory=/FROM openjdk:8-jre-alpineCOPY --from=builder /app/app.jar /CMD ["java", "-jar", "/app.jar"]新機能を使って Dockerfile を書き換えていく。まずはマウント・オプション。実行時に「.」(カレント・ディレクトリ内容)を Build Context として送信せず、マウントできる※ Docker v18.09 以上かつ、BuildKit 有効化の状態で利用可能contest mounts
  • 64.
    Dockerfilehelloコンテキスト・マウント(v18.09+ w/ BuildKit)64ディレクトリ内容をコンテナにCOPY しなくても、ビルド時に docker build コマンドを実行しているディレクトリ(ここでは 「target=.」で指定)をrw(読み書き可能な状態)で直接コンテナにマウントし、コンテナ内で「cat hello > /hello.txt」を実行→ 構築したイメージの“/hello.txt” に “Hello world!” が書かれたファイルが作成される# syntax=docker/dockerfile:1.0-experimentalFROM alpineRUN --mount=type=bind,target=.,rw cat hello > /hello.txtHello world!ソースコードなど、ビルド・コンテクストのコピーが不要となり、より早いビルドができるcontest mounts• Dockerfile の mount 例:ホスト側の docker build する場所に、このファイルがあるとします
  • 65.
    65コンテキスト・マウント(v18.09+ w/ BuildKit)contestmounts従来 “COPY . /app” BuildKitDockerfileapp用ディレクトリBuild用ディレクトリ“docker build” 時、 「.」 以下の内容をDocker イメージ用レイヤとして構築するため全て Docker に対して送る必要があった※結果として Docker イメージの不本意な増加※あるいはマルチ・ステージ・ビルドで回避Dockerfileapp用ディレクトリBuild用ディレクトリコンテナコピー マウントよいしょ…みーてーるーだーけー“docker build” の特定ステップのみ参照するため、・ build 全体の時間を削減・ イメージ・レイヤの肥大化を抑制
  • 66.
    キャッシュの保持(BuildKitが無ければ)66FROM maven:3.6-jdk-8-alpine ASbuilderWORKDIR /appCOPY pom.xml .RUN mvn -e –B dependency: resolveCOPY src ./srcRUN mvn –e –B packageCMD ["java", "-jar", "/app.jar"]docker build 時にキャッシュが破棄されると、毎回依存関係の準備に時間がかかる
  • 67.
    キャッシュの保持(v18.09+ w/ BuildKit)67#syntax=docker/dockerfile:1.0-experimentalFROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appRUN --mount=target=. --mount=type=cache,target=/root/.m2 ¥&& mvn package –DoutputDirectory=/FROM openjdk:8-jre-alpineCOPY --from=builder /app.jar /CMD ["java", "-jar", "/app.jar"]apt: /var/lib/apt/listsgo: ~/.cache/go-buildgo-modules: $GOPATH/pkg/modnpm: ~/.npmpip: ~/.cache/pipキャッシュ用ディレクトリをマウントできるので、依存関係の準備にかかる時間を削減できる
  • 68.
    キャッシュの保持• --mount=type=cache 例:68Dockerfile#syntax=docker/dockerfile:1.0-experimentalFROM ubuntuRUN --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」コマンドを実行する
  • 69.
  • 70.
    シークレット(これはダメな方法)70FROM baseimageRUN …ENVAWS_ACCESS_KEY_ID=…ENV AWS_SECRET_ACCESS_KEY=…RUN ./fetch-aseets-from-s3.shRUN ./build-scripts.shシークレット(secret)とは、パスワードやAPIキー、SSH 鍵などの認証情報(機微情報)ENV に書くと docker history で丸見えですし、
  • 71.
    シークレット(これもダメな方法)71FROM baseimageRUN …ARGAWS_ACCESS_KEY_IDARG AWS_SECRET_ACCESS_KEYRUN ./fetch-aseets-from-s3.shRUN ./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-experimentalFROM baseimageRUN …RUN --mount=type=secret,id=aws,target=/root/.aws/credentials,required ./fetch-assets-from-s3.shRUN ./build-scripts.sh$ docker build --secret id=aws,src=~/.aws/credentials .最終イメージに混入させないための手法が「secret」としてのマウント。対象ステップのみデータを参照できるよう一時的にマウントし、次のステップではマウントしません。↓idは docker build 時の –secret オプションで識別するため↑targetで、この構築ステップのみ、コンテナ内のこの場所に一時的にファイルを設置する指示↑これはホスト側に存在するファイル。~より、 $HOME や絶対パスのほうが安全かも↑次のステップでは、先の id=aws でマウントしたシークレットは見えない( 0 byte のファイル残骸のみ)
  • 73.
  • 74.
    • Dockerfile のmount secret 例:Dockerfile$HOME/secretシークレット・マウント(v18.09+ w/ BiuldKit)74# syntax=docker/dockerfile:1.0-experimentalFROM alpineRUN --mount=type=secret,id=check,target=/root/secret,required ¥cat /root/secret > /data.txtMYID=secretpassDockerfile で当該 RUN 命令行のビルド時のみ、一時的にホスト側ファイルをマウントできるsecret mountsホスト側にIDとパスワードのような、いわゆるシークレット(機微情報)を記録するファイルを設置もちろん、パーミッションは 600 にするなど、十分なセキュリティ配慮が必要$ docker build --secret id=check,src=$HOME/.data/credentials -t myimage .↑srcで指定したパスはホスト上のファイル
  • 75.
    プライベート git リポジトリ(ダメぜったい)75FROMbaseimageCOPY ./keys/private.pem /root/.ssh/private.pemARG REPO_REF=19ba8bcd9976ef8a9bd086187df19ba7bcd997f2RUN git clone git@githubcom:org/repo /work && cd /work ¥&& git checkout –b $REPO_REFこれもイメージ内に大事なファイルが残ってしまう NG 例
  • 76.
    プライベート git リポジトリ(v18.09+w/BuildKitの場合)76FROM alpineRUN apk add --no-cache openssh-clientRUN mkdir –p –m 0700 ~/.ssh && ssh-keyscan github.com >>~/.ssh/known_hostsARG REPO REF=19ba8bcd9976ef8a9bd086187df19ba7bcd997f2RUN –-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.
    BuildKit77SSH マウント(v18.09+ w/BiuldKit)mountsDockerfile.sshBuild用ディレクトリコンテナ鍵情報参照このステップがある間だけみーてーるーだーけー“docker build” の対象構築ステップ時のみ、ホスト側のSSH agent 情報を一時的にマウントシークレット・マウントに近いけれどSSH の利用に特化こんてなから GitHub や SSH 接続したい場合に有用dockerbuildid_rsa ssh-agent--mount=type=sshSSHリモート・ホストやGitHub / GitLab 等
  • 78.
    • Dockerfile のmount=SSH 例:DockerfileSSH マウント(v18.09+ w/ BiuldKit)78# syntax=docker/dockerfile:1.0-experimentalFROM alpineRUN apk update && apk add opensshRUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan <host_IP> > ~/.ssh/known_hostsRUN --mount=type=ssh,required ¥ssh <user>@<host_IP> ls -al / > /ls.txtGitHubやGitLabの認証だけでなk、別のホストにこのようにしてログイン&操作も可能mounts$ eval $(ssh-agent)$ ssh-add ~/.ssh/id_rsa(パスフレーズを入力)$ docker build --ssh default=$SSH_AUTH_SOCK -t <image_name> .
  • 79.
    Dockerfile 改善のまとめ• 従来⁃構築・開発・テスト環境の矛盾⁃ 膨れあがるイメージ容量⁃ 構築時間がマシマシ(キャッシュ無効)になり時間がかかる⁃ 構築が安全ではない• これから( BuildKit の活用によって)⁃ 構築・開発・テスト環境が一致⁃ イメージ容量は最小⁃ 構築が非常に速く、構築回数が増えていく⁃ より安全に構築できる79export DOCKER_BUILDKIT=1重要なのは有効化に新しいビルド時の一時マウント可能な bind、cache、tmpfs、secret、sshマルチ・ステージ・ビルドの活用によって、段階ごとの FROMステージ間のコピー機能により、最終成果物を小さく並列ビルドの活用により、従来よりも素早い構築
  • 80.
    参考資料• Advanced multi-stagebuild patterns – Tõnis Tiigi – Mediumhttps://medium.com/@tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae• Build secrets and SSH forwarding in Docker 18.09 – Tõnis Tiigi – Mediumhttps://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066• Introducing BuildKit – Moby Bloghttps://blog.mobyproject.org/introducing-buildkit-17e056cc5317• docker builder prune | Docker Documentationhttps://docs.docker.com/engine/reference/commandline/builder_prune/• Docker v18.09 新機能 (イメージビルド&セキュリティ) – nttlabs – Mediumhttps://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-9534714c26e280
  • 81.
  • 82.
    DockerCon での発表• DockerfileBest Practiceshttps://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices82• 動画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.com83

[8]ページ先頭

©2009-2025 Movatter.jp