LoginSignup
22
14

More than 1 year has passed since last update.

シンプルなPython3.9のDocker環境をマルチステージビルドしてスリムにする

Posted at

はじめに

MIERUNEアドベントカレンダー22日目です!

いよいよ終盤ですね!

今回はDockerのマルチステージビルドについてやっていきます!

いやいやGIS関係ないんかい!と思う方もいるかもしれませんが、そんなことはありません!

GISに関わるプログラミングをするときにPythonはもはや必須ですし、WebGISをやっていく上でDockerも必須です。
なのでまぁDockerの話題はほぼGISですね。

ということで早速やっていきましょう!

作成するファイルはこちらに置いていますので、せっかちな方はご利用ください。
https://github.com/nokonoko1203/minimize-docker-image

必要なファイルを作成する

まずは適当にディレクトリを作成しましょう!

mkdir minimize-docker-image
cd minimize-docker-image

次に適当なPipfileを作成して書き込みます。
Pythonのバージョンはなんでも良いですが、今回はpython3.9のdockerイメージを利用するので、3.9系を指定しました。
マイクロバージョンはほんとになんでも良いです。

touch Pipfile
  • Pipfile
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
autopep8 = "*"
flake8 = "*"
isort = "*"
mypy = "*"

[packages]
requests = "==2.24.0"

[requires]
python_version = "3.9.9"

作成したPipfileを利用してlockファイルを作ります。

pipenv lock

最後にDockerfileを作成しましょう。

  • Dockerfile
FROM python:3.9-buster

ENV PYTHONUNBUFFERED=1

RUN mkdir app

WORKDIR /app

COPY Pipfile.lock /app/

RUN pip install -U pip && \
    pip install pipenv==2021.5.29 && \
    pipenv sync --system && \
    pip uninstall --yes pipenv

これだけでPythonの実行環境が概ね完成しました!
Dockerってすごいですね!

イメージを作成して起動してみる

作成したDockerfileを利用してDockerイメージを作成しましょう!
python-sampleのところは作成したいイメージ名を指定しますので、任意で構いません。

docker image build . -t python-sample

Dockerイメージからコンテナを起動してPythonのパッケージがインストールされているか確認してみましょう!

% docker container run --rm python-sample pip list
Package                           Version
--------------------------------- ---------
backports.entry-points-selectable 1.1.1
certifi                           2021.10.8
chardet                           3.0.4
distlib                           0.3.4
filelock                          3.4.0
idna                              2.10
pip                               21.3.1
platformdirs                      2.4.0
requests                          2.24.0
setuptools                        57.5.0
six                               1.16.0
urllib3                           1.25.11
virtualenv                        20.10.0
virtualenv-clone                  0.5.7
wheel                             0.37.0

Pythonもちゃんと入っていそうです。

% docker container run --rm python-sample python -V
Python 3.9.9

Dockerイメージをスリムにする

先程作成したDockerイメージのサイズを確認してみましょう。

% docker image ls | grep python-sample
python-sample  latest  abd1e5ec8c95  15 minutes ago  945MB

dockerイメージの容量は比較的大きめ(945MB)です。

基本的な原則として、イメージサイズが大きいと良いことは少ないです。

イメージのビルドに時間がかかる上、SSDを圧迫します。

配布する際にはアップロードにもダウンロードにも時間がかかってしまいますね。

なので、特に理由がなければコンパクトにするのが望ましいです。

ということでDockerfileを編集してイメージサイズを下げていきましょう!

Dockerfileを改修して軽量なイメージを利用する

Dockerfileを以下のように修正します。

FROM python:3.9-slim-buster

ENV PYTHONUNBUFFERED=1

RUN mkdir app

WORKDIR /app

COPY Pipfile.lock /app/

RUN pip install -U pip && \
    pip install pipenv==2021.5.29 && \
    pipenv sync --system && \
    pip uninstall --yes pipenv

利用するイメージをpython:3.9-busterからpython:3.9-slim-busterに変更してみました。
このままイメージをビルドしてみましょう。

docker image build . -t python-sample-minimize

動作確認

% docker container run --rm python-sample-minimize pip list
Package                           Version
--------------------------------- ---------
backports.entry-points-selectable 1.1.1
certifi                           2021.10.8
chardet                           3.0.4
distlib                           0.3.4
filelock                          3.4.0
idna                              2.10
pip                               21.3.1
platformdirs                      2.4.0
requests                          2.24.0
setuptools                        57.5.0
six                               1.16.0
urllib3                           1.25.11
virtualenv                        20.10.0
virtualenv-clone                  0.5.7
wheel                             0.37.0

そのままイメージサイズを確認してみます。

% docker image ls | grep python-sample             
python-sample-minimize  latest  733101d08d8f  12 seconds ago  174MB
python-sample  latest  abd1e5ec8c95  4 hours ago  945MB

!!!

なんとびっくりイメージサイズが1/5以下に!!!!!

というのは当たり前で…

python:3.9-buster: よく利用される(Python以外の)ツールなどもてんこ盛りでプリインストールされている便利なイメージ
python:3.9-slim-buster: 利用頻度の低いツールを削ぎ落とした軽量イメージ

です。

ツールがあまりインストールされていないので、当然イメージサイズも小さい、ということになります。

今回は特に問題ないので利用しましたが、slim-busterを利用する際には自分の必要とするツールがプリインストールされているのかどうかよく確認してから利用する必要があります。

また、運用中のコンテナをbusterからslim-busterへ移行する場合にはより一層注意が必要です。

さらなる軽量化を目指す

ということで、(利用したいツールが全て揃っているのであれば)slim-busterを利用するだけでだいぶイメージサイズを軽量化できることがわかりましたが、今回はもう少し攻めてみましょう。

Dockerfileを以下のように修正します。

FROM python:3.9-buster as builder

ENV PYTHONUNBUFFERED=1

RUN mkdir app

WORKDIR /app

COPY Pipfile.lock /app/

RUN pip install -U pip && \
    pip install pipenv==2021.5.29 && \
    pipenv sync --system && \
    pip uninstall --yes pipenv

FROM python:3.9-slim-buster as production

ENV PYTHONUNBUFFERED=1

RUN mkdir app

WORKDIR /app

COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages/
COPY --from=builder /app /app/

Dockerfileの中にFROMが2回出てくるのが見慣れないという方もいるかもしれませんね。

これはマルチステージビルドといって、FROM文を複数使い、各ステージにbuilder・productionのような名前をつけて段階的にビルドしていくことです。

今回の例では、まずbuilderステージでpython:3.9-busterを利用し、pipからのライブラリのインストールなどを完了させます。
その後、python:3.9-slim-busterを利用したproductionステージで、builderステージでインストールしたライブラリが格納されたディレクトリごとコピーしてきています。

こうすることでpipやpipenvなど、アプリケーションの実行に不要なファイルを除外することができます。
では実際にイメージをビルドしてみましょう。

% docker image build . -t python-sample-minimize

その後、イメージサイズを確認してみましょう。

% docker image ls | grep python-sample-minimize
python-sample-minimize  latest  f9ab98960d48  32 seconds ago  138MB

174MBから138MBまで減らすことができました!

終わりに

複雑な依存関係をもたず、簡単なスクリプト実行のためにDockerを利用するのであれば、案外サクッとイメージサイズを下げることができます。

今回はマルチステージ前後で40MB程度しか減りませんでしたが、実行ファイルをビルドする必要があったり、Next.jsを利用して静的ファイルを吐き出す際の利用など、「ビルド時には多くのライブラリが必要だが、アプリケーションの実行にはほとんど依存関係が必要ない」場合にはものすごい効果を発揮します。

皆さんもどんどん利用していきましょう!

22
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
14