Slide 1

Slide 1 text

Copyright © 2022 RevComm Inc. よりよいDockerfileを考える ~Pythonの実例とともに~ RevComm Shota Kokado

Slide 2

Slide 2 text

Copyright © 2022 RevComm Inc. contents 1. はじめに 2. “よい Dockerfile” とは 3. Let’s practice! 4. 実践事例の紹介

Slide 3

Slide 3 text

Copyright © 2022 RevComm Inc. はじめに 3 この資料の想定読者 ● コンテナ技術に入門済みの人 ● Dockerfile を書いたことがある人 ● Web アプリケーション開発者(インタプリタ言語)

Slide 4

Slide 4 text

Copyright © 2022 RevComm Inc. はじめに 4 この資料の想定読者 ● コンテナ技術に入門済みの人 ● Dockerfile を書いたことがある人 ● Web アプリケーション開発者(インタプリタ言語) この資料で話さないこと ● コンテナとは何か?コンテナ技術の仕組み ● ML/DL、バッチ処理用途のワークロード ● コンパイル言語向けのこと(Java, Go, Rust) ○ …Dockerfile の戦略が異なってくる (alpine とか distroless とか)

Slide 5

Slide 5 text

Copyright © 2022 RevComm Inc. “よい Dockerfile” とは 5

Slide 6

Slide 6 text

Copyright © 2022 RevComm Inc. “よい Dockerfile” とは 6 コンテナイメージにとって重要な性質(抜粋) 参考: Dockerfile のベスト・プラクティス — Docker-docs-ja 20.10 ドキュメント ● ※“コンテナ” 自体の理解 ● 開発利便性 ● 可搬性 / セキュリティ

Slide 7

Slide 7 text

Copyright © 2022 RevComm Inc. “よい Dockerfile” とは 7 コンテナイメージにとって重要な性質(抜粋) 参考: Dockerfile のベスト・プラクティス — Docker-docs-ja 20.10 ドキュメント ● ※“コンテナ” 自体の理解 ○ 仮想マシン (VM) と同じ使い方をしない ○ (原則) 1コンテナ1プロセス ● 開発利便性 ● 可搬性 / セキュリティ

Slide 8

Slide 8 text

Copyright © 2022 RevComm Inc. “よい Dockerfile” とは 8 コンテナイメージにとって重要な性質(抜粋) 参考: Dockerfile のベスト・プラクティス — Docker-docs-ja 20.10 ドキュメント ● ※“コンテナ” 自体の理解 ○ 仮想マシン(VM)と同じ使い方をしない ○ (原則) 1コンテナ1プロセス ● 開発利便性 ○ ビルド時キャッシュを活用する ● 可搬性 / セキュリティ ○ .dockerignore で除外 ○ レイヤの数は最小に ○ ベースイメージとパッケージを最新化する ○ 不要なパッケージをインストールしない

Slide 9

Slide 9 text

Copyright © 2022 RevComm Inc. “よい Dockerfile” とは 9 コンテナイメージにとって重要な性質(抜粋) 参考: Dockerfile のベスト・プラクティス — Docker-docs-ja 20.10 ドキュメント ● ※“コンテナ” 自体の理解 ○ 仮想マシン(VM)と同じ使い方をしない ○ (原則) 1コンテナ1プロセス ● 開発利便性 ○ ビルド時キャッシュを活用する ● 可搬性 / セキュリティ ○ .dockerignore で除外 ○ レイヤの数は最小に ○ ベースイメージとパッケージを最新化する ○ 不要なパッケージをインストールしない ⇒Python アプリケーションを想定した実例とともに深堀り

Slide 10

Slide 10 text

Copyright © 2022 RevComm Inc. Let’s practice! 10

Slide 11

Slide 11 text

Copyright © 2022 RevComm Inc. 前提 11 ● Django を動かすだけの簡単なアプリケーションを想定 ● uWSGI でサーバー起動するまでを目標 JSON で応答を返す

Slide 12

Slide 12 text

Copyright © 2022 RevComm Inc. (再掲) “よい Dockerfile” とは 12 コンテナイメージにとって重要な性質(抜粋) 参考: Dockerfile のベスト・プラクティス — Docker-docs-ja 20.10 ドキュメント ● ※“コンテナ” 自体の理解 ○ 仮想マシン(VM)と同じ使い方をしない ○ (原則) 1コンテナ1プロセス ● 開発利便性 ○ ビルド時キャッシュを活用する ● 可搬性 / セキュリティ ○ .dockerignore で除外 ○ レイヤの数は最小に ○ ベースイメージとパッケージを最新化する ○ 不要なパッケージをインストールしない

Slide 13

Slide 13 text

Copyright © 2022 RevComm Inc. ● 先頭で COPY ./ ./ をしない ○ docker build で毎回(≒ソースコードを書き換える度)初めからになってしまう(= キャッシュを活用できない) ○ ビルド過程で必要となる requirements.txt などを先に配置する 開発利便性 - ビルド時キャッシュを活用する(1/2) 13

Slide 14

Slide 14 text

Copyright © 2022 RevComm Inc. ● 先頭で COPY ./ ./ をしない ○ docker build で毎回(≒ソースコードを書き換える度)初めからになってしまう(= キャッシュを活用できない) ○ ビルド過程で必要となる requirements.txt などを先に配置する 開発利便性 - ビルド時キャッシュを活用する(1/2) 14 ソースコード変更の度に「pip install …」が実行される

Slide 15

Slide 15 text

Copyright © 2022 RevComm Inc. ● 先頭で COPY ./ ./ をしない ○ docker build で毎回(≒ソースコードを書き換える度)初めからになってしまう(= キャッシュを活用できない) ○ ビルド過程で必要となる requirements.txt などを先に配置する 開発利便性 - ビルド時キャッシュを活用する(1/2) 15 ソースコード変更後は 7行目から開始

Slide 16

Slide 16 text

Copyright © 2022 RevComm Inc. ● 先頭で COPY ./ ./ をしない ○ docker build で毎回(≒ソースコードを書き換える度)初めからになってしまう(= キャッシュを活用できない) ○ ビルド過程で必要となる requirements.txt などを先に配置する ○ パッケージマネージャを使用する場合 開発利便性 - ビルド時キャッシュを活用する(1/2) 16 ● Pipenv ※以降、Pipenv を使用する前提のサンプルとする ● Poetry

Slide 17

Slide 17 text

Copyright © 2022 RevComm Inc. ● 必要な定型処理を先に実行する ○ パッケージのインストールを先に行う 開発利便性 - ビルド時キャッシュを活用する(2/2) 17

Slide 18

Slide 18 text

Copyright © 2022 RevComm Inc. ● 必要な定型処理を先に実行する ○ パッケージのインストールを先に行う 開発利便性 - ビルド時キャッシュを活用する(2/2) 18 Pipfile / Pipfile.lock を変更した場合、 直後のビルドは7行目から開始する

Slide 19

Slide 19 text

Copyright © 2022 RevComm Inc. “よい Dockerfile” とは 19 コンテナイメージにとって重要な性質(抜粋) 参考: Dockerfile のベスト・プラクティス — Docker-docs-ja 20.10 ドキュメント ● ※“コンテナ” 自体の理解 ○ 仮想マシン(VM)と同じ使い方をしない ○ (原則) 1コンテナ1プロセス ● 開発利便性 ○ ビルド時キャッシュを活用する ● 可搬性 / セキュリティ ○ .dockerignore で除外 ○ レイヤの数は最小に ○ ベースイメージとパッケージを最新化する ○ 不要なパッケージをインストールしない

Slide 20

Slide 20 text

Copyright © 2022 RevComm Inc. “可搬性” (Portability) … コンテナイメージを軽量に保つことで複数のホスト・基盤上で共有しやすくする。 軽量化には不要なパッケージ・ライブラリを含めないことが重要。結果、セキュリティ向上につながる。 可搬性 / セキュリティ 20

Slide 21

Slide 21 text

Copyright © 2022 RevComm Inc. (再掲) “よい Dockerfile” とは 21 コンテナイメージにとって重要な性質(抜粋) 参考: Dockerfile のベスト・プラクティス — Docker-docs-ja 20.10 ドキュメント ● ※“コンテナ” 自体の理解 ○ 仮想マシン(VM)と同じ使い方をしない ○ (原則) 1コンテナ1プロセス ● 開発利便性 ○ ビルド時キャッシュを活用する ● 可搬性 / セキュリティ ○ .dockerignore で除外 ○ レイヤの数は最小に ○ ベースイメージとパッケージを最新化する ○ 不要なパッケージをインストールしない

Slide 22

Slide 22 text

Copyright © 2022 RevComm Inc. ● 同じ命令は可能な限りまとめる レイヤの数を最小にする > RUN 、 COPY 、 ADD 命令のみレイヤを作成します。他の命令では、一時的な中間イメージ(temporary intermediate images)を作成し、構築時の容 量は増えません。 1. RUN 可搬性 / セキュリティ (1/2) - レイヤの数は最小に 22 2. COPY 3. ADD ※COPY が推奨される

Slide 23

Slide 23 text

Copyright © 2022 RevComm Inc. ● 同じ命令は可能な限りまとめる レイヤの数を最小にする > RUN 、 COPY 、 ADD 命令のみレイヤを作成します。他の命令では、一時的な中間イメージ(temporary intermediate images)を作成し、構築時の容 量は増えません。 1. RUN 可搬性 / セキュリティ (1/2) - レイヤの数は最小に 23 2. COPY 3. ADD ※COPY が推奨される 1行目の中間レイヤーを保持するため 3-4行目はイメージサイズ削減に効果が無い

Slide 24

Slide 24 text

Copyright © 2022 RevComm Inc. (再掲) “よい Dockerfile” とは 24 コンテナイメージにとって重要な性質(抜粋) 参考: Dockerfile のベスト・プラクティス — Docker-docs-ja 20.10 ドキュメント ● ※“コンテナ” 自体の理解 ○ 仮想マシン(VM)と同じ使い方をしない ○ (原則) 1コンテナ1プロセス ● 開発利便性 ○ ビルド時キャッシュを活用する ● 可搬性 / セキュリティ ○ .dockerignore で除外 ○ レイヤの数は最小に ○ ベースイメージとパッケージを最新化する ○ 不要なパッケージをインストールしない

Slide 25

Slide 25 text

Copyright © 2022 RevComm Inc. ● ベースイメージ ○ “buster” イメージを使っていませんか?(python:3.x-buster、python:3.x-slim-buster) ○ No!最新は “bullseye” です(= Debian 11.0) ※2022年11月時点 ○ ベースイメージには debian バージョンを指定しなくても良いかも(alias があるので) ■ python:3.10.8 = python:3.10.8-bullseye ■ python:3.10.8-slim = python:3.10.8-slim-bullseye ベースイメージとパッケージを最新化する 25

Slide 26

Slide 26 text

Copyright © 2022 RevComm Inc. ● ベースイメージ ○ “buster” イメージを使っていませんか?(python:3.x-buster、python:3.x-slim-buster) ○ No!最新は “bullseye” です(= Debian 11.0) ※2022年11月時点 ○ ベースイメージには debian バージョンを指定しなくても良いかも(alias があるので) ■ python:3.10.8 = python:3.10.8-bullseye ■ python:3.10.8-slim = python:3.10.8-slim-bullseye ● パッケージ ○ Docker 公式ドキュメントで「Dockerfile の中で apt-get upgrade しないように」と書かれていたのは昔の話 ○ OWASP が提唱して、Docker コミュニティも修正済み ○ Not installing security updates is bad advice by itamarst · Pull Request #614 · OWASP/CheatSheetSeries ○ Stop telling people not to install security updates by itamarst · Pull Request #12571 · docker/docs ○ パッケージは必ず最新化しましょう! ○ 定期的にイメージを更新しましょう! ベースイメージとパッケージを最新化する 26

Slide 27

Slide 27 text

Copyright © 2022 RevComm Inc. (再掲) “よい Dockerfile” とは 27 コンテナイメージにとって重要な性質(抜粋) 参考: Dockerfile のベスト・プラクティス — Docker-docs-ja 20.10 ドキュメント ● ※“コンテナ” 自体の理解 ○ 仮想マシン(VM)と同じ使い方をしない ○ (原則) 1コンテナ1プロセス ● 開発利便性 ○ ビルド時キャッシュを活用する ● 可搬性 / セキュリティ ○ .dockerignore で除外 ○ レイヤの数は最小に ○ ベースイメージとパッケージを最新化する ○ 不要なパッケージをインストールしない

Slide 28

Slide 28 text

Copyright © 2022 RevComm Inc. ● デフォルトのベースイメージには無駄なパッケージが(非常に)多い ⇒slim イメージを使いましょう ● slim イメージには gcc などビルドツール群が含まれないため、Python ライブラリをビルドできない場合がある ⇒マルチステージビルドを使う ○ slim イメージに gcc をインストールするのは 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 28

Slide 29

Slide 29 text

Copyright © 2022 RevComm Inc. ここまでの整理 ● slim イメージを使用する ○ Python ライブラリの準備を “not slim イメージ” で行う (マルチステージビルド) 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 29

Slide 30

Slide 30 text

Copyright © 2022 RevComm Inc. ここまでの整理 ● slim イメージを使用する ○ Python ライブラリの準備を “not slim イメージ” で行う (マルチステージビルド) ● 課題 ○ パッケージマネージャー (Pipenv / Poetry) をアプリケーションに含めたくない ○ dev-packages (テスト用ツールなど)を本番用イメージから分離した ■ CI では dev-packages を使いたい 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 30 アプリケーション自体に Pipenv は要らない (普通は)

Slide 31

Slide 31 text

Copyright © 2022 RevComm Inc. ● 結論 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 31 こちらでも見れます

Slide 32

Slide 32 text

Copyright © 2022 RevComm Inc. ● 結論 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 32 FROM [base image] AS [stage name] という形式 1つの FROM 命令のブロックが1ステージと対応

Slide 33

Slide 33 text

Copyright © 2022 RevComm Inc. ● 結論 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 33 1. ステージ: export ○ requirements.txt 形式のライブラリ一覧を生成する ○ ⇒後続ステージにて Pipenv が不要となる

Slide 34

Slide 34 text

Copyright © 2022 RevComm Inc. ● 結論 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 34 1. ステージ: export ○ requirements.txt 形式のライブラリ一覧を生成する ○ ⇒後続ステージにて Pipenv 不要となる 2. ステージ: builder / dev-builder ○ requirements.txt を元にライブラリを準備する ○ COPY --from=[stage name] … でステージ間でファイルを受け取る ○ prod 用、dev 用の2通りを用意

Slide 35

Slide 35 text

Copyright © 2022 RevComm Inc. ● 結論 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 35 1. ステージ: export ○ requirements.txt 形式のライブラリ一覧を生成する ○ ⇒後続ステージにて Pipenv 不要となる 2. ステージ: builder / dev-builder ○ requirements.txt を元にライブラリを準備する ○ COPY --from=[stage name] … でステージ間でファイルを受け取る ○ prod 用、dev 用の2通りを用意 3. ステージ: base ○ 最終的なアプリケーション用の環境をセットアップ ○ 必要なパッケージをインストール ○ ※一般ユーザーを作成、スイッチなど(割愛) libpq5: PostgreSQL 接続に必要 libxml2: uWSGI 実行に必要

Slide 36

Slide 36 text

Copyright © 2022 RevComm Inc. ● 結論 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 36 1. ステージ: export ○ requirements.txt 形式のライブラリ一覧を生成する ○ ⇒後続ステージにて Pipenv 不要となる 2. ステージ: builder / dev-builder ○ requirements.txt を元にライブラリを準備する ○ COPY --from=[stage name] … でステージ間でファイルを受け取る ○ prod 用、dev 用の2通りを用意 3. ステージ: base ○ 最終的なアプリケーション用の環境をセットアップ ○ 必要なパッケージをインストール ○ ※一般ユーザーを作成、スイッチなど(割愛) 4. ステージ: dev / prod ○ Python ライブラリをインストール ○ ソースコードを配置 ○ ※dev / prod で CMD を分ける、など適宜 ○ docker build --target [stage-name] .... でビルド対象ステージを 指定する

Slide 37

Slide 37 text

Copyright © 2022 RevComm Inc. ● 結論 可搬性 / セキュリティ (2/2) - 不要なパッケージをインストールしない 37

Slide 38

Slide 38 text

Copyright © 2022 RevComm Inc. 実践事例の紹介 38

Slide 39

Slide 39 text

Copyright © 2022 RevComm Inc. ● とあるマイクロサービスに対して実践したところ、大幅に効果があった Before 実践事例の紹介 39

Slide 40

Slide 40 text

Copyright © 2022 RevComm Inc. ● とあるマイクロサービスに対して実践したところ、大幅に効果があった Before 実践事例の紹介 40 ①slim イメージを使っていない ②アプリケーション起動が root ユーザー

Slide 41

Slide 41 text

Copyright © 2022 RevComm Inc. After 実践事例の紹介 41 ①slim イメージを使用するように変更。 builder ステージでライブラリをでインストール・ビルドし、 runner ステージで利用。 ①一般ユーザーでアプリケーションを起動するように変更。 ※80番ポートを起動できないためポート番号も変更。

Slide 42

Slide 42 text

Copyright © 2022 RevComm Inc. ● 開発利便性と軽量性/セキュリティ は両立できる(相反する性質ではない) ● なるべく slim イメージを使用しましょう ● マルチステージビルドを活用することで「アプリケーションに必要十分な環境」が作りやすくなる ○ 開発 / 本番用イメージを同一 Dockerfile で管理できる(DRY 原則を保てる) ※必要に応じて Dockerfile を分離して可読性を維持する(要はバランス) リンク ● サンプルコード: GitHub revcomm/public-slide-docker-multistage-build-for-python ○ dev コンテナ: ユニットテスト実行 ○ prod コンテナ:アプリケーション起動、動作確認 ● 仕事でPythonコンテナをデプロイする人向けのDockerfile (1): オールマイティ編 | フューチャー技術ブログ ● 軽量Dockerイメージに安易にAlpineを使うのはやめたほうがいいという話 - inductor's blog まとめ 42

Slide 43

Slide 43 text

Copyright © 2022 RevComm Inc. Have a good container life! 43