ここだけは理解しよう
- Docker イメージは複数のイメージが積み重なったもの
- 生成された DockerImage は Read Only
- Docker Container を作成することで、
変更可能なレイヤーが新しく作成され、その上でプロセスを動かす - Dockerfile の書き方によってファイルの読み書きがボトルネックとなり、遅いイメージができる
diffによる(RW)Containerの確認
# コンテナ実行
docker run \
--name ck-diff \
alpine touch /tmp/hoge.txt
# diffの確認
docker container diff ck-diff
赤枠の箇所が alpine
の image からコンテナ後に発生した diff(変更点)
を示しています。
tmpディレクト
と hoge.txt
を作成したことを示しています。
Docker Imageの層の積み重ねをみてみましょう
# hostにはnodeがないことを確認します
node -v
# nodeの環境を作成して、コンテナに入ります
docker run \
-it -p 3000:3000 \
-v `pwd`:/data \
node:12-alpine ash
# nodeのコンテナでnodeがあることを確認
node -v
ここからはコンテナで node を使うための準備です。
# nodeのコンテナ内でのコマンド
cd /data
npm install -g express-generator
express myapp
cd myapp
npm install
# expressの実行確認ができたら、コンテナからでましょう
npm start
# host側で下記のコマンドを実行しましょう
cd myapp/
ls
vi Dockerfile
docker build -t myapp:1 .
docker run -p 3000:3000 myapp:1
上記の Dockerfile の中身です。
FROM node
WORKDIR /scripts
COPY . .
RUN npm install
RUN groupadd app
RUN useradd -g app -m app
RUN mv /root/.config /home/app/
RUN chown -R app:app /scripts /home/app/.config
USER app
EXPOSE 3000
CMD ["npm", "start"]
このような感じで express
の web アプリが起動しています。
# myappのサイズを確認します。
docker images myapp:1
イメージは複数のイメージを積み重ねて最終的に 1 つのイメージになります。
また、積み重ねられたイメージのことを中間イメージと呼びます。
docker history
コマンドを利用することで Image の歴史をみることができます。
docker history myapp:1
# ベースとなっているnodeを確認します。
docker images node
alpineのnode
と node
の比較ができていますが、
明らかに from
で取得する node
のサイズが大きいです。
てか、こんなに大きいのか…
Docker Hubからサイズなどを確認しましょう。
# slimに変更
FROM node:slim
WORKDIR /scripts
COPY . .
RUN npm install
RUN groupadd app
RUN useradd -g app -m app
RUN mv /root/.config /home/app/
RUN chown -R app:app /scripts /home/app/.config
USER app
EXPOSE 3000
CMD ["npm", "start"]
上記の変更を行い、再度コンテナを作りましょう。
vi Dockerfile
docker build -t myapp:2 .
docker run -p 3000:3000 myapp:2
では、作成した myapp の Image サイズを確認します。
docker images myapp
次に history
コマンドを実行してみましょう。
12 行目までのユーザが記載している部分に変更はないです。
docker history myapp:2
FROM node:slim
WORKDIR /scripts
COPY . .
# RUNを&&で記載する。
RUN npm install \
&& groupadd app \
&& useradd -g app -m app \
&& mv /root/.config /home/app/ \
&& chown -R app:app /scripts /home/app/.config
USER app
EXPOSE 3000
CMD ["npm", "start"]
上記の修正を行い、Image を作成する。
vi Dockerfile
docker build -t myapp:3 .
では、作成ができたので、サイズと history
を確認する。
docker images myapp
docker history myapp:3
RUN
のレイヤーが減っていることを確認できます。
レイヤーを減らすことで UnisonFileSystem
への影響を減らすことができます。
UnisonFileSystemとは
こちらは、理解が難しかったのでUnison FileSystemをそのまま引用します。
最後に、Dockerのファイルシステムについです。
Docker Container から Docker Image へファイルを読み込む際、気をつけないとオーバーヘッドが大きくなります。
Containerレイヤーに操作対象のパスが存在しない場合、Imageレイヤーにファイルが無いかの捜査を行います。
この捜査は1レイヤーごとに見ていくため、レイヤーが多くなればなるほどオーバーヘッドが大きくなっていきます。
また、Dockerがデフォルトで使用しているファイルシステムではCopy On Write方式でファイルの読み書きを行います。
ファイルの更新がかかる度に捜査を実行するため、ログのように書き込みの激しいパスはDataVolumeを使用してUnison FileSystemを回避すると良いでしょう。
Dockerfile の RUN で実行した何かしらをコンテナ側から参照しようとします。
コンテナレイヤーに操作対象パスがないとレイヤーを辿っていくため、
その際にオーバヘッドがかかるといった意味合いと認識しています。