7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Dockerfileを理解して書きたくてレイヤ構造を拝んできた忘備録

Last updated at Posted at 2022-08-29

はじめに

Docker入門した時に、コンテナ?イメージ?レイヤ?とごっちゃになったので勉強したことを忘備録としてまとめる

ゴール

  • コンテナの構造と仕組みを理解する
  • イメージの実体を見てみる

参考サイト

とっても参考にさせていただきました。ありがとうございます。

Dockerコンテナのレイヤ構造について

前提知識

  • Dockerfileはテキスト形式のファイルで、イメージを作りあげるために実行するコマンドライン命令を記載する。
  • docker buildを実行すると、Dockerfileに記載したコマンドライン命令を順次実行し、ビルド結果となるイメージが作成される。
  • コンテナはイメージの実行可能なインスタンス(実行環境)

コンテナはレイヤの集まり

■イメージレイヤ

イメージを構成する読み込み専用のレイヤで、1つ以上存在する

■コンテナレイヤ

コンテナ上の読み書き可能なレイヤで、コンテナ内に1つ存在する
実行中のコンテナ内でファイルの変更を行った際は、イメージレイヤではなくコンテナ起動時に追加されるコンテナレイヤに記録される

💡 レイヤ構造を実現するために、DockerはUnionファイルシステム(UnionFS)を導入している。UnionFSは、複数にファイルシステム上のディレクトリやファイルをレイヤとして重ね合わせ、それらを仮想的に1つのファイルシステムとして扱う技術のことで、非常に軽量で高速。

読み込み専用のレイヤ

Dockerイメージにあたる。

  • イメージ構築(build)の時に、Dockerfileに記載された命令(RUNと COPYと ADD)の結果がレイヤとして追加されていく。 

  • Dockerfile命令ごとに1つのレイヤが作成されるため、命令を1行ずつ記載せずに&&で結合すればレイヤの数が減らすことができる。

  • レイヤに含まれる情報

    • ベースのイメージは?
    • インストールしているものは?
    • 環境変数や設定は?
      など

図で表すと・・・・

Dockerfile
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つのイメージからコンテナを複数実行することができるがイメージレイヤは読み込み専用としてコンテナ間で共有される。

    • 他のコンテナにより書き換えられることはなく、安全に共有できる。
    • コンテナ個々に専用の読み書き可能レイヤがあり、コンテナで行った操作はこのレイヤに書き込まれる。コンテナ間で共有はされない。

これらの仕組みによって、それぞれのコンテナは他のコンテナによって意図せず書き換えられないようになっているため、効率良くリソースを使うことができる。

図で表すと・・・・

image.png

※図はこちらのサイトを参考して書かせていただきました



お互いの環境が影響し合わないことを試してみる

1つのイメージから2つコンテナを起動し、お互いの環境が影響し合わないことを確認する。

  1. Dockerイメージを作成
    公式チュートリアル の以下の章を実施しました。

    Dockerfile
    FROM 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
    
  2. Dockerイメージの確認

    $ docker image ls
    REPOSITORY       TAG              IMAGE ID       CREATED         SIZE
    testimg          latest           9c693a57b0ee   4 minutes ago   430MB
    
  3. 同じイメージから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つ同時に起動できるようにポートを変えておく。

  4. 確認
    各コンテナに配置したアプリケーションをブラウザで開いてそれぞれデータを作ってみると、コンテナ同士のデータが共有されていないことが確認できる。

レイヤ構造を拝んでみる

まずはイメージ作成

Dockerfile
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フォルダに出力されたファイル
|--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も意識して書けるようになりました。

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?