はじめに
こんにちは。@canon1kyです。
本記事はDocker Advent Calendar 2019、7日目の記事です。
最近Dockerを使っていて、当たり前だけどやっていなかった圧倒的軽量化 を行って幸せになれたのでこの記事を書かせていただきます。
Dockerを使うすべての人が少しでも「やったぜ!!!」ってなってくれると嬉しいです。
知っている人は知っているかと思いますが、知らない人は是非見ていってください!
軽量化やってますか?
Dockerコンテナの軽量化やってますか??
既に「当たり前でしょ!!軽量化は基本中の基本!!」という人もいれば、「とりあえず使ってはいたけどあまり軽量化は意識したことなかったな〜」という人もいるでしょう。
私は「軽量化をしていたけど、そこまでガツンと軽量にはできていなかった(涙目)」民でした。
コンテナイメージサイズが大きいことによる弊害
主に下記のような現象が発生します。
- イメージのビルド時間が長い
- イメージをDocker Registoryにプッシュする時間が長い
- イメージをPullする時間が長い
それらが起因して、下記の弊害が起こります。
- トライアンドエラーに時間がかかり、生産性が低下
- ビルド時間、CI時間の増大
- オートスケールでコンテナがサービスインされるまでの時間が長くなる
- Kubernetesクラスタを構成するNodeディスクの消費
軽量化のアプローチ
私が主にやっていたのは下記のアプローチです。
1. RUN命令をまとめる
おそらく基本中の基本でしょう。
例えば下記の、Node.jsでGulpを使うコンテナを構築するDockerfile。
FROM node:10.17.0
# setup gulp
RUN npm install -g gulp@3.9.1
RUN npm install gulp-load-plugins
RUN npm install gulp-plumber
RUN npm install gulp-sass
RUN npm install gulp-pleeease
RUN npm install gulp-uglify
RUN npm install gulp-rename
RUN npm init -y
非常に多くのRUNコマンドが並んでいます。
RUN命令が走る度にイメージレイヤーが生成されてしまうので、ちょっと重くなります。
この例だと下記のように、RUNコマンドのレイヤーを1つにまとめられます。
FROM node:10.17.0
# setup gulp
# レイヤーが1つになる
RUN npm install -g gulp@3.9.1 \
&& npm install gulp-load-plugins \
&& npm install gulp-plumber \
&& npm install gulp-sass \
&& npm install gulp-pleeease \
&& npm install gulp-uglify \
&& npm install gulp-rename \
&& npm init -y
なお、さらに下記のようにできると良さそうです。
FROM node:10.17.0
# setup gulp
# npm installの後のパッケージを羅列
RUN npm install -g gulp@3.9.1 \
&& npm install gulp-load-plugins \
gulp-plumber \
gulp-sass \
gulp-pleeease \
gulp-uglify \
gulp-rename \
&& npm init -y
このように、複数のRUNコマンドを「連続で実行する1つのコマンド」として扱うことで、イメージレイヤーをまとめて軽量化できます。
※なお当方は、Node.js初心者であるためnpmに関する使い方で気になるところがあれば優しく指摘していただけると助かります()
2. いらないものを消す
例えば下記の、Webサーバー用PythonイメージをビルドするDockerfile。
FROM python:3.7.5
ENV PYTHONUNBUFFERED 1
# ↓ここに注目
RUN apt-get update && \
apt-get install -y default-libmysqlclient-dev && \
mkdir /code
WORKDIR /code
COPY . ./
RUN pip install --upgrade pip \
&& pip install -r requirements.txt
1つ目のRUNコマンドでmysqlclientのDebianパッケージをapt-get
でインストールしています。
この場合、**インストール時に使ったaptキャッシュ(ゴミファイル)**が残ってしまうので、下記のようにキャッシュを削除できます。
FROM python:3.7.5
ENV PYTHONUNBUFFERED 1
RUN apt-get update && \
apt-get install -y default-libmysqlclient-dev && \
apt-get clean && \ # ここと
rm -rf /var/lib/opt/lists/* && \ # ここでaptキャッシュを消している
mkdir /code
WORKDIR /code
COPY . ./
RUN pip install --upgrade pip \
&& pip install -r requirements.txt
こんな感じで、キャッシュなどの不要なファイルを消すことで軽量化できます。
しかし
軽くなっても数MB程度で、ほぼほぼ軽量化の実感は湧きませんでした。
先ほど挙げたNode.jsを使う下記のDockerfile。
FROM node:10.17.0
# setup gulp
RUN npm install -g gulp@3.9.1 \
&& npm install gulp-load-plugins \
gulp-plumber \
gulp-sass \
gulp-pleeease \
gulp-uglify \
gulp-rename \
&& npm init -y
このシンプルさを持っても、イメージサイズは980MB...
$ docker build . -t gulp-image-1
Sending build context to Docker daemon 2.048kB
...
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gulp-image-1 latest ee9ad2ee2e6b 2 minutes ago 980MB
node 10.17.0 d5680e53a228 9 days ago 903MB
...
こんなので1GB近くも使ってるなんてやってられるか!!!!
うーん、もっと軽くできないか...
改善していく
よく見てみると
ん...?ちょっと待てよ???
さっきのimage一覧をもう一度。
$ docker build . -t gulp-image-1
Sending build context to Docker daemon 2.048kB
...
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gulp-image-1 latest ee9ad2ee2e6b 2 minutes ago 980MB
node 10.17.0 d5680e53a228 9 days ago 903MB # ←これ
...
そもそもベースにしているnodeイメージがデカくね???
もっと軽いNode.jsイメージないのか?
もっと軽いやつがあった
DockerHubを探してみる。
バージョンはNode.jsの10.17.0を使いたいのでそいつを...
イメージ名は10.17.0-stretch-slim
。
Nodeイメージのページの下の方にバッチリ説明がある。
node:<version>-slim
This image does not contain the common packages contained in the default tag and only contains the minimal packages needed to run node. Unless you are working in an environment where only the node image will be deployed and you have space constraints, we highly recommend using the default image of this repository.
「通常のnodeイメージに入っている一般的なパッケージは入っておらず、nodeを走らせるための最小限のパッケージのみが入っている。nodeイメージのみがデプロイされ、容量に制約がある環境で作業している場合を除き、このリポジトリのデフォルトイメージを使用することを強くお勧めします。」
つまるところ、**いらない物全部抜きで最小限の物で構築されているからこれを使った方が良いよ!**ということ。
試しにビルドしてみる
下記のように書き換える。
# stretch-slimイメージに変更
FROM node:10.17.0-stretch-slim
# setup gulp
RUN npm install -g gulp@3.9.1 \
&& npm install gulp-load-plugins \
gulp-plumber \
gulp-sass \
gulp-pleeease \
gulp-uglify \
gulp-rename \
&& npm init -y
そしてビルド。
$ docker build . -t gulp-image-2
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM node:10.17.0-stretch-slim
...
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gulp-image-2 latest 77cd2cef489d 2 minutes ago 225MB # 新
gulp-image-1 latest ee9ad2ee2e6b 24 minutes ago 980MB # 旧
node 10.17.0 d5680e53a228 9 days ago 903MB # 旧
node 10.17.0-stretch-slim 7a5e19754b85 5 weeks ago 148MB # 新
980MB→225MB!!!
イメージサイズが4分の1以下になりました。やったぜ。
slimイメージが軽いというか、デフォルトのNodeイメージって本当にいろんな物が入ってたんですね...
まとめ
今回はslimイメージを使ったコンテナ軽量化の紹介をしました。
Node.jsの例の場合の使い分けとしてはいろいろあるかと思いますが、下記のような感じが良いのかなと思いました。
- 「とにかくDockerfileに細かいことを書かず、一通りツールが揃ったコンテナですぐにNode.jsを使いたい!!」みたいな場合は通常のNode.jsイメージ
- チーム開発や本番環境など、長い目線でコンテナを使用する場合はslimイメージ
今回はNode.jsを例にしましたが、もちろんPythonやPHPなどの他の言語用にもslimイメージは用意されているので、言語に合わせて使い分けてください。
それでは皆さん、来年度も良きDockerライフを!!