始めに
先日の記事にて、FastAPIのイメージが1GBになってしまった件を書きました。何か対策できないかと調査していく中で、gzip
ではなく、zstd
で圧縮することで高い圧縮率と高い解凍速度を達成できることを知りました。
今回の記事ではzstd
でDockerイメージの圧縮をします。
環境
- Docker Engine
- Docker Buildx
zstd圧縮を使用するためには、次のバージョンが必要です。
- Docker Engine
- Docker Buildx
# バージョン確認用コマンド
docker version
docker buildx version
実装
確実に目的のバージョン(最新バージョン)でビルドするために、ビルダーインスタンスを作成します。
次に、docker buildx
のoutput
オプションに必要なオプションを付与すると、zstd
で圧縮できます。
docker buildx create --name builder --use --platform linux/amd64
docker buildx build --builder builder -t kirimaru/xxx:zstd --output type=image,oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true,push=true .
# 実際に使用しているコマンド
# docker buildx build --builder builder --target dev_runtime -t kirimaru/fastapi-practice_dev-runtime:$RUNTIME_TAG --output type=image,oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true,push=true .
次のコマンドでgzip
で圧縮されていないことを確認しました。
# gzipで圧縮していた時のイメージ
docker buildx imagetools inspect --raw kirimaru/fastapi-practice_dev-runtime:python-1c86b7b0d3465cb68c6c3c6e1b256137ef6af039
# 該当箇所の抜粋
# "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip"
# zstdで圧縮したときのイメージ
# ※ マルチステージビルドだと、マニフェストのdigest値まで指定する必要があります
docker buildx imagetools inspect --raw kirimaru/fastapi-practice_dev-runtime:python-97df63af48201968a20c804cdb84e10765e68ee7@sha256:00b9a175bfb82fcd9f3b018e1d726d1a118c7d7357fe0649df1ad73d372222e4
# "mediaType": "application/vnd.oci.image.layer.v1.tar+zstd"
各オプション解説
--builder builder
特定のビルダーインスタンス(今回はbuilder)を使用するという指定です。
-t kirimaru/xxx:zstd
ビルド時のイメージにタグを付与します。詳細は後述しますが、zstd
で圧縮する際には必須級です。
--output オプション
- type=image
- 出力タイプをイメージとして指定します。指定は必須です
- oci-mediatypes=true
- OCI(Open Container Initiative)メディアタイプを使用します
- compression=zstd
- compression-level=3
- zstd圧縮のレベルを3に設定します。(1-22の範囲、低いほど高速で圧縮率は低下しますが、3がバランスが取れているようです)
- force-compression=true
- push=true
ハマったポイント
リモートリポジトリにイメージをpushする際にzstdで圧縮するようで、ローカルで一度ビルドしてからタグを付与しなおしてpushするということはできませんでした。そのため、-t
とpush=true
でビルドしながらpushしています。
他の細かい失敗は次に記載しています。
- bakeではうまくzstdで圧縮できなかった
- おそらく、pushオプションを付与すれば大丈夫だろうが未検証
- --type=imagesだとビルドキャッシュだけに残るようで、イメージ化されなかった。かといって、--loadを付与して明示的にimage化したらgzipになった
- --type=dockerにすれば問題なさそうだったが、こちらはgzipで圧縮された
ソースコード
なし
終わりに
ローカルでzstd
の最大圧縮レベルの22を検証しようとしたらまったくイメージサイズが変わらなくてずっとハマってました。他のブログも参考にしたのですが、push=true
にしている理由等も特に記載がなかったので、完全に見落としでしたね。
参考情報