走進docker(06):docker create命令背後發生了什麼?

有了image以後,就能夠開始建立並啓動容器了,平時咱們都是用docker run命令直接建立並運行一個容器,它的背後其實包含獨立的兩步,一步是docker create建立容器,另外一步是docker start啓動容器,本篇將先介紹在docker create這一步中,docker作了哪些事情。node

簡單點來講,dockerd在收到客戶端的建立容器請求後,作了兩件事情,一是準備容器須要的layer,二是檢查客戶端傳過來的參數,並和image配置文件中的參數進行合併,而後存儲成容器的配置文件。docker

建立容器

建立一個容器用於示例json

#建立一個容器,並取名爲docker_test,
#-i是爲了讓容器能接受用戶的輸入,-t是指定docker爲容器建立一個tty,
#由於ubuntu這個鏡像默認啓動的進程是bash,而bash須要tty,不然會異常退出
dev@dev:~$ docker create -it --name docker_test ubuntu
967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368

dev@dev:~$ docker ps -a
CONTAINER ID   IMAGE    COMMAND       CREATED         STATUS   PORTS   NAMES
967438113fba   ubuntu   "/bin/bash"   6 seconds ago   Created          docker_test

layer的元數據

建立容器時,docker會爲每一個容器建立兩個新的layer,一個是隻讀的init layer,裏面包含docker爲容器準備的一些文件,另外一個是容器的可寫mount layer,之後在容器裏面對rootfs的全部增刪改操做的結果都會存在這個layer中。ubuntu

# layer的元數據存儲在layerdb/mounts/目錄下,目錄名稱就是容器的ID
# 裏面包含了三個文件
root@dev:/var/lib/docker/image/aufs/layerdb/mounts/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# ls
init-id  mount-id  parent

# mount-id文件包含了mount layer的cacheid
root@dev:/var/lib/docker/image/aufs/layerdb/mounts/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# cat mount-id
305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281

# init-id文件包含了init layer的cacheid
# init layer的cacheid就是在mount layer的cacheid後面加上了一個「-init」
root@dev:/var/lib/docker/image/aufs/layerdb/mounts/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# cat init-id
305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init

# parent裏面包含的是image的最上一層layer的chainid
# 表示這個容器的init layer的父layer是image的最頂層layer
root@dev:/var/lib/docker/image/aufs/layerdb/mounts/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# cat parent
sha256:9840d207a275f956f3e634148044e63dc78df511fd72e22d8cb3dad57dc49bf6

# 能夠根據parent的chainid獲得它的diffid,
# 這個diffid對應的確實是ubuntu:latest的最頂層layer
# 如何獲得image的layer信息請參考上一篇文章: 
# 走進docker(05):docker在本地如何管理image(鏡像)?
root@dev:/var/lib/docker/image# cat ./aufs/layerdb/sha256/9840d207a275f956f3e634148044e63dc78df511fd72e22d8cb3dad57dc49bf6/diff
sha256:d8b353eb3025c49e029567b2a01e517f7f7d32537ee47e64a7eac19fa68a33f3

新加的這兩層layer比較特殊,只保存在layerdb/mounts下面,在layerdb/sha256目錄下沒有相關信息,說明docker將container的layer和image的layer的元數據放在了不一樣的兩個目錄中bash

layer的數據

container layer的數據和image layer的數據的管理方式是同樣的,都存在/var/lib/docker/<storage-driver>目錄下面。spa

layers目錄

該目錄下包含了每一個layer的祖先layer的cacheid操作系統

root@dev:/var/lib/docker/aufs# cat ./layers/305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init
7938f2b32c53a9e0d3974f9579dd9dbb450202e1e11fe514e31556d4ea808c4e
4c10796e21c796a6f3d83eeb3613c566ca9e0fd0a596f4eddf5234b87955b3c8
fd0ba28a44491fd7559c7ffe0597fb1f95b63207a38a3e2680231fb2f6fe92bd
b656bf5f0688069cd90ab230c029fdfeb852afcfd0d1733d087474c86a117da3
1e83d2ea184e08eed978127311cc96498e319426abe2fb5004d4b1454598bd76

#從這裏能夠看出mount layer在init layer的上面
root@dev:/var/lib/docker/aufs# cat ./layers/305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281
305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init
7938f2b32c53a9e0d3974f9579dd9dbb450202e1e11fe514e31556d4ea808c4e
4c10796e21c796a6f3d83eeb3613c566ca9e0fd0a596f4eddf5234b87955b3c8
fd0ba28a44491fd7559c7ffe0597fb1f95b63207a38a3e2680231fb2f6fe92bd
b656bf5f0688069cd90ab230c029fdfeb852afcfd0d1733d087474c86a117da3
1e83d2ea184e08eed978127311cc96498e319426abe2fb5004d4b1454598bd76

#上面的7938f2...就是ubuntu:latest最上一層layer的cacheid
root@dev:~# find /var/lib/docker/image/ -name cache-id|xargs grep 7938f2b32c53a9e0d3974f9579dd9dbb450202e1e11fe514e31556d4ea808c4e
/var/lib/docker/image/aufs/layerdb/sha256/9840d207a275f956f3e634148044e63dc78df511fd72e22d8cb3dad57dc49bf6/cache-id:7938f2b32c53a9e0d3974f9579dd9dbb450202e1e11fe514e31556d4ea808c4e
#9840d2...是ubuntu:latest最上一層layer的chainid

diff目錄

該目錄下存放着每一個layer所包含的數據3d

#mount layer是新建的供容器寫數據layer,
#因爲容器尚未運行,因此這裏沒有任何數據
root@dev:/var/lib/docker/aufs/diff# tree 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281
305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281

0 directories, 0 files

#init layer包含了docker爲每一個容器所預先準備的文件
root@dev:/var/lib/docker/aufs/diff# tree 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init/
305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init/
├── dev
│   └── console
└── etc
    ├── hostname
    ├── hosts
    ├── mtab -> /proc/mounts
    └── resolv.conf

2 directories, 5 files

init layer裏面的文件有什麼做用呢?從下面的結果能夠看出,除了mtab文件是指向/proc/mounts的軟鏈接以外,其餘的都是空的普通文件。code

root@dev:/var/lib/docker/aufs/diff/305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init# ls -l dev
total 0
-rwxr-xr-x 1 root root 0 Jun 25 11:25 console
root@dev:/var/lib/docker/aufs/diff/305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init# ls -l etc
total 0
-rwxr-xr-x 1 root root  0 Jun 25 11:25 hostname
-rwxr-xr-x 1 root root  0 Jun 25 11:25 hosts
lrwxrwxrwx 1 root root 12 Jun 25 11:25 mtab -> /proc/mounts
-rwxr-xr-x 1 root root  0 Jun 25 11:25 resolv.conf

這幾個文件都是Linux運行時必須的文件,若是缺乏的話會致使某些程序或者庫出現異常,因此docker須要爲容器準備好這些文件:進程

  • /dev/console: 在Linux主機上,該文件通常指向主機的當前控制檯,有些程序會依賴該文件。在容器啓動的時候,docker會爲容器建立一個pts,而後經過bind mount的方式將pts綁定到容器裏面的/dev/console上,這樣在容器裏面往這個文件裏面寫東西就至關於往容器的控制檯上打印數據。這裏建立一個空文件至關於佔個坑,做爲後續bind mount的目的路徑。

  • hostname,hosts,resolv.conf:對於每一個容器來講,容器內的這幾個文件內容都有可能不同,這裏也只是佔個坑,等着docker在外面生成這幾個文件,而後經過bind mount的方式將這些文件綁定到容器中的這些位置,即這些文件都會被宿主機中的文件覆蓋掉。

  • /etc/mtab:這個文件在新的Linux發行版中都指向/proc/mounts,裏面包含了當前mount namespace中的全部掛載信息,不少程序和庫會依賴這個文件。

注意: 這裏mtab指向的路徑是固定的,但內容是變化的,取決於你從哪裏打開這個文件,當在宿主機上打開時,是宿主機上/proc/mounts的內容,當啓動並進入容器後,在容器中打開看到的就是容器中/proc/mounts的內容。

mnt目錄

裏面存放的是通過aufs文件系統mount以後的layer數據,即當前layer和全部的下層layer合併以後的數據,對於aufs文件系統來講,只有在運行容器的時候纔會被docker所mount,因此容器沒啓動的時候,這裏看不到任何文件。

root@dev:/var/lib/docker/aufs/mnt# tree 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281
305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281

0 directories, 0 files
root@dev:/var/lib/docker/aufs/mnt# tree 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init/
305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init/

0 directories, 0 files

配置文件

docker將用戶指定的參數和image配置文件中的部分參數進行合併,而後將合併後生成的容器的配置文件放在/var/lib/docker/containers/下面,目錄名稱就是容器的ID

root@dev:/var/lib/docker/containers/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# tree
.
├── checkpoints
├── config.v2.json
└── hostconfig.json

1 directory, 2 files
  • config.v2.json: 通用的配置,如容器名稱,要執行的命令等

  • hostconfig.json: 主機相關的配置,跟操做系統平臺有關,如cgroup的配置

  • checkpoints: 容器的checkpoint這個功能在當前版本仍是experimental狀態。

這裏不詳細介紹配置項的內容,後續介紹某些具體配置項的時候再來看這些文件。

checkpoints這個功能很強大,能夠在當前node作一個checkpoint,而後再到另外一個node上繼續運行,至關於無縫的將一個正在運行的進程先暫停,而後遷移到另外一個node上並繼續運行。

結束語

docker create命令乾的活比較少,主要是準備container的layer和配置文件,配置文件中的項比較多,後續會挑一些經常使用的項進行專門介紹。

相關文章
相關標籤/搜索