All Articles

Dockerのイメージサイズを削減する

この前作ったMeCabのgRPCサーバ(mecab-grpc)のDockerイメージサイズが1.27GBとそこそこの大きさなので出来る限りサイズを小さくしてみたいと思います。

Dockerfile

FROM python:3.5.6-alpine3.9
LABEL Name=mecab-grpc Version=1.0.0

RUN apk add --no-cache git make g++ swig

WORKDIR /
RUN git clone https://github.com/taku910/mecab.git
WORKDIR /mecab/mecab
RUN ./configure --enable-utf8-only \
    && make \
    && make check \
    && make install

WORKDIR /mecab/mecab-ipadic
RUN ./configure --with-charset=utf8 \
    && make \
    && make install

WORKDIR /mecab/mecab-jumandic
RUN ./configure --with-charset=utf8 \
    && make \
    && make install

COPY . /mecab-grpc
WORKDIR /mecab-grpc
RUN python -m pip install --upgrade pip \
    && python -m pip install -r requirements.txt \
    && sh protoc-gen.sh

CMD ["python", "server.py"]

現状はこんな感じ。ベースイメージは既にalpineを使っているので、ベースイメージはそのままで不要なパッケージを削除したりレイヤー数を抑えたりする感じになると思います。(頑張ればマルチステージビルドとdistrolessみたいな方向性で極限まで削れるんだろうけど、今回のケースは手間に対して得られる効果が薄そうなのでalpineと古典的な削減方法で妥協)

調べる

削減の方法はググればいっぱい出てくる。実際に作業する前に調べて得たポイントを書き出してみる。

  • 小さいベースイメージを使う
  • レイヤーの数を最小限にする
  • デバッグ用のツールをインストールしない
  • 不要になったツールは同じレイヤーで削除
  • 適切な .dockerignore
  • apt-get install -y --no-install-recommends …
  • rm -rf /var/lib/apt/lists/*
  • apt-get purge -y --auto-remove …
  • apk add --no-cache …
  • apk add —-virtual …
  • apk del --purge …

どのサイトもこんな感じで同じようなことを言ってた。まとめると、

  • アプリの動作にとって不要なものはインストールしない
  • ツール(とかソース、キャッシュ、その他一時的なファイル)の追加と削除は1つのコンテキストと考えて、1つのレイヤーで完結させる

という感じだと思う。

やってみる

まずどのレイヤーでどのくらいサイズが増えているのか見たいので docker history をする。

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
67eb23360bbf        4 hours ago         /bin/sh -c #(nop)  CMD ["python" "server.py"]   0B
2978157db9ba        4 hours ago         /bin/sh -c python -m pip install --upgrade p…   216MB
ad947e372dde        4 hours ago         /bin/sh -c #(nop) WORKDIR /mecab-grpc           0B
6842b17a252e        4 hours ago         /bin/sh -c #(nop) COPY dir:7ff7416db8e5d3d9d…   3.85kB
b7a768bcc5b6        4 hours ago         /bin/sh -c ./configure --with-charset=utf8  …   297MB
f08be6cb767a        4 hours ago         /bin/sh -c #(nop) WORKDIR /mecab/mecab-juman…   0B
db55cd3ac0c1        4 hours ago         /bin/sh -c ./configure --with-charset=utf8  …   106MB
33cd77a79206        4 hours ago         /bin/sh -c #(nop) WORKDIR /mecab/mecab-ipadic   0B
c77fe2139ae9        4 hours ago         /bin/sh -c ./configure --enable-utf8-only   …   10.7MB
05277449a505        4 hours ago         /bin/sh -c #(nop) WORKDIR /mecab/mecab          0B
1c7466774cb7        4 hours ago         /bin/sh -c git clone https://github.com/taku…   379MB
b5e81d428587        4 hours ago         /bin/sh -c #(nop) WORKDIR /                     0B
7471a9d7fcf5        4 hours ago         /bin/sh -c apk add --no-cache git make g++ s…   188MB
3201b5481ba9        4 hours ago         /bin/sh -c #(nop)  LABEL Name=mecab-grpc Ver…   0B
be8ce886a36a        6 days ago          /bin/sh -c #(nop)  CMD ["python3"]              0B
<missing>           6 days ago          /bin/sh -c set -ex;   wget -O get-pip.py 'ht…   6.04MB
<missing>           6 days ago          /bin/sh -c #(nop)  ENV PYTHON_PIP_VERSION=19…   0B
<missing>           3 weeks ago         /bin/sh -c cd /usr/local/bin  && ln -s idle3…   32B
<missing>           3 weeks ago         /bin/sh -c set -ex  && apk add --no-cache --…   61.8MB
<missing>           3 weeks ago         /bin/sh -c #(nop)  ENV PYTHON_VERSION=3.5.6     0B
<missing>           3 weeks ago         /bin/sh -c #(nop)  ENV GPG_KEY=97FC712E4C024…   0B
<missing>           3 weeks ago         /bin/sh -c apk add --no-cache ca-certificates   551kB
<missing>           3 weeks ago         /bin/sh -c #(nop)  ENV LANG=C.UTF-8             0B
<missing>           3 weeks ago         /bin/sh -c #(nop)  ENV PATH=/usr/local/bin:/…   0B
<missing>           4 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>           4 weeks ago         /bin/sh -c #(nop) ADD file:2a1fc9351afe35698…   5.53MB

サイズが増えているところをピックアップして見てゆく。

apk add しているところで188MB増。 g++ パッケージ以外( gitmakeswig )はビルド&インストールする時しか必要ないので使い終わったら削除できる。( g++ にはロードされる共有ライブラリが含まれる。あとコンパイラも含まれてるから改善の余地あり)

MeCabのリポジトリをクローンしているところで379MB増。これはMeCab本体と辞書のインストールが終わったら必要なくなるので削除できる。

MeCab本体のインストールで10.7MB増、ipadicのインストールで106MB増、jumandicのインストールで297MB増。jumandicは正直使ったことが無いので削除。(辞書は人それぞれ。というか辞書によってはサイズが爆増するので、イメージサイズを頑張って削減するぞ!的な試みがほぼ無意味になるという)

最後に pip のアップグレードと依存パッケージのインストールとgRPCのスタブ諸々の生成で216MB増。そもそも pip はベースイメージの段階で最新のバージョンが入るっぽいからアップグレードは必要ない(削減とはあまり関係ないけど)。あとは依存パッケージのインストール時に pip のキャッシュを作らないために --no-cache-dir を追加する。

というわけで、書き直した Dockerfile が以下。

FROM python:3.5.6-alpine3.9
LABEL Name=mecab-grpc Version=1.0.0

COPY . /opt/mecab-grpc

RUN set -x \
    && apk add --no-cache --virtual .run-deps \
        g++ \
    \
    && apk add --no-cache --virtual .build-deps \
        git \
        make \
        swig \
    \
    && mkdir -p /usr/local/src \
    && cd /usr/local/src \
    && git clone https://github.com/taku910/mecab.git \
    \
    && cd /usr/local/src/mecab/mecab \
    && ./configure --enable-utf8-only && make && make check && make install \
    \
    && cd /usr/local/src/mecab/mecab-ipadic \
    && ./configure --with-charset=utf8 && make && make check && make install \
    \
    && cd /opt/mecab-grpc \
    && pip install \
        --disable-pip-version-check \
        --no-cache-dir \
        -r requirements.txt \
    && sh protoc-gen.sh \
    \
    && apk del --purge .build-deps \
    && rm -rf /usr/local/src/mecab

WORKDIR /opt/mecab-grpc
CMD ["python", "server.py"]

いくつかに分散していた RUNWORKDIR が1つ RUN にまとまっている(その都合上 COPYRUN の前に持ってくる)。 RUN の中ではまず set -x をする。これで単一の RUN で複数のコマンドを実行する時の出力が見やすくなる。公式のDockerfileがやってるのを真似した(サブシェルとかパイプを使う場合は set -ex としたり)。

apt add では --virtual でパッケージ群の意図の把握と管理がしやすいように名前を付ける。( .run-deps は後で何かをするわけじゃないけど、今回は分かりやすいようにあえて)

MeCab本体と辞書のインストールは特に変わらない(jumandicは削除)。 pip はバージョンチェックのスキップをするために --disable-pip-version-check を追加(新しいバージョンの pip があるぜ的なメッセージを出さないために)。 --no-cache-dir は上述の通り。

そんで RUN の最後に忘れずに apk del.build-deps を削除して、MeCabのソースコードも削除。

こんな感じでイメージサイズの合計が442MB。約1/3に削減できた。