diveでDockerイメージのサイズ削減できるか確認する

はじめに

昨今、サプライチェーン攻撃の話題をよく目にする。ホストマシンに直接何かを入れるのは、本当に怖い時代になった。そのため基本的には開発環境は、いわゆるdevコンテナのようなものを自分で育てている。ただこのdevコンテナ用のイメージが徐々に肥大化してきた。開発ツール一式入れていることもあり、ある程度は仕方がないものの、できることならスリム化したい。そこで、このイメージのサイズを削減できるか確認する。

diveのインストール

このコマンドはDockerイメージやレイヤーの内容を探索し、Docker/OCIイメージのサイズを縮小する方法を見つける。

インストール手順

できる範囲(「付録: インストール元の検証について」を参照)での安全策を講じ、チェックサムを検証してインストールするためにスクリプトを書いた。

install.sh

set -e -x

curl -fOL "https://github.com/wagoodman/dive/releases/download/v0.13.1/dive_0.13.1_linux_arm64.deb"
curl -fOL "https://github.com/wagoodman/dive/releases/download/v0.13.1/dive_0.13.1_checksums.txt"

# checksums.txt の該当行を使って SHA256 を検証する。
# checksums.txt 自体に GPG 署名はないため、この検証が保証するのは
# 「ダウンロードしたファイルが GitHub 上のリリースアセットと一致すること」のみ。
# GitHub そのものやリリースパイプラインが侵害された場合には無効となる。
grep "dive_0.13.1_linux_arm64.deb" dive_0.13.1_checksums.txt | sha256sum -c -

sudo apt install ./dive_0.13.1_linux_arm64.deb

このスクリプトでパッケージをインストールした。

bash install.sh

イメージを解析する

CI=true を指定することでインタラクティブUIを使わずにテキストレポートを出力できる。

CI=true dive sximada/agentic/all:202605.dev1
Image Source: docker://sximada/agentic/all:202605.dev1
Extracting image from docker-engine... (this can take a while for large images)
Analyzing image...
  efficiency: 98.3495 %
  wastedBytes: 85862238 bytes (86 MB)
  userWastedPercent: 3.2159 %
Inefficient Files:
Count  Wasted Space  File Path
    2        7.4 MB  /usr/bin/perl
    5        4.0 MB  /var/cache/debconf/templates.dat
    5        3.9 MB  /var/cache/debconf/templates.dat-old
    2        3.3 MB  /usr/lib/aarch64-linux-gnu/libc.so.6
    8        2.1 MB  /var/lib/dpkg/status
    8        2.1 MB  /var/lib/dpkg/status-old
    2        1.7 MB  /usr/sbin/ldconfig
    7        1.5 MB  /var/log/dpkg.log
...
Results:
  PASS: highestUserWastedPercent
  SKIP: highestWastedBytes: rule disabled
  PASS: lowestEfficiency
Result:PASS [Total:3] [Passed:2] [Failed:0] [Warn:0] [Skipped:1]

各指標の意味

efficiency
レイヤー間でファイルが重複していない度合い。100%に近いほど良い。
wastedBytes
複数のレイヤーに同じファイルが存在することによる重複サイズ。レイヤーをsquash(統合)することで削減できる上限値。
userWastedPercent
ユーザー操作(Dockerfile命令)に起因する無駄の割合。

結果

sximada/agentic/all:202605.dev1 (4.01GB)の解析結果から言えること:

  • レイヤー構造は良好: efficiency 98.35% はほぼ問題ない水準。Dockerfileのレイヤー設計に起因する無駄は少ない。
  • squashで削減できる量は限定的: wastedBytes 86MB はイメージ全体(4.01GB)の約2%に過ぎない。レイヤー統合で得られる効果は小さい。
  • 本質的な削減には別のアプローチが必要: イメージが4GBある主な原因はインストール済みのパッケージやファイルの総量であり、diveのCI出力だけでは特定できない。インタラクティブモード(~dive <image>~)でレイヤーごとのファイルツリーを確認し、不要なパッケージの削除や軽量ベースイメージへの切り替えを検討する必要がある。

結論

できなそう。

付録

インストール元の検証について

冒頭でサプライチェーン攻撃について触れた手前、インストール前にどこまでの安全確認ができるか調べた。

セキュリティ上の調査

まずv0.13.1のリリースアセットを確認した。

  • dive_0.13.1_checksums.txt が提供されている(SHA256ハッシュ一覧)
  • GPG署名ファイル(~.asc~ / ~.sig~)は提供されていない
  • cosign/Sigstore による署名も提供されていない
  • gitタグは軽量タグ(lightweight tag)であり、署名されていない
  • GoReleaserの設定にも signs / cosign の設定はない

つまり、checksums.txtを使った検証はできるが、そのchecksums.txt自体が正当な発行元のものかどうかを暗号学的に証明する手段がない。

信頼の根拠をどこに置くか

では、作者を信頼する根拠は何か。「完全な確証は得られない」が正直な答えだ。それでも判断材料として使えるものはある。

  • GitHubリポジトリのスター数・コントリビューター数・活動履歴(コミュニティから継続的に見られている)
  • ソースコードが公開されており、誰でも監査できる
  • ビルドパイプライン(GitHub Actions + goreleaser)もリポジトリ上に公開されており、ビルド過程を追うことができる

これらを総合して「受け入れられる水準」と判断するしかない。

checksums.txt検証で守れるもの・守れないもの

  • チェックサム検証が 有効 な攻撃:

    • ネットワーク経路上の中間者攻撃(MitM)
    • CDN・ミラーサーバーの改ざん
    • ダウンロード中の偶発的な破損
  • チェックサム検証が 無効 な攻撃:

    • GitHubリポジトリ自体の侵害
    • 作者のビルド環境・リリースパイプラインの侵害
    • 作者が悪意を持っている場合

つまり、checksums.txtはHTTPSで取得するためMitMには有効だが、GitHubが侵害された場合には.debとchecksums.txtが同時に書き換えられうる。このリスクはゼロにはできない。

ソースコードはチェックしなくていいの?

このようなツールを安易に使うのではなくAgentを使っておかしなコードがないかを事前に調べておくということは、実施できるしやるべきだと思う。今回は省略してしまった。反省点だ。

作成日