はじめに
Docker入門した時に、コンテナ?イメージ?レイヤ?とごっちゃになったので勉強したことを忘備録としてまとめる
ゴール
- コンテナの構造と仕組みを理解する
- イメージの実体を見てみる
参考サイト
とっても参考にさせていただきました。ありがとうございます。
Dockerコンテナのレイヤ構造について
前提知識
-
Dockerfile
はテキスト形式のファイルで、イメージを作りあげるために実行するコマンドライン命令を記載する。 -
docker build
を実行すると、Dockerfile
に記載したコマンドライン命令を順次実行し、ビルド結果となるイメージが作成される。 - コンテナはイメージの実行可能なインスタンス(実行環境)
コンテナはレイヤの集まり
■イメージレイヤ
イメージを構成する読み込み専用のレイヤで、1つ以上存在する
■コンテナレイヤ
コンテナ上の読み書き可能なレイヤで、コンテナ内に1つ存在する
実行中のコンテナ内でファイルの変更を行った際は、イメージレイヤではなくコンテナ起動時に追加されるコンテナレイヤに記録される
💡 レイヤ構造を実現するために、DockerはUnionファイルシステム(UnionFS)
を導入している。UnionFS
は、複数にファイルシステム上のディレクトリやファイルをレイヤとして重ね合わせ、それらを仮想的に1つのファイルシステムとして扱う技術のことで、非常に軽量で高速。
読み込み専用のレイヤ
Dockerイメージにあたる。
-
イメージ構築(build)の時に、
Dockerfile
に記載された命令(RUN
とCOPY
とADD
)の結果がレイヤとして追加されていく。 -
Dockerfile
の命令ごとに1つのレイヤが作成されるため、命令を1行ずつ記載せずに&&
で結合すればレイヤの数が減らすことができる。 -
レイヤに含まれる情報
- ベースのイメージは?
- インストールしているものは?
- 環境変数や設定は?
など
図で表すと・・・・
FROM ubuntu:20.04
RUN apt-get update
COPY ./hello.sh /hello.sh
CMD [ "/hello.sh" ]
- FROM :ubuntu:20.04の Docker イメージからレイヤを作成
- RUN :aptgetをアップデート
- COPY :ローカルファイルを(コンテナのレイヤに)追加
- CMD :コンテナ起動後にコンテナ内でhello.shを実行
読み書き可能のレイヤ
読み書き可能レイヤにはコンテナで実行したルートファイルシステムへの変更差分のみが格納される。
つまり、コンテナに対して行った追加・修正・削除したデータが保存される。
-
読み込み専用レイヤに含まれるファイルに変更を加える場合は、変更対象のファイルのみが読み書き可能レイヤにコピーされ変更が加えられる。
-
コンテナが削除されると、その書き込みレイヤも削除される。
-
1つのイメージからコンテナを複数実行することができるがイメージレイヤは読み込み専用としてコンテナ間で共有される。
- 他のコンテナにより書き換えられることはなく、安全に共有できる。
- コンテナ個々に専用の読み書き可能レイヤがあり、コンテナで行った操作はこのレイヤに書き込まれる。コンテナ間で共有はされない。
これらの仕組みによって、それぞれのコンテナは他のコンテナによって意図せず書き換えられないようになっているため、効率良くリソースを使うことができる。
図で表すと・・・・
お互いの環境が影響し合わないことを試してみる
1つのイメージから2つコンテナを起動し、お互いの環境が影響し合わないことを確認する。
-
Dockerイメージを作成
公式チュートリアル の以下の章を実施しました。DockerfileFROM node:12-alpine RUN apk add --no-cache python2 g++ make WORKDIR /app COPY . . RUN yarn install --production CMD ["node", "src/index.js"] EXPOSE 3000
-
Dockerイメージの確認
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE testimg latest 9c693a57b0ee 4 minutes ago 430MB
-
同じイメージから2つコンテナを立ち上げる
# コンテナ名「testcontainer1」 $ docker run -dp 3000:3000 --name testcontainer1 -it testimg dfac31bb54ee7450dc9a1f6742e40422700595a351f2580995e2dd7d9d84c2e1 # コンテナ名「testcontainer2」 $ docker run -dp 3001:3000 --name testcontainer2 -it testimg 791ababe73ae298415dd8e57e91693ead5f0763052ce4cbc0cc3506632db88cc # コンテナの起動を確認 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 791ababe73ae testimg "docker-entrypoint.s…" 42 seconds ago Up 41 seconds 0.0.0.0:3001->3000/tcp testcontainer2 dfac31bb54ee testimg "docker-entrypoint.s…" 54 seconds ago Up 53 seconds 0.0.0.0:3000->3000/tcp testcontainer1
※ 2つ同時に起動できるようにポートを変えておく。
-
確認
各コンテナに配置したアプリケーションをブラウザで開いてそれぞれデータを作ってみると、コンテナ同士のデータが共有されていないことが確認できる。-
コンテナ「testcontainer1」http://localhost:3000/
-
コンテナ「testcontainer2」http://localhost:3001/
-
レイヤ構造を拝んでみる
まずはイメージ作成
FROM ubuntu:20.04
RUN apt-get update
COPY ./hello.sh /hello.sh
CMD [ "/hello.sh" ]
Dockerfile
を作成してビルドする
docker build -t test-image .
作成したイメージを出力する
docker save test-image | tar -xC ./export/
- docker save [image] でイメージを出力する
- イメージ「test-image」をtar形式で出力している
|--export
| |--955c4c5ed5f543d022e7e5e4af1a9a2fab12f26991ee42fb5c468aa8678dc426
| | |--VERSION
| | |--json
| | |--layer.tar
| |
| |--a992d083f1f0bb0a74aee6b683535b30de1e1e9ccfd876e0c1dedc920ddaa84a
| | |--VERSION
| | |--json
| | |--layer.tar
| |
| |--74008e61fb84e526d304357806ebec7ad43aed15ea763c7b98a93df28bc0588f
| | |--VERSION
| | |--json
| | |--layer.tar
| |
| |--8ff95465ba803d01aac73488eb1f044a91d8dcb6e38a71d1ec102d6a2b044313.json
| |
| |--manifest.json
| |--repositories
-
layer.tar
: イメージを構成するレイヤ群 -
manifest.json
,repositories
: イメージの構成などに関する情報 -
8ff954……..313.json
: 実行コマンドや環境変数など、実行環境を再現するため情報
各ファイルの中身を確認
layer.tar
# FROMで作成されたレイヤ(ubuntuを構成するフォルダやファイル)
$ tar --list -f 955c4c5ed5f543d022e7e5e4af1a9a2fab12f26991ee42fb5c468aa8678dc426/layer.tar
bin
boot/
dev/
etc/
etc/.pwd.lock
etc/adduser.conf
〜略〜
var/run
var/spool/
var/spool/mail
var/tmp/
# RUNで作成されたレイヤ(「apt-get update」で変更した分のフォルダやファイル)
$ tar --list -f a992d083f1f0bb0a74aee6b683535b30de1e1e9ccfd876e0c1dedc920ddaa84a/layer.tar
tmp/
var/
var/lib/
var/lib/apt/
var/lib/apt/lists/
〜略〜
var/lib/apt/lists/ports.ubuntu.com_ubuntu-ports_dists_focal_main_binary-arm64_Packages.lz4
var/lib/apt/lists/ports.ubuntu.com_ubuntu-ports_dists_focal_multiverse_binary-arm64_Packages.lz4
# COPYで作成されたレイヤ(ローカルからコピーしたファイル)
$ tar --list -f 74008e61fb84e526d304357806ebec7ad43aed15ea763c7b98a93df28bc0588f/layer.tar
hello.sh
manifest.json
イメージ情報の概要が記載されていた。
$ cat manifest.json
[
{
"Config": "8ff95465ba803d01aac73488eb1f044a91d8dcb6e38a71d1ec102d6a2b044313.json",
"RepoTags": [
"test-image:latest"
],
"Layers": [
"955c4c5ed5f543d022e7e5e4af1a9a2fab12f26991ee42fb5c468aa8678dc426/layer.tar",
"a992d083f1f0bb0a74aee6b683535b30de1e1e9ccfd876e0c1dedc920ddaa84a/layer.tar",
"74008e61fb84e526d304357806ebec7ad43aed15ea763c7b98a93df28bc0588f/layer.tar"
]
}
]
8ff954……..313.json
イメージ情報詳細や変更履歴が記載されていた。
{
"architecture": "arm64",
"config": {
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/hello.sh"
],
"ArgsEscaped": true,
"OnBuild": null
},
"created": "2022-06-21T04:49:35.639404252Z",
"history": [
{
"created": "2022-06-07T01:25:15.695379365Z",
"created_by": "/bin/sh -c #(nop) ADD file:8bb0809a8ac8e978274cf731cff7529372088d22c5b0233a28f01ef414aefbca in / "
},
{
"created": "2022-06-07T01:25:16.433758958Z",
"created_by": "/bin/sh -c #(nop) CMD [\"bash\"]",
"empty_layer": true
},
{
"created": "2022-06-21T04:49:35.619560543Z",
"created_by": "RUN /bin/sh -c apt-get update # buildkit",
"comment": "buildkit.dockerfile.v0"
},
{
"created": "2022-06-21T04:49:35.639404252Z",
"created_by": "COPY ./hello.sh /hello.sh # buildkit",
"comment": "buildkit.dockerfile.v0"
},
{
"created": "2022-06-21T04:49:35.639404252Z",
"created_by": "CMD [\"/hello.sh\"]",
"comment": "buildkit.dockerfile.v0",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:9fa12d818e9150724ca19fb518320d6cd48d987908062905a670c1a32e4a03a9",
"sha256:88a7de6f4747c2993263f43ebd5ae1bcc7d2f07cf1ddb4d9c19a4884ce578f2b",
"sha256:86cb9b63e55597f3168589be583702f4c9e08b6b0d0639c78094a54b992a68d1"
]
},
"variant": "v8"
}
repositories
最新版のレイヤ情報かな。Dockerfile
を変更してdocker build
したら変わるはず。
{"test-image":{"latest":"74008e61fb84e526d304357806ebec7ad43aed15ea763c7b98a93df28bc0588f"}}
おわりに
Dockerイメージについて自分の中でスッキリしたことにより、なんとなく書いていたDockerfile
も意識して書けるようになりました。