2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

この記事では既存のコンテナイメージをdistrolessイメージを使って改善していく記事です。
主な内容としては実践したときのメモを中心に書きます。
(忘れやすいことなど)誤りなどがあれば書き直していく予定です。

今回利用したソースコードは以下のリポジトリにあります。

distroless_docker_image GitHub

※のちほど、finchを使った記事も挙げます。

環境

今回は以下の環境で動作確認を行っています。そのほかの環境で動かす場合の参考にしてください。

  • MacBook
    • Apple Sillicon M1
    • Sonoma 14.0
  • Rancher Desktop
    • v1.7.0
  • Python
    • Python 3.9

※まずは、Rancher Desktopをインストールしてください。
※Python3.9と記載していますが、dockerイメージにおけるPythonです。

既存のコンテナイメージ

今回改善するイメージは以下です。

FROM python:3.9-alpine as builder

RUN apk add --no-cache musl-dev mysql-dev gcc
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir --upgrade pip && pip install --no-cache-dir -r requirements.txt

CMD ["python", "main.py"]

imageを構築する過程でpipを実行しています。pipでインストールするパッケージは以下のとおりです。

requirements.txt
alembic==1.13.1
annotated-types==0.6.0
boto3==1.4.8
botocore==1.8.11
certifi==2023.11.17
charset-normalizer==3.3.2
docutils==0.14
exceptiongroup==1.2.0
functions==0.7.0
greenlet==3.0.3
idna==3.6
iniconfig==2.0.0
jmespath==0.9.3
Mako==1.3.0
MarkupSafe==2.1.3
mysqlclient==2.2.1
packaging==23.2
pluggy==1.3.0
pydantic==2.5.3
pydantic_core==2.14.6
pytest==7.4.4
python-dateutil==2.6.1
python-multipart==0.0.6
pytz==2023.3.post1
requests==2.31.0
s3transfer==0.1.12
schemas==0.7.1
six==1.11.0
SQLAlchemy==2.0.25
SQLAlchemy-Utils==0.41.1
tomli==2.0.1
typing_extensions==4.9.0
urllib3==2.1.0
xmltodict==0.13.0

なお、mysqlclientをインストールしているため、apkでmysql-devをインストールしています。
イメージをビルドします。

docker build -t test_alpine:1 .

サイズを確認するため、docker imagesを実行します。

docker images

実行結果は以下のとおりです。

REPOSITORY                           TAG          IMAGE ID       CREATED         SIZE
test_alpine                          1            374875ee50bb   8 seconds ago   333MB

サイズは333MBです。このコンテナイメージをdistrolessイメージに置き換えていきます。

distrolessイメージを使って改善していく

まずはどんな感じのdockerfileになるかを確認します。

FROM python:3.9-alpine as builder

WORKDIR /app
COPY . .
RUN pip --no-cache-dir install --upgrade pip && pip install --no-cache-dir --target site-packages -r requirements.txt

FROM gcr.io/distroless/python3-debian11:nonroot

WORKDIR /app
COPY --from=builder /app .
ENV PYTHONPATH=/app/site-packages
CMD ["./main.py"]

なお、requirements.txtは以下のとおりです。変更点としてはmysqlclientを削除して代わりにmysql-connector-python==8.2.0をインストールしています。

requirements.txt
alembic==1.13.1
annotated-types==0.6.0
boto3==1.4.8
botocore==1.8.11
certifi==2023.11.17
charset-normalizer==3.3.2
docutils==0.14
exceptiongroup==1.2.0
functions==0.7.0
greenlet==3.0.3
idna==3.6
iniconfig==2.0.0
jmespath==0.9.3
Mako==1.3.0
MarkupSafe==2.1.3
# mysqlclient==2.2.1
packaging==23.2
pluggy==1.3.0
pydantic==2.5.3
pydantic_core==2.14.6
pytest==7.4.4
python-dateutil==2.6.1
python-multipart==0.0.6
pytz==2023.3.post1
requests==2.31.0
s3transfer==0.1.12
schemas==0.7.1
six==1.11.0
SQLAlchemy==2.0.25
SQLAlchemy-Utils==0.41.1
tomli==2.0.1
typing_extensions==4.9.0
urllib3==2.1.0
xmltodict==0.13.0
mysql-connector-python==8.2.0

イメージをビルドします。

docker build -t test_distroless:1 .

サイズを確認するため、docker imagesを実行します。

docker images

実行結果は以下のとおりです。

REPOSITORY                           TAG          IMAGE ID       CREATED         SIZE
test_alpine                          1            374875ee50bb   8 seconds ago   333MB
test_distroless                      1            e6ee09fc6a8e   2 minutes ago   132MB

サイズは132MBです。distrolessイメージを使うことでほぼ同じPythonのパッケージを使いつつ、イメージサイズを大幅に削減できました。

distrolessイメージを作るときのポイント

イメージサイズを削減できたところでdistrolessイメージを作るときのポイントを確認します。
主に以下のポイントです。

  • マルチステージビルドを使う
  • その他のパッケージに依存したパッケージをインストールしないもしくは代わりを用意する

それぞれ見ていきましょう。

マルチステージビルドを使う

dockerにはマルチステージビルドという機能があります。マルチステージビルドとは複数のFROMを使ってイメージを構築する機能です。

以下のようなメリットがあります。

  • 他のイメージから取得したものをコピー
  • 保存されているビルドイメージ(ビルドキャッシュ)から必要なものをコピーすることでビルドの高速化
    • パッケージインストール時に発生するダウンロード時間をより短くできる

ただし、以下のようなデメリットもあります。

  • 特定のビルドイメージに依存する形になってしまう
  • ビルドイメージを保存するため、保存データ容量が大きくなる

また、昨今においてはさまざまなアーキテクチャで開発を行うことが多くなってきているため
ビルドイメージを取得する際にアーキテクチャによってビルドイメージが異なることがあります。

ビルドイメージの構築はCI/CDなどを構築してクラウド上でやるのが良いでしょう。

その他のパッケージに依存したパッケージをインストールしない

distrolessイメージを使うときには、その他のパッケージに依存したパッケージをインストールしないようにする必要があります。

今回の場合はmysqlclientをインストールしているためにmysql-devもインストールしていますが。
distrolessイメージを使うときにはmysqlclientをインストールしないようにする必要があります。
そのため、mysqlclientを削除してmysql-connector-pythonをインストールしています。

mysqlclientをインストールする場合は依存しているapkのパッケージをインストールする必要がありますが
distrolessイメージにはシェルとパッケージシステムが存在しないため、パッケージをインストールできません。

つまり、distrolessイメージを使うときにはその他のパッケージに依存したパッケージをインストールしないようにするかもしくは代わりとなるパッケージを用意する必要があります。

ちなみにmysqlclientをインストールしようとするとpkg-configが正常に動作せず、インストールに失敗します。

まとめ

今回は既存のコンテナイメージをdistrolessイメージを使って改善しました。
distrolessイメージを使うことでイメージサイズを大幅に削減できるため、使えるところでは使っていきたいです。

ただし、マルチステージビルドを使う必要があり、ビルドイメージをいくつか保存する必要があるためビルドイメージの運用には注意が必要です。

イメージをビルドする際はクラウドベースのビルド環境を構築しておきましょう。

2
2
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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?