今天想做一個有點調皮的實驗,在上一篇中,我們用 nginx
這個 image 啟動了一個 container,在裡面放了一個 a.txt 的檔案後,將這個 container commit 成一個新的 image mynginx:a
。今天就讓我們用 mynginx:a
這個 image 啟動一個 container,並且驗證一下在這個 container 裡是否有 a.txt 這個檔案及其內容:
$ docker run -it --rm mynginx:a /bin/bash
root@330b823440a9:/# cat a.txt
a
如我們預期的,有 a.txt 這個檔案,且內容也符合。用另外一個 terminal 先回到 Host,讓我們去編輯一下 /var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/diff
裡的這個 a.txt,如果在裡面多加上一行字之類的,注意,這邊會需要用 root 權限才能操作:
$ echo "b" >> /var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/diff/a.txt
$ cat /var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/diff/a.txt
a
b
修改完之後,回到剛剛啟動的那個 container,再印出一次 a.txt:
root@1c77ff7fbaaa:/# cat a.txt
a
b
欸,b 也跟著出現了!那如果我們修改的是 container 裡的 a.txt 呢?
root@1c77ff7fbaaa:/# echo "c" >> a.txt
root@1c77ff7fbaaa:/# cat a.txt
a
b
c
回到 Host,查看一下 Host 中的 a.txt 的內容:
$ cat /var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/diff/a.txt
a
b
只有 a 跟 b,沒有 c 喔!這時候,讓我們在 Host 中的 a.txt 加上更多內容:
$ echo "d" >> /var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/diff/a.txt
$ cat /var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/diff/a.txt
a
b
d
回到 container 中,查看一下 a.txt:
# cat a.txt
a
b
c
發現 d 不會像剛剛的 b 一樣出現在 container 的 a.txt 中,為什麼會有不一樣的情況呢?
上述的步驟比較多,我們來整理一下觀察的結果:
mynginx:a
啟動的 container 中,會有 a.txt 這個檔案,且內容會跟我們在這個 image 的 UpperDir
檔案夾中的 a.txt 一模一樣。重新用 mynginx:a
啟動一個新的 container,並且觀察 a.txt,其內容應該會是我們在上一個實驗中,最後對 Host 裡的 a.txt 編輯的結果:
$ docker run -it --rm --name nginx-a1 mynginx:a /bin/bash
root@cffbff10b148:/# cat a.txt
a
b
d
回到 Host,將這個新的 container commit 成另外一個新的 image mynginx:a1
,用 inspect 去查看這個新的 image,會發現這個新的 image 的 RootFS
與 GraphDriver
這兩個區塊的內容跟 mynginx:a
一模一樣。
重新用 mynginx:a
啟動一個新的 container,這次我們對 a.txt 做一些編輯,例如加上一個 x:
$ docker run -it --rm --name nginx-a2 mynginx:a /bin/bash
root@33b776b69eea:/# cat a.txt
a
b
d
root@33b776b69eea:/# echo "x" >> a.txt
root@33b776b69eea:/# cat a.txt
a
b
d
x
回到 Host,將這個新的 container commit 成另外一個新的 image mynginx:a2
,用 inspect 去查看這個新的 image,會發現這個新的 image 的 RootFS
與 GraphDriver
,如預期地多了一層 layer,一樣去 mynginx:a
的 UpperDir
看一下,會發現裡頭一樣有一個 a.txt,且其內容為:
$ docker image inspect --format='{{json .GraphDriver}}' mynginx:a2 | jq
{
"Data": {
"LowerDir": "...略",
"MergedDir": "略",
"UpperDir": "/var/lib/docker/overlay2/8aa9e16514e13409d7e335a586a0a9f79d3c44b00e0d3492943f66b74125011a/diff",
"WorkDir": "略"
},
"Name": "overlay2"
}
$ cat /var/lib/docker/overlay2/8aa9e16514e13409d7e335a586a0a9f79d3c44b00e0d3492943f66b74125011a/diff/a.txt
a
b
d
x
重新用 mynginx:a
啟動一個新的 container,這次我們不對 a.txt 進行編輯,但在這個 container 裡增加一個新檔案 b.txt:
$ docker run -it --rm --name nginx-b mynginx:a /bin/bash
root@ef95ee841c42:/# cat a.txt
a
b
d
root@ef95ee841c42:/# touch b.txt
root@ef95ee841c42:/# echo "B" > b.txt
root@ef95ee841c42:/# cat b.txt
B
然後一樣 commit 成一個新的 image mynginx:b
:
$ docker commit nginx-b mynginx:b
sha256:7ec241c60bc868acd1daaa18abce0472c8c314e25892fcfcd70dd0c92a8d8c2c
# 觀察 GraphDriver
$ docker image inspect --format='{{json .GraphDriver}}' mynginx:b | jq
{
"Data": {
"LowerDir": "/var/lib/docker/overlay2/e6f2ed0e6d55115918467a74b4dfab3f3423c346cccdbe68763de8727061bf20/diff:/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/c4186bea7547109e50df09d0c10e4ecd3d7cf4ac554812d5d3b95ab0d5ea6a88/merged",
"UpperDir": "/var/lib/docker/overlay2/c4186bea7547109e50df09d0c10e4ecd3d7cf4ac554812d5d3b95ab0d5ea6a88/diff",
"WorkDir": "/var/lib/docker/overlay2/c4186bea7547109e50df09d0c10e4ecd3d7cf4ac554812d5d3b95ab0d5ea6a88/work"
},
"Name": "overlay2"
}
$ sudo ls var/lib/docker/overlay2/c4186bea7547109e50df09d0c10e4ecd3d7cf4ac554812d5d3b95ab0d5ea6a88/diff
b.txt
不再出現 a.txt,但會有剛剛新加上去的 b.txt。
實驗做到這裡,目前的 image layer 已經變成了:
mynginx:a
的 UpperDir
中會有一個 a.txt。mynginx:a2
的 UpperDir
中會有一個 a.txt,內容跟 image mynginx:a
中的不一樣。mynginx:b
的 UpperDir
中沒有 a.txt,但會有新加上去的 b.txt。這些是我們觀察到的結果,但到底原理是什麼呢?這些 layers 又是怎麼堆疊成我們在 container 裡看到的樣子呢?這個就讓我們靜待下一篇嚕。