iT邦幫忙

2022 iThome 鐵人賽

DAY 5
2
DevOps

那些關於 docker 你知道與不知道的事系列 第 5

Day 05: 什麼是 image layer?

  • 分享至 

  • xImage
  •  

在上一篇中,我們討論到了 image 會把應用程式、相依的函式庫/套件,以及應用程式執行時所需的系統環境給打包起來,用這個 image 啟動的 container 就會有所有需要的資源,藉此我們達成了「Build once, Run anywhere」的夢想(?)。但這也引申了另外一個問題,這個 image 會不會很大呢?如果有兩個類似環境的應用程式,例如有兩個不同的 Node.js 程式要用 container 來執行,他們都需要 Node.js 16 這個版本的執行環境,那會不會包了兩個很大的 image 呢?

寫到這裡,應該很自然地會想到,是否可以把相同的部分抽取出來共用,我們能想到的,docker 當然也能想到,所以的確 docker 也這麼做了。我們先來查看一下目前 Host 裡有哪些 images (備註1):

$ docker image ls
REPOSITORY       TAG       IMAGE ID       CREATED       SIZE
nginx            latest    2d389e545974   6 days ago    142MB

這時候讓我們用 docker image inspect nginx (或是 docker image inspect 2d389e545974)來查看一下這個 image 的細節,執行完這個指令後,一樣會看到一大串資訊,這次我們特別看一下 RootFS 這個區塊,跟 container 一樣,我們可以透過 format 跟 jq 來查看:

$ docker image inspect --format='{{json .RootFS}}' 2d389e545974 | jq
{
  "Type": "layers",
  "Layers": [
    "sha256:b45078e74ec97c5e600f6d5de8ce6254094fb3cb4dc5e1cc8335fb31664af66e",
    "sha256:9388548487b1997b925923c4711efa5c7fdf5a5203a36e8055ffe7960a6b9127",
    "sha256:a064c1703bfdb529a4338259302cdf4d2407fddcedeabb9879b2332deb2df794",
    "sha256:7ee9bf58503c7147275d30d50397bb67a643e58925764492ef3e2d8f375bccde",
    "sha256:31192a8593ecba270815430c38c164c53ed65a765062b1b4b4aeca1ceec92d1e",
    "sha256:36665e416ec8d9af3690bd5738f7642688252a2edf427e1a0ae6b1a1ca6748d0"
  ]
}

這邊可以看到他用的詞是layer,然後這邊有 6 層 layers,這個 layer 是 docker 所設計的,也正是這個 layer 使我們之前的推測成真。除了 RootFS 這個區塊外,還有一個區塊 GraphDriver 特別值得注意:

$ docker image inspect --format='{{json .GraphDriver}}' 2d389e545974 | jq
{
  "Data": {
    "LowerDir": "/var/lib/docker/overlay2/b55fadceebc53ee1e133343d57bcb70b4a96659ebb0a4c83ffcf27a02fe495ee/diff:/var/lib/docker/overlay2/1d05141f1e9f2fbc9bdfb87a681976ce7db6f1dae3c12a6d94c00197e07da019/diff:/var/lib/docker/overlay2/c5dee5abf71f4c0ecb219c68f19ca56f64b0400739319ed482994fb58c297f79/diff:/var/lib/docker/overlay2/ed5b345b9d1a113c250527826f268a24e556fc67314340a6082b9627bf99fc36/diff:/var/lib/docker/overlay2/2607ebf4a87c9a99966ad99c7c096d541114a3b4f75ab25e2bac3bf614f3485b/diff",
    "MergedDir": "/var/lib/docker/overlay2/8b0ad5ef739a7bb36a94fafce200ff939055225d5bcfd43b837ec3a5e8e595d6/merged",
    "UpperDir": "/var/lib/docker/overlay2/8b0ad5ef739a7bb36a94fafce200ff939055225d5bcfd43b837ec3a5e8e595d6/diff",
    "WorkDir": "/var/lib/docker/overlay2/8b0ad5ef739a7bb36a94fafce200ff939055225d5bcfd43b837ec3a5e8e595d6/work"
  },
  "Name": "overlay2"
}

這邊請特別注意 LowerDirUpperDir,他們是 Host 上的檔案夾路徑,讓我們整理一下 LowerDir,可以看到它包含有五個檔案夾路徑:

/var/lib/docker/overlay2/b55fadceebc53ee1e133343d57bcb70b4a96659ebb0a4c83ffcf27a02fe495ee/diff
/var/lib/docker/overlay2/1d05141f1e9f2fbc9bdfb87a681976ce7db6f1dae3c12a6d94c00197e07da019/diff
/var/lib/docker/overlay2/c5dee5abf71f4c0ecb219c68f19ca56f64b0400739319ed482994fb58c297f79/diff
/var/lib/docker/overlay2/ed5b345b9d1a113c250527826f268a24e556fc67314340a6082b9627bf99fc36/diff
/var/lib/docker/overlay2/2607ebf4a87c9a99966ad99c7c096d541114a3b4f75ab25e2bac3bf614f3485b/diff

讓我們來做個小實驗:

  1. 用 nginx 這個 image 啟動一個 container,並命名為 nginx-a,在這個 container 中建立一個檔案,並且在這檔案中加上一些內容
$ docker run -it --name nginx-a nginx /bin/bash
root@e72d1a7dca58:/# touch a.txt
root@e72d1a7dca58:/# echo "a" > a.txt
  1. 另外一個 terminal 登入 Host,將這個 container commit 成一個新的 image mynginx:a
$ docker commit nginx-a mynginx:a
$ docker image ls

REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
mynginx          a         c62870f5a42d   12 minutes ago   142MB
nginx            latest    2d389e545974   7 days ago       142MB
  1. 查看 image nginx:a,一樣特別觀察一下 RootFSGraphDriver 這兩個區塊:
$ docker image inspect --format='{{json .RootFS}}' mynginx:a | jq
{
  "Type": "layers",
  "Layers": [
    "sha256:b45078e74ec97c5e600f6d5de8ce6254094fb3cb4dc5e1cc8335fb31664af66e",
    "sha256:9388548487b1997b925923c4711efa5c7fdf5a5203a36e8055ffe7960a6b9127",
    "sha256:a064c1703bfdb529a4338259302cdf4d2407fddcedeabb9879b2332deb2df794",
    "sha256:7ee9bf58503c7147275d30d50397bb67a643e58925764492ef3e2d8f375bccde",
    "sha256:31192a8593ecba270815430c38c164c53ed65a765062b1b4b4aeca1ceec92d1e",
    "sha256:36665e416ec8d9af3690bd5738f7642688252a2edf427e1a0ae6b1a1ca6748d0",
    "sha256:990cd1c1946b4594aafdb4a879edf16977013643c1a64e4ecd9bfe7fd3d4fb67"
  ]
}

跟 image nginx 比較一下,有沒有發現,這邊多了一層 layer,變成 7 層了,而且前面的 6 層 layers 跟 nginx 的一模一樣。

再讓我們看一下 GraphDriver 這個區塊:

docker image inspect --format='{{json .GraphDriver}}' mynginx:a | jq
{
  "Data": {
    "LowerDir": "/var/lib/docker/overlay2/8b0ad5ef739a7bb36a94fafce200ff939055225d5bcfd43b837ec3a5e8e595d6/diff:/var/lib/docker/overlay2/b55fadceebc53ee1e133343d57bcb70b4a96659ebb0a4c83ffcf27a02fe495ee/diff:/var/lib/docker/overlay2/1d05141f1e9f2fbc9bdfb87a681976ce7db6f1dae3c12a6d94c00197e07da019/diff:/var/lib/docker/overlay2/c5dee5abf71f4c0ecb219c68f19ca56f64b0400739319ed482994fb58c297f79/diff:/var/lib/docker/overlay2/ed5b345b9d1a113c250527826f268a24e556fc67314340a6082b9627bf99fc36/diff:/var/lib/docker/overlay2/2607ebf4a87c9a99966ad99c7c096d541114a3b4f75ab25e2bac3bf614f3485b/diff",
    "MergedDir": "/var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/merged",
    "UpperDir": "/var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/diff",
    "WorkDir": "/var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/work"
  },
  "Name": "overlay2"
}

整理 LowerDir

/var/lib/docker/overlay2/8b0ad5ef739a7bb36a94fafce200ff939055225d5bcfd43b837ec3a5e8e595d6/diff
/var/lib/docker/overlay2/b55fadceebc53ee1e133343d57bcb70b4a96659ebb0a4c83ffcf27a02fe495ee/diff
/var/lib/docker/overlay2/1d05141f1e9f2fbc9bdfb87a681976ce7db6f1dae3c12a6d94c00197e07da019/diff
/var/lib/docker/overlay2/c5dee5abf71f4c0ecb219c68f19ca56f64b0400739319ed482994fb58c297f79/diff
/var/lib/docker/overlay2/ed5b345b9d1a113c250527826f268a24e556fc67314340a6082b9627bf99fc36/diff
/var/lib/docker/overlay2/2607ebf4a87c9a99966ad99c7c096d541114a3b4f75ab25e2bac3bf614f3485b/diff

mynginx:aLowerDir 有 6 個檔案夾路徑,而且他的第一個檔案夾路徑竟然是 nginxUpperDir,是不是很有趣!而這些既然都是在 Host 上的檔案夾路徑,那讓我們進到 mynginx:aUpperDir 看一下:

$ cd /var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/diff
$ ls
a.txt  etc  root  run  var

看到了嗎?在 mynginx:aUpperDir 所記錄的檔案夾裡竟然有一個 a.txt,我們來 cat 他看看:

$ cat a.txt
a

果然真的是我們剛剛在 container 裡做的那個 a.txt,是不是太神奇了!?

到這裡,我們應該可以有個小小的結論,那就是 image 是由這些 layers 堆疊起來的。以我們的實驗來說,mynginx:a 是從 image nginx 啟動的 container 做出來的,透過觀察可以發現 mynginx:a 的 layers 跟 nginx 的 layers 一模一樣,可以說,那些一樣的 layers 就是 mynginx:anginx 共用的部分了。

https://ithelp.ithome.com.tw/upload/images/20220920/20151857h4Pa3EBsgM.png

以上的觀察不知道你們覺得好不好玩,我自己是覺得很好玩,親眼看到這些東西在哪裡,即使還是不知道為什麼,但總讓我覺得似乎又掌握 container 更多了一點,就是一種踏實感,好像不再神秘與虛無飄渺了!下一篇希望可以帶大家動手做更多的實驗與觀察,希望你們也能覺得有趣~


備註:

  1. 也可以用 docker image listdocker images 來查看在 host 中的 images

上一篇
Day 04: 什麼是 image?
下一篇
Day 06: 來玩一下 docker image layer
系列文
那些關於 docker 你知道與不知道的事32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0

整个系列思路很清晰,学到很多,感谢!

我要留言

立即登入留言