1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ビルド時にgit cloneするイメージの軽量化(マルチステージビルドの復習)

Posted at

Dockerを触り始めた頃、巨大なリポジトリをcloneしてきて必要なファイル群をコピーしたりchownしたりといった操作を一つのステージでまとめて行ってしまっていたことがありました。これによって5GB近いサイズのイメージが出来上がっていた訳ですが、Dockerfileをマルチステージな構成を活かせる形に書き換えることで、イメージサイズを半分以下にまで落とすことができました。

この仕組みを調べたことがDockerの理解に役立ったため、当時の自分やDockerを触り始めたばかりの方に向けてまとめてみようと思います。今回行った最適化のポイントは、マルチステージビルドの活用COPY時の—chownオプションの活用の二つになります。

マルチステージビルドの活用

イメージサイズ肥大化への対処

Dockerのイメージは、ベースイメージのファイルシステムに対する一連の操作の重ね合わせとして認識されます。ビルドの際は、RUN, COPY, ADDなどの各操作が行われる度に新しいレイヤが作られ、それらのレイヤはスタックのようにベースイメージの上に重ねられて、最終的なイメージを形成します。

そのため、何も考えずにイメージをビルドすると、

  • ビルドツールと依存ライブラリ(コンパイラやビルドツール)
  • ビルド前のソースコードファイル
  • テストコードやテストツール

などの本番では必要のないファイル群が混ざってしまうことになります。

この問題に対処するために、昔は中間イメージを作成する手法が一般的だったようです。必要なファイルの入った中間イメージをもとにコンテナを起動してビルドなどの作業を行い、その生成物を本番のイメージにコピーすることでサイズを抑えていました(参考: docker docs マルチステージビルドの利用)。この手法は依然として有効ですが、マルチステージビルドはこのプロセスをよりシンプルにし、ビルドプロセスを1つのDockerfileに統合することを可能にします。

Dockerfileのマルチステージ化

今回のリファクタでは、次のようなDockerfileを

FROM php:7.4-fpm-alpine
...
RUN git clone -b master https://github.com/sampleorg/bigrepo.git /homedir
...
RUN cp -r /homedir /var/www/app
RUN chown -R php.php /var/www/app

以下のように書き直しました。

FROM alpine:3.13 as build
...
RUN git clone -b master https://github.com/sampleorg/bigrepo.git /homedir
...
FROM php:7.4-fpm-alpine
...
COPY --from=build --chown=php:php /homedir /var/www/app

もとのDockerfileでは、cloneしてきたリポジトリのコピー・所有権の変更を全て本番ステージで行っていました。操作の度にレイヤが生成されるため、影響を受けるファイルの数やサイズが大きい操作が積み重なることで、イメージサイズは2倍3倍と肥大して行ってしまいます。

リファクタ後のDockerfileでは、cloneやその後の処理はビルドステージで行い、必要なファイル群のみを本番ステージに持ってくるようにしました。

マルチステージビルドの際にビルドステージで生成されるイメージは、実際にはDockerのローカルストレージ(一般的にはDockerホストのファイルシステム内)に一時的に保存され、後続のステージから参照できるようになります。本番ステージでCOPY —from=buildのような命令を使用することで、この一時的に保存されたビルドステージのイメージからファイルをコピーすることができるようになります。

ビルドが完全に終了すると、これらの最終イメージの作成のみに用いられる中間イメージはその後は不要なため通常は削除されます。このような仕組みによって、最終的に生成されるイメージのサイズを小さく抑えることができるようになりました。

REPOSITORY       TAG       IMAGE ID       CREATED         SIZE
before           latest    8aabe296d57e   2 hours ago     4.87GB
after            latest    72fc81f23bc1   2 hours ago     1.88GB

COPY時の—chownオプションの活用

chownすると差分にカウントされる

リファクタ後のDockerfileについて、本番ステージの記述は以下のようにすることもできます。

FROM php:7.4-fpm-alpine
...
# COPY --from=build --chown=php:php /homedir /var/www/app
COPY --from=build /homedir /var/www/app
RUN chown -R php:php /var/www/app

しかしこの場合、生成されるイメージは大きなままとなってしまっています。

REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
after            latest    72fc81f23bc1   2 hours ago      1.88GB
after-chmod      latest    fbe148476f5b   16 minutes ago   3.36GB

これは、chown対象のディレクトリごと、前のレイヤの状態に対する差分として扱われてしまうためだと考えられます。DockerfileのADD/COPY操作において--chownを使用することで、ADD/COPYの一連のステップの中で操作対象ファイルの所有者を変更することができるため、こちらも不要なレイヤを増やさないという観点からイメージサイズの抑制に有効そうでした。

まとめ

ここまで、マルチステージビルドの活用COPY時の—chownオプションの活用の二つのポイントを通してイメージサイズの軽量化について説明しながら、イメージがどのように構成されているかなどのDockerの基本的なところも合わせて復習して来ました。この先の理解の助けになれば幸いです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?