はじめに
RailsのDockerイメージのサイズを半分以下にする事ができました!
Docker Multi-Stage Buildsとは
Docker17以降のバージョンでDockerfileにFrom句を複数書けるようになりました。
これがマジでヤバイ!
何がヤバイかというと、
複数のビルドしたイメージから必要なものだけをコピーできるということ。
ライブラリを展開する為に必要なツールのインストールなど行う場合が多々あるかと思いますが、最終的なイメージには不要なものもあるかと思います。
そういった不要なものを省く事が簡単にできます。
イメージはなるべくサイズを抑えるべきです。
イメージのビルド、デリバリの時間を圧縮でき、これはCI/CDの基本です。
Docker Multi-Stage Buildsに関しては、こちらの記事で詳しく解説されています。
Docker multi stage buildで変わるDockerfileの常識
Before And After
Rails用のdocker imageのサイズがどのくらい変わるか結果を先にお見せします。
Before
771MB
➜ rails_docker git:(master) ✗ docker images | grep web
railsdocker_web latest f2772a54bc64 54 seconds ago 771MB
After
355MB
なんと、半分以下のサイズになっています。
➜ rails_docker git:(master) ✗ docker images | grep web
railsdocker_web latest bfeeacbc82e7 12 days ago 355MB
Dockerfile
続いてDockerfileのBefore, Afterを比較してみましょう。
Before
FROM ruby:2.3.2-alpine
ENV LANG ja_JP.UTF-8
RUN apk --update add --virtual build-dependencies \
build-base \
curl-dev \
mysql-dev \
linux-headers
RUN apk --update add \
bash \
nodejs \
mariadb-dev \
tzdata \
&& rm /usr/lib/libmysqld*
RUN gem install bundler
WORKDIR /tmp
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
ENV BUNDLE_JOBS=4
RUN bundle install
RUN apk del build-dependencies
ENV APP_HOME /myapp
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
COPY . $APP_HOME
After
FROM ruby:2.3.2-alpine as builder
RUN apk --update add --virtual build-dependencies \
build-base \
curl-dev \
mysql-dev \
linux-headers
RUN gem install bundler
WORKDIR /tmp
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
ENV BUNDLE_JOBS=4
RUN bundle install
RUN apk del build-dependencies
FROM ruby:2.3.2-alpine
ENV LANG ja_JP.UTF-8
RUN apk --update add \
bash \
nodejs \
mariadb-dev \
tzdata \
&& rm /usr/lib/libmysqld*
RUN gem install bundler
WORKDIR /tmp
COPY --from=builder /usr/local/bundle /usr/local/bundle
ENV APP_HOME /myapp
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
COPY . $APP_HOME
ここでポイントとなるのが、
FROM ruby:2.3.2-alpine as builder
と、
COPY --from=builder /usr/local/bundle /usr/local/bundle
です。
あと、FROM
が2回登場している事がわかります。
最初のビルドでbuilder
というエイリアスをつけており、そこから、
/usr/local/bundle
を次のビルドでコピーしています。
要は、最初のビルドではbundle install
するだけが目的です。
その為のツールは全て不要です。
さいごに
Multi-Stage BuildsによってDockerイメージの軽量化ができました。
もちろん、Multi-Stage Buildsを利用せずとも軽量化はできます。
不要なファイルを手動で個別に削除していけば良いわけです。
しかし、Multi-Stage Buildsを使えば削除の手順を省く事ができるので、Dockerfileの見通しがよくなります。
更に、イメージの軽量化は可能ですが、細かいTipsは割愛します。
RailsのDockerイメージは肥大しやすいので、イメージサイズを少し意識してみてはいかがでしょうか?
快適なDockerライフを。