ENECHANGE Developer Blog

ENECHANGE開発者ブログ

PythonアプリのDockerイメージを6割ほど軽量化した手順と効果

CTO室の岩本 (iwamot) です。

この記事では、Dockerイメージの軽量化事例をご紹介します。

ざっくりまとめると、下記の手順で軽量化を進めました。

  1. diveを使ってレイヤを分析した
  2. ベースイメージをpythonからpython:slimに変えた
  3. 無駄なファイルを除外した

まず、背景から説明します。

背景

弊社では、自社開発のPythonアプリケーションをDockerイメージとしてビルドし、電力使用量の予測に使っています。

ここ1年、AWS Lambdaで運用していたのですが、下記の問題があるため、Amazon ECSおよびAWS Fargateへの移行を決めました。

移行を進めていて気になったのが、イメージの大きさでした。似たようなRuby on Railsアプリケーションより、約440MBも大きい状況です。

  • Pythonアプリケーション:771.31MB
  • Ruby on Railsアプリケーション:332.54MB(別件でECS/Fargateに移行したもの)

これを何らかの手段で軽量化できれば、下記の効果が得られるはずです。

そのため、軽量化に取り組むことにしました。

手順

1. diveを使ってレイヤを分析した

軽量化の方針を決めるのに有用なのが、diveというツールです。

github.com

diveを使うと下記の点が手早く把握できます。

  • どのレイヤでどんなファイルが追加されたか
  • 無駄なファイルが含まれていないか

対象のDockerイメージをdiveで分析したところ、下記の課題が把握できました。

  • ベースイメージのpython:3.10.10-bullseye自体が大きい
  • 機械学習モデルの訓練にのみ必要なファイルが、最終イメージに含まれている

2. ベースイメージをpythonからpython:slimに変えた

ベースイメージの大きさについては、もし軽量版のpython:3.10.10-slim-bullseyeに変えられれば、それだけで300MB弱の軽量化が見込めそうでした。

しかし軽量版には、dbm.ndbmのインポートでエラーになる問題がありました。対象のアプリケーションはdbm.ndbmに依存しているため、このままでは変えられません。

そこで報告したのが、下記のissueです。

github.com

報告から数日後、ありがたいことに修正してもらえ、ベースイメージを軽量版に変えることができました。

3. 無駄なファイルを除外した

機械学習モデルの訓練用ファイルが最終イメージに含まれていた点は、マルチステージビルドを活用できていないのが原因でした。

trainingステージを追加し、訓練が終わったら使用済みファイルを削除することで、最終イメージから除外しました。

効果

軽量化により得られた効果は、下記の通りです。

  • イメージサイズ:58.2%の削減 (771.31MB → 322.46MB)
  • Dockerレジストリの利用料金:58.2%の削減(Amazon ECRのストレージとデータ転送量が単純に減ったと仮定)
  • ECSタスクの起動時間:約20秒の短縮(タスクのステータスが「PENDING」から「ACTIVATING」に移るまでの実測値)
  • CodeBuildのビルド時間:約30秒の短縮(実測値)

ビルド時間の短縮は意図していませんでしたが、効果がありました。

まとめ

以上、Dockerイメージの軽量化事例をご紹介しました。

特にお伝えしたかったのは、下記の点です。

  • イメージの軽量化には、いろんなメリットがある
  • 軽量化にはdiveが便利
  • OSSの妙な挙動を見つけたら、積極的に報告しよう

今後は、タスクの起動時間をさらに短くできないか、zstd圧縮を試そうと思っています。

aws.amazon.com