こんにちは、Synergy! 開発チームの松本です。これは TECHSCORE Advent Calendar 2018 の 10 日目の記事です。
Docker イメージをビルドした結果、作成されたイメージのサイズが大きすぎて困った経験はないでしょうか。コンパクトなイメージを作成するには、イメージの構造を知ることが鍵となります。本稿は、その前提知識となるイメージ内部についての解説記事です。
なお、本記事内で利用している Docker のバージョンは次の通りです。
1 2 |
$ docker --version Docker version 18.03.0-ce, build 0520e24 |
ユニオンファイルシステムとコピーオンライト
Docker コンテナが軽量だと言われる理由のひとつが、ユニオンファイルシステムにあります。ユニオンファイルシステムは、複数のファイルシステム上のディレクトリやファイルをレイヤとして重ね合わせ、それらを仮想的に一つのファイルシステムとして扱う技術です。
Docker は、このユニオンファイルシステムを使い、イメージを複数の読み取り専用レイヤのスタックとして扱います。コンテナ内ではさらに、読み書き可能なレイヤを一枚重ねています。
コンテナ上の読み書き可能なレイヤをコンテナレイヤと呼び、イメージを構成する読み込み専用レイヤをイメージレイヤと呼びます。
この構成により、同一ノード上で動く複数のコンテナが、Docker イメージを構成するイメージレイヤを共有することを可能にし、トータルとしてのコンテナサイズを最小化しているのです。
共有しているイメージレイヤに対するコンテナ上でのファイルの更新は、コピーオンライトによって実現しています。
コピーオンライトでは、イメージレイヤに存在するファイルへの更新時に、イメージレイヤからデータをコンテナレイヤーにコピーして変更を反映します。対象となるデータが複数のイメージレイヤに存在する場合は、最も上位のイメージレイヤ内のデータがコピーされます。
コピーオンライト処理は、利用している環境が選択しているストレージドライバによって実装が異なります。例えば aufs ドライバではコピーされるデータはファイルそのものですが、devicemapper ドライバではコピーされるデータは 64K バイトのブロック単位となります。
サポートされるストレージドライバのリストは次の通りで、利用している環境や用途に応じてベストなドライバを選択できます。
- overlay2, overlay
- aufs
- btrfs
- devicemapper
- vfs
- zfs
選択中のドライバが何であるかは、docker info
コマンドで確認できます。以下の例では devicemapper ドライバが選択されているとわかります。
1 2 |
$ docker info | grep 'Storage Driver' Storage Driver: devicemapper |
イメージのレイヤ構成
Docker イメージ内のレイヤ構造は docker history
コマンドで確認できます。下の例では、ubuntu:18.04
が 5 つのレイヤで構成されていることをうかがえます。
1 2 3 4 5 6 7 8 9 10 |
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 18.04 ea4c82dcd15a 4 weeks ago 85.8MB $ docker history ubuntu:18.04 IMAGE CREATED CREATED BY SIZE COMMENT ea4c82dcd15a 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 4 weeks ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B <missing> 4 weeks ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B <missing> 4 weeks ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 745B <missing> 4 weeks ago /bin/sh -c #(nop) ADD file:bcd068f67af2788db… 85.8MB |
このイメージをビルドする時に利用された Dockerfile と見比べてみましょう。各行は、Dockerfile 内の RUN
や ADD
などの命令(instruction)に対応しており、一番下の行が、Dockerfile 内での ADD ubuntu-bionic-core-cloudimg-amd64-root.tar.gz /
を実行した結果として作成されたレイヤです。最上位のレイヤはイメージ ID と一致しています。
この ubuntu:18.04
をもとに新たなイメージを作成するとレイヤ構成がどうなるか試してみます。Dockerfile は次の通り。
1 2 |
FROM ubuntu:18.04 RUN echo "Hello world" > /tmp/newfile |
ビルドします。
1 2 3 4 5 6 7 8 9 10 |
$ docker build -t changed-ubuntu . Sending build context to Docker daemon 2.048kB Step 1/2 : FROM ubuntu:18.04 ---> ea4c82dcd15a Step 2/2 : RUN echo "Hello world" > /tmp/newfile ---> Running in 39692af0aaaf Removing intermediate container 39692af0aaaf ---> 16f4672a0118 Successfully built 16f4672a0118 Successfully tagged changed-ubuntu:latest |
レイヤ構成を見てみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE changed-ubuntu latest 16f4672a0118 26 seconds ago 85.8MB ubuntu 18.04 ea4c82dcd15a 4 weeks ago 85.8MB $ docker history changed-ubuntu:latest IMAGE CREATED CREATED BY SIZE COMMENT 16f4672a0118 3 minutes ago /bin/sh -c echo "Hello world" > /tmp/newfile 12B ea4c82dcd15a 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 4 weeks ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B <missing> 4 weeks ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B <missing> 4 weeks ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 745B <missing> 4 weeks ago /bin/sh -c #(nop) ADD file:bcd068f67af2788db… 85.8MB |
先ほどの ubuntu:18.04
の上に、12 バイトの新たなレイヤ 16f4672a0118
が重なり、それが Dockerfile に記述した RUN
命令の結果として作成されたものであることがわかります。
このように、Docker イメージのビルドは、ベースとして利用したイメージの上に新たなレイヤを追加するだけとなります。
イメージレイヤのごみファイル問題
前述の通り Docker イメージは、Dockerfile に記述された RUN
や ADD
命令などを実行した結果、ファイルシステム上に加えられた変更をレイヤとして生み出します。このため、必要となる最終成果物を生成する途中で生み出された不要なファイルがレイヤに含まれて、レイヤのサイズが大きくなってしまうことがあります。
実験してみましょう。
Ubuntu で、apt-get install
する前に apt-get update
することはよくあります。下の例では apt-get update
でパッケージリストの更新を行うだけの Dockerfile を作成し、ビルドします。
Dockerfile の内容はこれです。
1 2 |
FROM ubuntu:18.04 RUN apt-get update |
ビルドします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
$ docker build -t apt-get-update-1 . Sending build context to Docker daemon 2.048kB Step 1/2 : FROM ubuntu:18.04 ---> ea4c82dcd15a Step 2/2 : RUN apt-get update ---> Running in 09669f5d8084 Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [83.2 kB] Get:2 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB] Get:3 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB] Get:4 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB] Get:5 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [264 kB] Get:6 http://security.ubuntu.com/ubuntu bionic-security/multiverse amd64 Packages [1364 B] Get:7 http://archive.ubuntu.com/ubuntu bionic/multiverse amd64 Packages [186 kB] Get:8 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [119 kB] Get:9 http://archive.ubuntu.com/ubuntu bionic/main amd64 Packages [1344 kB] Get:10 http://archive.ubuntu.com/ubuntu bionic/restricted amd64 Packages [13.5 kB] Get:11 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages [11.3 MB] Get:12 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [574 kB] Get:13 http://archive.ubuntu.com/ubuntu bionic-updates/restricted amd64 Packages [10.7 kB] Get:14 http://archive.ubuntu.com/ubuntu bionic-updates/multiverse amd64 Packages [6138 B] Get:15 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [734 kB] Get:16 http://archive.ubuntu.com/ubuntu bionic-backports/universe amd64 Packages [2975 B] Fetched 15.1 MB in 22s (676 kB/s) Reading package lists... Removing intermediate container 09669f5d8084 ---> 397f83c03093 Successfully built 397f83c03093 Successfully tagged apt-get-update-1:latest |
レイヤの中身を確認するために、イメージを docker save
コマンドでアーカイブします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ docker save apt-get-update-1:latest > apt-get-update-1.tar $ tar tvf apt-get-update-1.tar -rw-r--r-- 0/0 3538 2018-11-23 06:31 397f83c03093d363c8d66d82c822e2437f5837c7a2ae10b3fb18ffe5749c177a.json drwxr-xr-x 0/0 0 2018-11-23 06:31 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/ -rw-r--r-- 0/0 3 2018-11-23 06:31 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/VERSION -rw-r--r-- 0/0 469 2018-11-23 06:31 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/json -rw-r--r-- 0/0 12288 2018-11-23 06:31 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:31 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/ -rw-r--r-- 0/0 3 2018-11-23 06:31 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/VERSION -rw-r--r-- 0/0 469 2018-11-23 06:31 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/json -rw-r--r-- 0/0 15872 2018-11-23 06:31 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:31 973e978733af8ff5895179246123d8d91e1b9c3f869492507aefa7d74f123c45/ -rw-r--r-- 0/0 3 2018-11-23 06:31 973e978733af8ff5895179246123d8d91e1b9c3f869492507aefa7d74f123c45/VERSION -rw-r--r-- 0/0 469 2018-11-23 06:31 973e978733af8ff5895179246123d8d91e1b9c3f869492507aefa7d74f123c45/json -rw-r--r-- 0/0 3072 2018-11-23 06:31 973e978733af8ff5895179246123d8d91e1b9c3f869492507aefa7d74f123c45/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:31 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/ -rw-r--r-- 0/0 3 2018-11-23 06:31 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/VERSION -rw-r--r-- 0/0 393 2018-11-23 06:31 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/json -rw-r--r-- 0/0 88324608 2018-11-23 06:31 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:31 e5edf37c02223247b8034c8d7b9f38d7cf2daf77e852f1199697bcf30c36b1a7/ -rw-r--r-- 0/0 3 2018-11-23 06:31 e5edf37c02223247b8034c8d7b9f38d7cf2daf77e852f1199697bcf30c36b1a7/VERSION -rw-r--r-- 0/0 1239 2018-11-23 06:31 e5edf37c02223247b8034c8d7b9f38d7cf2daf77e852f1199697bcf30c36b1a7/json -rw-r--r-- 0/0 23897088 2018-11-23 06:31 e5edf37c02223247b8034c8d7b9f38d7cf2daf77e852f1199697bcf30c36b1a7/layer.tar -rw-r--r-- 0/0 520 1970-01-01 09:00 manifest.json -rw-r--r-- 0/0 99 1970-01-01 09:00 repositories |
manifest.json
と repositories
のタイムスタンプがおかしいですが、本筋に関係ないので無視しましょう。
各 layer.tar
の中に、レイヤ内のファイルが格納されています。ベースとなった ubuntu:18.04
のイメージに含まれていたレイヤを除き、新たに追加されたのは、973e978733af
、e5edf37c0222
からはじまるディレクトリ内の layer.jar
です。この中で、RUN apt-get update
で作成されたレイヤは、e5edf37c0222
ではじまるディレクトリの layer.tar
です。中身を確認してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ tar xf apt-get-update-1.tar $ tar tvf e5edf37c02223247b8034c8d7b9f38d7cf2daf77e852f1199697bcf30c36b1a7/layer.tar drwxr-xr-x 0/0 0 2018-10-19 06:03 var/ drwxr-xr-x 0/0 0 2018-10-19 06:02 var/lib/ drwxr-xr-x 0/0 0 2018-10-19 06:03 var/lib/apt/ drwxr-xr-x 0/0 0 2018-11-23 06:31 var/lib/apt/lists/ -rw-r--r-- 0/0 74562 2018-11-23 05:50 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-backports_InRelease -rw-r--r-- 0/0 4448 2018-09-21 19:00 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-backports_universe_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 88722 2018-11-23 05:50 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_InRelease -rw-r--r-- 0/0 927751 2018-11-23 03:52 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_main_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 9329 2018-11-21 05:42 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_multiverse_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 16198 2018-11-11 09:59 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_restricted_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 1203693 2018-11-23 03:52 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_universe_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 242048 2018-04-27 08:38 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_InRelease -rw-r--r-- 0/0 2165377 2018-04-27 02:43 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_main_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 292075 2018-04-27 08:38 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_multiverse_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 20606 2018-04-24 19:41 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_restricted_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 18132054 2018-04-27 07:52 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_universe_binary-amd64_Packages.lz4 drwxr-xr-x 100/0 0 2018-11-23 06:31 var/lib/apt/lists/auxfiles/ -rw-r----- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/lock drwx------ 100/0 0 2018-11-23 06:31 var/lib/apt/lists/partial/ -rw-r--r-- 0/0 83237 2018-11-23 05:50 var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_bionic-security_InRelease -rw-r--r-- 0/0 424814 2018-11-23 00:33 var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_bionic-security_main_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 1953 2018-11-21 04:59 var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_bionic-security_multiverse_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 188231 2018-11-23 00:33 var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_bionic-security_universe_binary-amd64_Packages.lz4 |
当たり前の話ですが、このように apt-get upadte
コマンドによって取得したパッケージリストがレイヤの中に含まれています。しかし多くの場合、これらのファイルはイメージサイズを大きくしているだけの存在で、コンテナの実行には不要です。
では次は、この不要なパッケージリスト(やキャッシュ)を削除する RUN
を追加した Dockerfile を用意し、ビルドして中身を見てみます。
1 2 3 |
FROM ubuntu:18.04 RUN apt-get update RUN apt-get clean && rm -rf /var/lib/apt/lists/* |
ビルドします。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ docker build -t apt-get-update-2 . Sending build context to Docker daemon 2.048kB Step 1/3 : FROM ubuntu:18.04 ---> ea4c82dcd15a Step 2/3 : RUN apt-get update ---> Using cache ---> 397f83c03093 Step 3/3 : RUN apt-get clean && rm -rf /var/lib/apt/lists/* ---> Running in 34a90f9e57e4 Removing intermediate container 34a90f9e57e4 ---> 28d865d3491d Successfully built 28d865d3491d Successfully tagged apt-get-update-2:latest |
余談ですが Step 2/3 を見ると、先ほど作成した apt-get-update-1:latest
が利用されていることが確認できます。
アーカイブして中身を確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
$ docker save apt-get-update-2:latest > apt-get-update-2.tar $ tar tvf apt-get-update-2.tar -rw-r--r-- 0/0 3778 2018-11-23 06:31 28d865d3491d0845cf54cf183e6520083b2d5fc63581180f8cd3ee88582c9ace.json drwxr-xr-x 0/0 0 2018-11-23 06:31 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/ -rw-r--r-- 0/0 3 2018-11-23 06:31 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/VERSION -rw-r--r-- 0/0 469 2018-11-23 06:31 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/json -rw-r--r-- 0/0 12288 2018-11-23 06:31 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:31 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/ -rw-r--r-- 0/0 3 2018-11-23 06:31 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/VERSION -rw-r--r-- 0/0 469 2018-11-23 06:31 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/json -rw-r--r-- 0/0 15872 2018-11-23 06:31 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:31 973e978733af8ff5895179246123d8d91e1b9c3f869492507aefa7d74f123c45/ -rw-r--r-- 0/0 3 2018-11-23 06:31 973e978733af8ff5895179246123d8d91e1b9c3f869492507aefa7d74f123c45/VERSION -rw-r--r-- 0/0 469 2018-11-23 06:31 973e978733af8ff5895179246123d8d91e1b9c3f869492507aefa7d74f123c45/json -rw-r--r-- 0/0 3072 2018-11-23 06:31 973e978733af8ff5895179246123d8d91e1b9c3f869492507aefa7d74f123c45/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:31 cb7480f242bce4996f5a6aa5f204038c6be507a7074e5cea2afd89d60fb6292d/ -rw-r--r-- 0/0 3 2018-11-23 06:31 cb7480f242bce4996f5a6aa5f204038c6be507a7074e5cea2afd89d60fb6292d/VERSION -rw-r--r-- 0/0 1279 2018-11-23 06:31 cb7480f242bce4996f5a6aa5f204038c6be507a7074e5cea2afd89d60fb6292d/json -rw-r--r-- 0/0 19968 2018-11-23 06:31 cb7480f242bce4996f5a6aa5f204038c6be507a7074e5cea2afd89d60fb6292d/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:31 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/ -rw-r--r-- 0/0 3 2018-11-23 06:31 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/VERSION -rw-r--r-- 0/0 393 2018-11-23 06:31 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/json -rw-r--r-- 0/0 88324608 2018-11-23 06:31 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:31 f2bc08b32ca8232fb47f71bcbe95ebce147ffa05f77c1ac7caef7e35243c3ead/ -rw-r--r-- 0/0 3 2018-11-23 06:31 f2bc08b32ca8232fb47f71bcbe95ebce147ffa05f77c1ac7caef7e35243c3ead/VERSION -rw-r--r-- 0/0 469 2018-11-23 06:31 f2bc08b32ca8232fb47f71bcbe95ebce147ffa05f77c1ac7caef7e35243c3ead/json -rw-r--r-- 0/0 23897088 2018-11-23 06:31 f2bc08b32ca8232fb47f71bcbe95ebce147ffa05f77c1ac7caef7e35243c3ead/layer.tar -rw-r--r-- 0/0 597 1970-01-01 09:00 manifest.json -rw-r--r-- 0/0 99 1970-01-01 09:00 repositories |
ベースとなった ubuntu:18.04
のイメージに含まれていたレイヤを除き、新たに追加されたのは、973e978733af
、cb7480f242bc
、f2bc08b32ca8
からはじまるディレクトリです。
f2bc08b32ca8
の layer.jar
を見ると、先ほどと同じように apt-get upadte
コマンドによって取得したパッケージリストが含まれてしまっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ tar xf apt-get-update-2.tar $ tar tvf f2bc08b32ca8232fb47f71bcbe95ebce147ffa05f77c1ac7caef7e35243c3ead/layer.tar drwxr-xr-x 0/0 0 2018-10-19 06:03 var/ drwxr-xr-x 0/0 0 2018-10-19 06:02 var/lib/ drwxr-xr-x 0/0 0 2018-10-19 06:03 var/lib/apt/ drwxr-xr-x 0/0 0 2018-11-23 06:31 var/lib/apt/lists/ -rw-r--r-- 0/0 74562 2018-11-23 05:50 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-backports_InRelease -rw-r--r-- 0/0 4448 2018-09-21 19:00 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-backports_universe_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 88722 2018-11-23 05:50 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_InRelease -rw-r--r-- 0/0 927751 2018-11-23 03:52 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_main_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 9329 2018-11-21 05:42 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_multiverse_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 16198 2018-11-11 09:59 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_restricted_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 1203693 2018-11-23 03:52 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic-updates_universe_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 242048 2018-04-27 08:38 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_InRelease -rw-r--r-- 0/0 2165377 2018-04-27 02:43 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_main_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 292075 2018-04-27 08:38 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_multiverse_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 20606 2018-04-24 19:41 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_restricted_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 18132054 2018-04-27 07:52 var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_bionic_universe_binary-amd64_Packages.lz4 drwxr-xr-x 100/0 0 2018-11-23 06:31 var/lib/apt/lists/auxfiles/ -rw-r----- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/lock drwx------ 100/0 0 2018-11-23 06:31 var/lib/apt/lists/partial/ -rw-r--r-- 0/0 83237 2018-11-23 05:50 var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_bionic-security_InRelease -rw-r--r-- 0/0 424814 2018-11-23 00:33 var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_bionic-security_main_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 1953 2018-11-21 04:59 var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_bionic-security_multiverse_binary-amd64_Packages.lz4 -rw-r--r-- 0/0 188231 2018-11-23 00:33 var/lib/apt/lists/security.ubuntu.com_ubuntu_dists_bionic-security_universe_binary-amd64_Packages.lz4 |
「削除されてないじゃないか」と思うかもしれませんが、cb7480f242bc
の layer.jar
を見てください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
$ tar tvf cb7480f242bce4996f5a6aa5f204038c6be507a7074e5cea2afd89d60fb6292d/layer.tar drwxr-xr-x 0/0 0 2018-10-19 06:03 var/ drwxr-xr-x 0/0 0 2018-10-19 06:02 var/lib/ drwxr-xr-x 0/0 0 2018-10-19 06:03 var/lib/apt/ drwxr-xr-x 0/0 0 2018-11-23 06:31 var/lib/apt/lists/ ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic-backports_InRelease ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic-backports_universe_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic-updates_InRelease ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic-updates_main_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic-updates_multiverse_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic-updates_restricted_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic-updates_universe_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic_InRelease ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic_main_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic_multiverse_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic_restricted_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.archive.ubuntu.com_ubuntu_dists_bionic_universe_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.auxfiles ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.lock ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.partial ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.security.ubuntu.com_ubuntu_dists_bionic-security_InRelease ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.security.ubuntu.com_ubuntu_dists_bionic-security_main_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.security.ubuntu.com_ubuntu_dists_bionic-security_multiverse_binary-amd64_Packages.lz4 ---------- 0/0 0 2018-11-23 06:31 var/lib/apt/lists/.wh.security.ubuntu.com_ubuntu_dists_bionic-security_universe_binary-amd64_Packages.lz4 |
.wh.
をプレフィクスとしたファイルリストがサイズ 0 で含まれています。これがホワイトアウトファイルと呼ばれる、削除したファイルのリストです。このレイヤを重ねることで、下層レイヤのファイルを削除したことにしているのです。
しかし、これでは余分にレイヤが増えただけで、全体としてのイメージサイズが小さくなっていません。
次は RUN
命令一行で Dockerfile を書いてみます。
1 2 |
FROM ubuntu:18.04 RUN apt-get update && apt-get clean && rm -rf /var/lib/apt/lists/* |
ビルドします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
$ docker build -t apt-get-update-3 . Sending build context to Docker daemon 2.048kB Step 1/2 : FROM ubuntu:18.04 ---> ea4c82dcd15a Step 2/2 : RUN apt-get update && apt-get clean && rm -rf /var/lib/apt/lists/* ---> Running in 2f45bfcc3736 Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [83.2 kB] Get:2 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB] Get:3 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [119 kB] Get:4 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB] Get:5 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB] Get:6 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [264 kB] Get:7 http://security.ubuntu.com/ubuntu bionic-security/multiverse amd64 Packages [1364 B] Get:8 http://archive.ubuntu.com/ubuntu bionic/multiverse amd64 Packages [186 kB] Get:9 http://archive.ubuntu.com/ubuntu bionic/restricted amd64 Packages [13.5 kB] Get:10 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages [11.3 MB] Get:11 http://archive.ubuntu.com/ubuntu bionic/main amd64 Packages [1344 kB] Get:12 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [734 kB] Get:13 http://archive.ubuntu.com/ubuntu bionic-updates/restricted amd64 Packages [10.7 kB] Get:14 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [574 kB] Get:15 http://archive.ubuntu.com/ubuntu bionic-updates/multiverse amd64 Packages [6138 B] Get:16 http://archive.ubuntu.com/ubuntu bionic-backports/universe amd64 Packages [2975 B] Fetched 15.1 MB in 23s (647 kB/s) Reading package lists... Removing intermediate container 2f45bfcc3736 ---> 2f98a3bdc5eb Successfully built 2f98a3bdc5eb Successfully tagged apt-get-update-3:latest |
アーカイブして、内容を確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$ docker save apt-get-update-3:latest > apt-get-update-3.tar $ tar tvf apt-get-update-3.tar -rw-r--r-- 0/0 3619 2018-11-23 06:33 2f98a3bdc5eb40882c29040a4b1d824c8f300ec12803e0c975055c0d2c2cc8da.json drwxr-xr-x 0/0 0 2018-11-23 06:33 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/ -rw-r--r-- 0/0 3 2018-11-23 06:33 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/VERSION -rw-r--r-- 0/0 469 2018-11-23 06:33 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/json -rw-r--r-- 0/0 12288 2018-11-23 06:33 4d261ce96493c446d20af968a8415279ab8e46658e717d79cb9299bb211f5aee/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:33 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/ -rw-r--r-- 0/0 3 2018-11-23 06:33 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/VERSION -rw-r--r-- 0/0 469 2018-11-23 06:33 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/json -rw-r--r-- 0/0 15872 2018-11-23 06:33 7b55d5fa32646ca928da35300c6a43b82633909610b4114b95e22dd4bb72f82e/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:33 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/ -rw-r--r-- 0/0 3 2018-11-23 06:33 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/VERSION -rw-r--r-- 0/0 393 2018-11-23 06:33 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/json -rw-r--r-- 0/0 88324608 2018-11-23 06:33 d03f81680b031705cd4976ebb35c175b1cad44a74040a7d0c4c77c558354d988/layer.tar drwxr-xr-x 0/0 0 2018-11-23 06:33 df0a6127ae8b4a84f4ef649835fe0b0b0382ba0ef1e8a44b3334c806aaf0bddd/ -rw-r--r-- 0/0 3 2018-11-23 06:33 df0a6127ae8b4a84f4ef649835fe0b0b0382ba0ef1e8a44b3334c806aaf0bddd/VERSION -rw-r--r-- 0/0 1307 2018-11-23 06:33 df0a6127ae8b4a84f4ef649835fe0b0b0382ba0ef1e8a44b3334c806aaf0bddd/json -rw-r--r-- 0/0 3072 2018-11-23 06:33 df0a6127ae8b4a84f4ef649835fe0b0b0382ba0ef1e8a44b3334c806aaf0bddd/layer.tar -rw-r--r-- 0/0 443 1970-01-01 09:00 manifest.json -rw-r--r-- 0/0 99 1970-01-01 09:00 repositories |
新たに追加されたのは、df0a6127ae8b
から始まるディレクトリのみですが、この中の layer.jar
にはパッケージリストは入っていません。
1 2 3 4 |
$ tar tvf df0a6127ae8b4a84f4ef649835fe0b0b0382ba0ef1e8a44b3334c806aaf0bddd/layer.tar drwxr-xr-x 0/0 0 2018-10-19 09:47 run/ drwxr-xr-x 0/0 0 2018-10-19 09:47 run/systemd/ -rw-r--r-- 0/0 7 2018-10-19 09:47 run/systemd/container |
今回は、期待通りごみファイルがレイヤごと消えてなくなりました。Docker イメージのビルドでは、ごみファイルが残らないよう、常に注意が必要ですね。
イメージレイヤのゴミファイル問題 その 2 (マルチステージビルド)
先ほどの apt-get update
のようなケースでは、&&
でコマンドをつなぐだけで対応できますが、&&
で対応するには複雑になりすぎるようなケースもあり得ます。以前はビルダーパターンを使った、少し面倒な方法で回避していましたが、Docker 17.05 以降では、マルチステージビルドで対応できまるようになりました。
マルチステージビルドでは、ひとつの Dockerfile 内で、複数の FROM
命令が使えます。これがマルチステージと呼ばれる理由です。
各ステージでは、前のステージでビルドされた成果物を参照でき、最終ステージのみがイメージとして保存されます。
次の例は、docker ユーザーガイドからの引用です。
1 2 3 4 5 6 7 8 9 10 11 |
FROM golang:1.7.3 as builder WORKDIR /go/src/github.com/alexellis/href-counter/ RUN go get -d -v golang.org/x/net/html COPY app.go . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /go/src/github.com/alexellis/href-counter/app . CMD ["./app"] |
ひとつめのステージは、FROM
命令に builder
という名前が付けられています。それをふたつめのステージの COPY
命令の --from=builder
で参照していることがわかります。これにより、ひとつめのステージの成果物である app
を、ふたつめのステージにコピーすることを可能にし、必要なファイルのみをイメージ内に含めることができるというわけです。
最後に
Docker に関するブログネタについては、他にも書きたいことがいくつかありました。コンテナ内でホスト OS とは異なる OS をどのように動かしているのかも、そのひとつです。機会があれば書いてみようと思っていますが、そう思って書いたことがないのが現実です。われながら移り気なものです……。