重い
pushするのに時間がかかりすぎている.ビルドが遅いのは仕方がない.
いくらなんでもデプロイのたびに待つのはつらいので原因を探ってみると,
イメージ容量が800M!あれRubyってこんなに重いっけ???
ダイエット
目標は100MB台.
イメージ変遷
ruby:2.3.3(835.7MB) -> ruby:2.3.3-alpine(264.7MB) -> alpine:3.4(131.3MB)
約6分の1になりました.
FROM ruby:2.3.3
最初の状態.835.7MBうーん重い.流石に毎回これを転送するのはちょっと…
FROM ruby:2.3.3
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY Gemfile /usr/src/app/
COPY Gemfile.lock /usr/src/app/
RUN apt-get update && apt-get install -y git nodejs && apt-get clean &&\
gem install bundler --no-document && \
bundle config build.nokogiri --use-system-libraries && \
bundle install --without development test&& \
apt-get clean
COPY . .
RUN rails assets:precompile RAILS_ENV=production
EXPOSE 3000
CMD rails s -p 3000 -b '0.0.0.0'
FROM ruby:2.3.3-alpine
alpineって軽いよねー,流行ってるよねー.
264.7MBかぁ,まだ重いね.
FROM ruby:2.3.3-alpine
ENV RUNTIME_PACKAGES="libxml2-dev libxslt-dev libstdc++ tzdata mariadb-client-libs nodejs ca-certificates"\
DEV_PACKAGES="build-base mariadb-dev"
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY Gemfile /usr/src/app/
COPY Gemfile.lock /usr/src/app/
RUN apk add --update --no-cache $RUNTIME_PACKAGES &&\
apk add --update\
--virtual build-dependencies\
--no-cache\
$DEV_PACKAGES &&\
gem install bundler --no-document &&\
bundle config build.nokogiri --use-system-libraries &&\
bundle install --without development test &&\
apk del build-dependencies
COPY . .
RUN rails assets:precompile RAILS_ENV=production
EXPOSE 3000
CMD rails s -p 3000 -b '0.0.0.0'
FROM alpine:3.4
いや別にruby最新版使う必要ないし,ソースビルドしなくてもいいよね.
ビルド済みパッケージ使ったら軽くなるんじゃね?
131.3MB!やった!目標達成.これだったら,ローカルバイナリ並みの容量ですね.
FROM alpine:3.4
ENV RUNTIME_PACKAGES="ruby ruby-irb ruby-json ruby-rake ruby-bigdecimal ruby-io-console ruby-dev libxml2-dev libxslt-dev libstdc++ tzdata mariadb-client-libs nodejs ca-certificates"\
DEV_PACKAGES="build-base mariadb-dev"
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN apk add --update --no-cache $RUNTIME_PACKAGES
COPY Gemfile /usr/src/app/
COPY Gemfile.lock /usr/src/app/
RUN apk add --update\
--virtual build-dependencies\
--no-cache\
$DEV_PACKAGES && \
gem install bundler --no-document && \
bundle config build.nokogiri --use-system-libraries && \
bundle install --without development test&& \
apk del build-dependencies
COPY . .
RUN rails assets:precompile RAILS_ENV=production
CMD rails s -p 3000 -b '0.0.0.0'
まとめ
rubyの公式イメージでも,debianベースで732MBくらい,alpineベースで136.3MBくらいとデカイ.
最新バージョンのrubyを使わなきゃいけない事情がない限り,ビルド済みのパッケージでrubyは入れたほうが楽早軽.
おまけ
データを削除しているはずなのにイメージ容量が減らない
最初ruby:2.3.3-alpineのイメージで作ったときに容量が驚きの648MB!
debian版に比べたら200MBほど減少はしているものの,軽量なはずのalpinelinuxのメリットを消してしまっている.
その時のDockerfileはこんな感じ.
FROM ruby:2.3.3-alpine
ENV RUNTIME_PACKAGES="libxml2-dev libxslt-dev libstdc++ tzdata mariadb-client-libs nodejs ca-certificates"\
DEV_PACKAGES="build-base mariadb-dev"
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY Gemfile /usr/src/app/
COPY Gemfile.lock /usr/src/app/
RUN apk add --update --no-cache $RUNTIME_PACKAGES
RUN apk add --update\
--virtual build-dependencies\
--no-cache\
$DEV_PACKAGES
RUN gem install bundler --no-document && \
bundle config build.nokogiri --use-system-libraries && \
bundle install --without development test
RUN apk del build-dependencies
COPY . .
RUN rails assets:precompile RAILS_ENV=production
EXPOSE 3000
CMD rails s -p 3000 -b '0.0.0.0'
DockerfileってRUNにコマンド書くときにシェルスクリプトにまとめたり,&&で結合してるのをよく見るけれども
なんか見づらいなって感じてた頃がありました.
で,何を思ったかRUNを複数行に書いてしまったわけです.
overlayfsだと,apt-get/apkで依存関係をインストール,bundle install後に削除というのを別のRUNで実行していたためそれぞれにレイヤーが作成され,ファイル削除したレイヤーはファイルを削除したという情報だけが残ります.よって追加されたファイルのデータ自体は消えないわけですね.
解決方法は依存関係のインストール→bundle install→依存関係のアンインストールを一つのRUNで実行するだけですね.お恥ずかしい.
alpineだとgem install bundlerで証明書エラーが出る
ERROR: Could not find a valid gem 'bundler' (>= 0), here is why:
Unable to download data from https://rubygems.org/ - SSL_connect returned=1 errno=0 state=error: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)
ルート証明書が入ってなかったので,https通信に失敗しているみたい.
apk add ca-certificates
をしましょう.
bundle execできない
開発環境のcomposeが混ざっていた
意外とどこのサイトでも書いてないけど,docker-composeとかでローカルディレクトリをマウントしていた場合,
vendor/bundleがアーキテクチャ違うから動かない.
dockerで開発するならdockerのみで,ローカルで開発するならローカルのみで動かさないとハマりやすい.
dockerignoreについて
上でも述べた,ローカルマウントに関連してハマったポイント.
マイグレーションのテストをしようとdocker-compose run --rm --no-deps app sh
した時,
なぜかignoreしているはずのvendor/bundleがいる…と混乱した.
そのときに,何も考えないでrm -rf vendor/bundle && bundle install
して,migrateする.
ローカルに戻るとbundle exec
できないみたいな状況に陥り,パニックに.
よく考えればbuild時は正常にvendor/bundleはignoreされ,add .しても特に問題はない.
ただ,その後にvolumeマウントしていたためにignoreしたはずのファイルがいるということ.
気をつけよう.