pythonのバッチ用のイメージを作りたくなったのでサイズがどれくらいになるか調べてみた
これはかなり個人的なメモ。
コンテナ経由でpythonで作ったバッチを実行しようと思った。そしてイメージのサイズがどれくらいかを大まかに知りたくなった。そんなわけで調べてみた。
サイズを極限まで絞りたいと言う気持ちはなかったのでdistrolessなどは省略。素直にDebianベースのイメージを選んだ。
作成する環境のメモ
baseとなるイメージは python:3.8-slim にしてみた。
$ docker images python:3.8-slim REPOSITORY TAG IMAGE ID CREATED SIZE python 3.8-slim 13172ea67a56 7 days ago 118MB
これに以下のパッケージを追加しただけの状態。
- pandas
- boto3
どういう物を作りたいか雰囲気は察せられそう。
imageのサイズ
先に作ったimageの概略を書いておく。以下のようなサイズになっていた。
REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
---|---|---|---|---|
foo | 0.1.0 | 813317bd2068 | 5 days ago | 291MB |
foo | 0.0.0 | 883eb7b407c1 | 5 days ago | 320MB |
foo 0.0.0が何も考えずに作ったシンプルなイメージ。foo 0.1.0 がマルチステージビルドで頑張ったイメージ
0.0.0
最もシンプルなDockerfileを考えてみる。何も考えずに書いた感じ。
Dockerfile
FROM python:3.8-slim RUN python3 -m pip install pandas boto3 CMD ["python3"]
dockerでbuildしてみる。
docker build -t foo:0.0.1 .
0.1.0
0.1.0はマルチステージビルドで頑張ったもの。以下の記事の内容を省略したもの。
Dockerfile.multi
FROM python:3.8-slim as builder WORKDIR /opt/app COPY requirements.lock /opt/app RUN python3 -m pip install -r requirements.lock FROM python:3.8-slim as runner COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages #COPY --from=builder /usr/local/bin/boto /usr/local/bin/boto CMD ["python3"]
(コメントしているコピーの行は何かconsole_scriptsなどでコマンドをインストールしたときのためのもの) (今見るとWORKDIRを指定する意味がこのDockerfileでは一切無い)
その他細々と思ったことがあるが省略1。
こちらもdockerでビルド
$ docker build -t 0.1.0 -f Dockerfile.multi
requirements.lock
boto3==1.17.12 botocore==1.20.12 jmespath==0.10.0 numpy==1.20.1 pandas==1.2.2 python-dateutil==2.8.1 pytz==2021.1 s3transfer==0.3.4 six==1.15.0 urllib3==1.26.3
どのレイヤーでどれだけ使われているかを見てみる
docker history
でどのレイヤーがどれだけ使っているか分かる。ちなみに、--no-trunc
をつけると省略される部分の全文が見れる。foo:0.0.0の方で見ていると、pipでインストールした時点で200Mb程度使われるようだ。それしかしていないのでそれはそう。
$ docker history foo:0.0.0 --format '{{.ID}}\t{{.CreatedSince}}\t{{.Size}}\t{{.CreatedBy}}' 883eb7b407c1 5 days ago 0B /bin/sh -c #(nop) CMD ["python3"] faca00f27605 5 days ago 202MB /bin/sh -c python3 -m pip install boto3 pand… # ここからはbaseのimageのhistory 13172ea67a56 7 days ago 0B /bin/sh -c #(nop) CMD ["python3"] <missing> 7 days ago 9.19MB /bin/sh -c set -ex; savedAptMark="$(apt-ma… <missing> 7 days ago 0B /bin/sh -c #(nop) ENV PYTHON_GET_PIP_SHA256… <missing> 7 days ago 0B /bin/sh -c #(nop) ENV PYTHON_GET_PIP_URL=ht… <missing> 7 days ago 0B /bin/sh -c #(nop) ENV PYTHON_PIP_VERSION=21… <missing> 7 days ago 32B /bin/sh -c cd /usr/local/bin && ln -s idle3… <missing> 7 days ago 32.4MB /bin/sh -c set -ex && savedAptMark="$(apt-… <missing> 7 days ago 0B /bin/sh -c #(nop) ENV PYTHON_VERSION=3.8.8 <missing> 2 weeks ago 0B /bin/sh -c #(nop) ENV GPG_KEY=E3FF2839C048B… <missing> 2 weeks ago 7.06MB /bin/sh -c set -eux; apt-get update; apt-g… <missing> 2 weeks ago 0B /bin/sh -c #(nop) ENV LANG=C.UTF-8 <missing> 2 weeks ago 0B /bin/sh -c #(nop) ENV PATH=/usr/local/bin:/… <missing> 2 weeks ago 0B /bin/sh -c #(nop) CMD ["bash"] <missing> 2 weeks ago 69.2MB /bin/sh -c #(nop) ADD file:d5c41bfaf15180481…
マルチステージビルドをした方の0.1.0も、表示としてはほぼほぼ同様の形になる。こちらはCOPYの行が主。諸々のインストールなどはbuilderの方で動いているので。
$ docker history foo:0.1.0 --format '{{.ID}}\t{{.CreatedSince}}\t{{.Size}}\t{{.CreatedBy}}' 813317bd2068 5 days ago 0B /bin/sh -c #(nop) CMD ["python3"] 20e64f9d4a80 5 days ago 173MB /bin/sh -c #(nop) COPY dir:181eb1f8c5a0da2a6… # base imageの方は省略 13172ea67a56 7 days ago 0B /bin/sh -c #(nop) CMD ["python3"] ...
ほぼpip installでイメージのサイズが倍に
わかったのは、pandasとboto3を入れた瞬間にほぼbase imageの倍のサイズになるということ。alpine2やdistrolessを検討する意味はほぼ無い。
考えてみれば、site-packages以下をduなどで覗いてみれば分かることではあった。すべての依存を見ていないが、botocoreとpandasで100Mを超える。
$ du -sh ~/my/lib/python3.8/site-packages/boto 10M $VIRTUAL_ENV/lib/python3.8/site-packages/boto $ du -sh ~/my/lib/python3.8/site-packages/botocore 41M $VIRTUAL_ENV/lib/python3.8/site-packages/botocore $ du -sh ~/my/lib/python3.8/site-packages/boto3 1.3M $VIRTUAL_ENV/lib/python3.8/site-packages/boto3 $ du -sh ~/my/lib/python3.8/site-packages/pandas 63M $VIRTUAL_ENV/lib/python3.8/site-packages/pandas
追記
pipだけが差分なら pip install --no-cache-dir
でインストールすれば十分では?3
0.0.1がそれ(ioknife4は表示を見やすくするためだけのものなので忘れてしまっても良い)。
$ docker images | ioknife rest | ggrep -P 'foo' REPOSITORY TAG IMAGE ID CREATED SIZE foo 0.0.1 de0f50ba0477 9 seconds ago 286MB foo 0.1.0 813317bd2068 5 days ago 291MB foo 0.0.0 883eb7b407c1 5 days ago 320MB # ここでもう一度base image $ docker images python:3.8-slim REPOSITORY TAG IMAGE ID CREATED SIZE python 3.8-slim 13172ea67a56 7 days ago 118MB
はい。
補足
:warning: tzの設定やaptのupdateとか諸々やれていないので、この記事のDockerfileをそのまま使うことはオススメしない。
参考
このあたりの情報がとても助かった。
- https://future-architect.github.io/articles/20200513/
- https://future-architect.github.io/articles/20200514/
公式
- https://hub.docker.com/_/python
- https://docs.docker.com/develop/develop-images/multistage-build/
- https://docs.docker.com/engine/reference/commandline/history/
記事では使っていないけれど、実際にDockerfileを書くときには便利。
- https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
- https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image