鉄板すぎる話ですが、自分の手元で確かめたかったのでメモに残します。
- Alpine Linux を利用する
- RUN 命令などを削減する
- マルチステージビルド
- 全部盛り
何もしない状態
Docker ドキュメント を参考に作成。
FROM ruby:2.6.8
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN gem install bundler:2.2.16 
RUN bundle install
COPY . /app
COPY dockerfiles/rails/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
サイズは1GB超え。
$ docker image ls
REPOSITORY         TAG               IMAGE ID       CREATED          SIZE
vocabook_api_app   latest            005fb8bfbdae   4 minutes ago    1.11GB
Alpine Linux を利用する
Alpine Linux は、コンテナでよく登場する軽量な Linux ディストリビューション。
apk というパッケージマネージャを利用するため、サブコマンドやパッケージ名を修正する。
注意:
すでに Debian ベースで動かしているサービスをコンテナ化する場合などは、Debian ベースの軽量なディストリビューション(stretch や buster)の利用が推奨されます。
FROM ruby:2.6.8-alpine3.14
RUN apk update -qq && apk add --no-cache build-base postgresql-dev nodejs
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN gem install bundler:2.2.16 
RUN bundle install
COPY . /app
COPY dockerfiles/rails/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
何もしない状態から 300MB 削減。
$ docker image ls
REPOSITORY         TAG               IMAGE ID       CREATED          SIZE
vocabook_api_app   latest            24268673b3c8   43 seconds ago   799MB
RUN 命令などを削減する
RUN や COPY などの命令によってレイヤと呼ばれる中間イメージが作成される。
命令数を減らすことで生成されるレイヤを削減し、イメージの軽量化を図る。
FROM ruby:2.6.8
RUN apt-get update -qq && \
    apt-get install -y build-essential libpq-dev nodejs && \
    mkdir /app
WORKDIR /app
COPY Gemfile Gemfile.lock /app/
RUN gem install bundler:2.2.16 && bundle install
COPY . /app
COPY dockerfiles/rails/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
この程度の命令数ではサイズは変わらず。
$ docker image ls
REPOSITORY         TAG               IMAGE ID       CREATED              SIZE
vocabook_api_app   latest            3b3100aef7b1   About a minute ago   1.11GB
マルチステージビルド
bundle installで分けている記事があったので参考に試してみる。
パッケージをインストールするステージ、そのパッケージをコピーして持ってくるステージに分ける。
FROM ruby:2.6.8 AS builder
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN gem install bundler:2.2.16 
RUN bundle install
FROM ruby:2.6.8 AS runner
RUN apt-get update -qq && apt-get install -y libpq-dev nodejs
RUN mkdir /app
WORKDIR /app
COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY . /app
COPY dockerfiles/rails/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
何もしていない状態から 20MB 程度減らすことができた。
$ docker image ls
REPOSITORY         TAG               IMAGE ID       CREATED          SIZE
vocabook_api_app   latest            376df67aec60   35 minutes ago   1.09GB
history コマンドでレイヤのサイズを見てみると、確かに 20MB くらい削減されている。
上:何もしないとき | 下:マルチステージビルド
<missing>      4 hours ago          RUN /bin/sh -c bundle install # buildkit        103MB     buildkit.dockerfile.v0
<missing>      11 minutes ago   COPY /usr/local/bundle /usr/local/bundle # b…   86.4MB    buildkit.dockerfile.v0
マルチステージビルドは、コンパイルしてバイナリを生成するようなケースだと分かりやすく効果が出そう。
全部盛り
FROM ruby:2.6.8-alpine3.14 AS builder
RUN apk update -qq && \
    apk add --no-cache build-base postgresql-dev nodejs && \
    mkdir /app
WORKDIR /app
COPY Gemfile Gemfile.lock /app/
RUN gem install bundler:2.2.16 && bundle install
FROM ruby:2.6.8-alpine3.14 AS runner
RUN apk update -qq && \
    apk add --no-cache postgresql-dev nodejs && \
    mkdir /app
WORKDIR /app
COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY . /app
COPY dockerfiles/rails/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
めっちゃ小さくなった。何もしない状態の半分近くまで小さくなっている。
$ docker images
REPOSITORY         TAG               IMAGE ID       CREATED             SIZE
vocabook_api_app   latest            4aebe416674b   2 minutes ago       588MB
history を見てみると、apk addのところで差分が出ていそうなので、build-base を最終イメージに持ってこなかったのが良かったみたい。
<missing>      6 minutes ago   RUN /bin/sh -c apk update -qq &&     apk add…   354MB     buildkit.dockerfile.v0
<missing>      6 hours ago     RUN /bin/sh -c apk update -qq && apk add --n…   547MB     buildkit.dockerfile.v0
参考