🐳

LLMを活用してDockerfileを最適化し15%のサイズ削減を実現した話

2025/03/26に公開

3行まとめ

  • LLMを活用してDockerfileのリファクタリングを実施し、イメージサイズを15%削減(1.96GB → 1.75GB)
  • LLM登場前に書いたコードをLLMにリファクタさせるのは良い結果を生む。(最近これが楽しい)
  • slimイメージへの移行とパッケージ最適化により、ビルド時間とpull時間を改善

背景

長年運用しているDockerfileは複雑化していく傾向にあります。

リファクタリングはリグレッションのリスクがあり、手を出しづらいです。

最近、DevinによるDockerfileリファクタリングの成功事例を見て、自プロジェクトでも試してみることにしました。

最適化前の状態

まず、変更前のdocker imageのサイズを調べておきます。

docker images minedia-www-app
REPOSITORY        TAG       IMAGE ID       CREATED      SIZE
minedia-www-app   latest    7e88a3086cb9   4 days ago   1.96GB

2GBありました。

アプローチ

Devinにやってもらおうかと思いましたが、そもそもこんなDockerfileのリファクタだったらClineで十分だと思うのでClineでClaude sonnet 3.5(少し前に行ったので古い)で実行してみました。

プロンプトは、ラフに「Dockerfileをリファクタリングして。」という指示だけです。

LLMによる主要な変更点

1. ベースイメージの最適化

-FROM ruby:3.4.1
+FROM ruby:3.4.1-slim

必要最低限しか入っていない -slim をbase imageとして使うようになりました。

いままでも導入を検討していましたが、開発時にはツールが少なかったり、リグレッションが発生してしまうリスクがあるのであんまり導入に積極的に離れませんでしたがそこを踏み込んで変更してくれました。

2. 環境変数とパッケージインストールの効率化

-ENV LANG="C.UTF-8" TZ="UTC"
-
-RUN apt update -qq && DEBIAN_FRONTEND=noninteractive apt -yq dist-upgrade &&\
-  DEBIAN_FRONTEND=noninteractive apt install -yq\
-    build-essential\
-    default-mysql-client\
-    ffmpeg\
+
+ENV LANG="C.UTF-8" \
+    TZ="UTC" \
+    APP_HOME=/app \
+    LUA_LIB="/usr/lib/liblua5.1.so.0"
+
+# Install system dependencies
+RUN apt-get update -qq && \
+    DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -yq \
+    build-essential \
+    curl \
+    default-mysql-client \
+    ffmpeg \
     liblua5.1-0 \
-    pandoc &&\
-    apt clean &&\
-    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* &&\
+    pandoc \
+    imagemagick \
+    libmagickwand-dev && \
+    ln -s /usr/lib/`uname -m`-linux-gnu/liblua5.1.so.0 ${LUA_LIB} && \
+    # Install Node.js
+    curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
+    apt-get install -y nodejs && \
+    # Cleanup
+    apt-get clean && \
+    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
     truncate -s 0 /var/log/*log

今までは人間が見やすいようにするメンテナナンス性や、build cacheを使うためにステップごとに処理をある程度区切っていましたが
build layerを少なくするために1コマンドで色々行うように変更されました。

人間がメンテナンスしづらくはなりますが、LLM経由でメンテナンスできるならばこれで問題無いと思います。

ベースイメージのサイズ比較

サイズ削減の効果を調査するために、そもそもslimとそうでないイメージでどのくらいサイズの差があるのかを調べてみたら、5倍ちかく容量が違いました。

通常イメージ

docker images ruby:3.4.1
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
ruby         3.4.1     79e67c837851   5 weeks ago   1.01GB

Slimイメージ

docker images ruby:3.4.1-slim
REPOSITORY   TAG          IMAGE ID       CREATED       SIZE
ruby         3.4.1-slim   eb3ae63a0b49   8 weeks ago   219MB

最終的な成果

最適化の結果

項目 最適化前 最適化後 削減率
ベースイメージ 1.0GB 219MB 78.1%
アプリケーションイメージ 1.96GB 1.75GB 10.7%

ベースイメージの大幅な軽量化により、全体で約250MB(約15%)のサイズ削減に成功しました。
これによりビルド時間の短縮やコンテナのpull時間改善など、CI/CDパイプライン全体の効率化につながりました。

(余談)Docker Gordonでの試み

Docker Desktopに統合されたAI機能(Gordon)も試してみましたが、現時点では正常に動作しませんでした。

設定を有効化し、規約に同意しても機能が利用できない状態でした。

本番環境へのデプロイ時の注意

このDockerfileの最適化を行った後、入念なテストを経て本番にデプロイしました。

1つだけ問題が発生しました。AWS ECSのhealthcheckにて ps コマンドによるsidekiqプロセスの有無をチェックしてhealthyかどうかを判定していました。
slim imageにはpsコマンドすら入っていなかったので別のコマンドでチェックするようにtask definitionsを変更しました。

cat /proc/*/cmdline | tr '\0' ' ' | grep sidekiq || exit 1

まとめ

  • イメージサイズを15%削減(約250MB)できました。
    • すでにある程度はきれいにしているのでそんなに無駄は無いので70%も削る余地が無かったです。
    • ビルド時間の短縮とpull時間の改善
  • LLMを活用することで、従来は困難だった最適化作業を効率的に実施できた
株式会社マインディア テックブログ

Discussion