背景
今年もDBマイグレーションするのに Flywayコンテナ のお世話になりましたが、公式イメージはとてもサイズが大きいです。
$ docker pull flyway/flyway:11.19.0
$ docker images flyway/flyway:11.19.0
REPOSITORY TAG IMAGE ID CREATED SIZE
flyway/flyway 11.19.0 e69c5298d0c7 5 days ago 591MB
というのも、Flyway公式イメージには多くのデータベースに対するJDBC Driverが標準で同梱されており、これらが容量を消費しているからです。なんと、/flyway 全体の約90%が /flyway/drivers ディレクトリに占められています…
$ docker run --rm -it --entrypoint=sh flyway/flyway:11.19.0
# du -h -d 1 /flyway
239M /flyway/drivers
8.0K /flyway/conf
27M /flyway/lib
1.2M /flyway/licenses
267M /flyway
# ls -lFh /flyway/drivers # databricks-jdbcとかsnowflake-jdbcとかサイズ感がおかしいよ
total 143M
drwxr-xr-x 2 root root 4.0K Dec 8 11:00 aws/
drwxr-xr-x 2 root root 4.0K Dec 8 11:00 cassandra/
drwxr-xr-x 2 root root 4.0K Dec 8 11:00 couchbase/
-rw-r--r-- 1 1001 1001 35M Oct 13 14:34 databricks-jdbc-3.0.1.jar
drwxr-xr-x 2 root root 4.0K Dec 8 11:00 gcp/
-rw-r--r-- 1 1001 1001 1.1M Sep 26 2024 google-cloud-storage-2.43.1.jar
-rw-r--r-- 1 1001 1001 2.6M Aug 12 2024 h2-2.3.232.jar
-rw-r--r-- 1 1001 1001 1.6M May 31 2023 hsqldb-2.7.2.jar
-rw-r--r-- 1 1001 1001 1.2M Jan 17 2021 jaybird-jdk18-3.0.10.jar
-rw-r--r-- 1 1001 1001 153K Nov 10 2022 jffi-1.3.10.jar
-rw-r--r-- 1 1001 1001 943K Nov 10 2022 jffi-1.3.10-native.jar
-rw-r--r-- 1 1001 1001 311K Jun 8 2013 jtds-1.3.1.jar
-rw-r--r-- 1 1001 1001 613K Nov 7 2023 mariadb-java-client-2.7.11.jar
drwxr-xr-x 2 root root 4.0K Dec 8 11:00 mongo/
-rw-r--r-- 1 1001 1001 1.2M Oct 13 18:26 mssql-jdbc-12.10.2.jre11.jar
-rw-r--r-- 1 1001 1001 5.1M May 28 2025 ojdbc11-21.18.0.0.jar
-rw-r--r-- 1 1001 1001 1.1M Feb 20 2024 postgresql-42.7.2.jar
-rw-r--r-- 1 1001 1001 0 Dec 8 10:36 put-your-jdbc-drivers-here.txt
-rw-r--r-- 1 1001 1001 546K Jul 26 2022 singlestore-jdbc-client-1.1.4.jar
-rw-r--r-- 1 1001 1001 79M Oct 6 17:14 snowflake-jdbc-3.27.0.jar
-rw-r--r-- 1 1001 1001 14M Jul 21 04:18 sqlite-jdbc-3.50.3.0.jar
私のユースケースでは、PostgreSQLにだけ接続できれば十分なので、同梱するJDBCドライバを取捨選択することで、Flywayイメージを小さくする方法を検討したいと思います。
確認環境
- Flyway 11.19.0
- PostgreSQL 16.11
- Docker 27.3.1
- macOS 15.6.1
解決方法
コンテナイメージのサイズを小さくするといえばお決まりの方法ですが、マルチステージビルドを使って、最終イメージには必要なJDBCドライバだけを含めるようにします。
Eclipse Temurin 21 を採用しているのは、公式イメージのDockerfile になるべく合わせているからで、それ以上の理由はないです。
FROM flyway/flyway:11.19.0 AS base
# driversディレクトリを一時的に退避して、必要なJDBCドライバだけ元に戻す
RUN mv /flyway/drivers /tmp/drivers \
&& mkdir /flyway/drivers \
&& mv /tmp/drivers/postgresql-*.jar /flyway/drivers/
FROM eclipse-temurin:21-jre-noble AS flyway
WORKDIR /flyway
COPY --from=base /flyway /flyway
ENV PATH="/flyway:${PATH}"
ENTRYPOINT ["flyway"]
CMD ["-?"]
$ docker build -t flyway-custom .
$ docker images | grep flyway
flyway-custom latest 6bc2eef0f4c3 5 seconds ago 342MB
flyway/flyway 11.19.0 e69c5298d0c7 5 days ago 591MB
250MBぐらい小さくなりましたね ![]()
ダメ案
マルチステージビルドを使わずに、公式イメージから不要なJDBCドライバを削除するだけで済めばDockerfileのメンテもしやすくて楽なのですが、この方法ではイメージサイズは減りません。
FROM flyway/flyway:11.19.0
RUN mv /flyway/drivers /tmp/drivers \
&& mkdir /flyway/drivers \
&& mv /tmp/drivers/postgresql-*.jar /flyway/drivers/ \
&& rm -rf /tmp/drivers
$ docker build -t flyway-ng .
$ docker images | grep flyway
flyway-ng latest b03f1747d47d 45 seconds ago 592MB
flyway/flyway 11.19.0 e69c5298d0c7 5 days ago 591MB
Dockerのイメージレイヤーは読み取り専用で積み重なっていくため、一度追加されたファイルは、後続レイヤーで削除しても元のレイヤーからは消えないからです。
例えば、コンテナイメージをファイルに出力してみて、blobs ディレクトリ以下を探すと、すべての /flyway/drivers/*.jar を含むレイヤーが存在することを確認できます。
$ docker image save flyway-ng -o image.tar
$ mkdir image
$ tar xvf image.tar -C image
$ ls -l image/blobs/sha256/ # レイヤーの分だけファイルが作られているのがわかる
total 1165840
-rw-r--r-- 1 oohira wheel 1093120 12 14 12:24 06cffdd31a20717ff6ddde78bb6c0548e26866c93e79ca1abd1df0b470496385
-rw-r--r-- 1 oohira wheel 279600128 12 14 12:24 46a033c8abf9a6da2d934120e3ce49222bb5aac6aa4961b12eaa5cea54c085f0
-rw-r--r-- 1 oohira wheel 1855 12 14 12:24 5af97ed168eb4924b0ee39c94890cc2c6e0373f147137b98b2f04d7149a19916
-rw-r--r-- 1 oohira wheel 7168 12 14 12:24 5c41ef53b2b36a5ce40cd0f8bab06e9a4af40feeb2907de351163a5072277364
-rw-r--r-- 1 oohira wheel 2560 12 14 12:24 5d73a960e67b6a1c4d248278c8fa8963803080059a06d2b2088db5c015b87149
-rw-r--r-- 1 oohira wheel 482 12 14 12:24 62673c02c88f0334de9165054c6c5ac0a007675df5e83d92fb04a67e67501312
-rw-r--r-- 1 oohira wheel 165083648 12 14 12:24 65cf014d89ad72542e406b2f1ea4baf1329a4dca828e679687a943866705ccf4
...
$ tar tvf image/blobs/sha256/46a033c8abf9a6da2d934120e3ce49222bb5aac6aa4961b12eaa5cea54c085f0
drwxr-xr-x 0 0 0 0 12 8 20:00 flyway/
-rw-r--r-- 0 1001 1001 1121 12 8 19:36 flyway/README.txt
drwxr-xr-x 0 0 0 0 12 8 20:00 flyway/conf/
-rw-r--r-- 0 1001 1001 743 12 8 19:36 flyway/conf/flyway.toml.example
drwxr-xr-x 0 0 0 0 12 8 20:00 flyway/drivers/
drwxr-xr-x 0 0 0 0 12 8 20:00 flyway/drivers/aws/
-rw-r--r-- 0 0 0 9312307 12 8 19:43 flyway/drivers/aws/aws-secretsmanager-jdbc-2.0.3-shaded.jar
drwxr-xr-x 0 0 0 0 12 8 20:00 flyway/drivers/cassandra/
-rw-r--r-- 0 1001 1001 173763 12 10 2019 flyway/drivers/cassandra/HdrHistogram-2.1.12.jar
-rw-r--r-- 0 1001 1001 122004 6 26 2021 flyway/drivers/cassandra/asm-9.2.jar
...
補足
- Flyway公式のDockerfileへの追従が漏れるリスクあり
- Flywayのディレクトリ構成が大きく変わると、単にベースイメージ
flyway/flywayのバージョン番号を変えるだけでは変更に追従できなくなる可能性があります。Flywayの起動自体がエラーになるような場合は気付きやすいと思いますが、特定のロジックを通ったときだけ実行時エラーになるといった場合は気付きにくいので、注意が必要です
- Flywayのディレクトリ構成が大きく変わると、単にベースイメージ
- jlink や distroless を使えばJavaのランタイム分も軽量化できるのでは
- できるかもしれませんが、個人的にはそこまでのモチベーションはありません。Javaベースのコンテナを使う時点でイメージサイズや起動オーバーヘッドの削減には限界があるので、可読性や変更容易性を犠牲にしてまでギリギリまでイメージサイズを削りたいというニーズがないためです。この記事の方法も、保守性を考えれば微妙なラインですが、さすがにJDBCドライバの消費分は無駄なので、許容できると判断しました。なお、Flywayのエントリポイントはシェルスクリプトなので、distroless対応を試みる場合はシェルを使わない仕組みへの置き換えが必要です(試していない)
まとめ
この記事では、マルチステージビルドを使って、Flywayの公式イメージからPostgreSQLのJDBCドライバだけを含む軽量なイメージを作る方法を紹介しました。PostgreSQL以外のJDBCドライバでも流用できる方法だと思うので、誰かの参考になればさいわいです。