Docker筆記(一)- 鏡像與容器,Overlay2
來自專欄 Cerulean的專欄7 人贊了文章
背景
本系列Docker筆記將以基於TensorFlow的模型的訓練與部署的具體場景為例,總結Docker的基本原理、安裝、鏡像製作、容器部署等。事實上,在學校實驗室和自己的開源項目推進Docker使用已經快1年了,這篇文章之所以現在才開始寫,純粹是拖太久。
安裝docker與nvidia-docker
首先,請以官網教程安裝docker:
How to install docker on Ubuntu 16.04
如果你打算製作或者使用涉及到cuda或者cuddn等與GPU相關的鏡像或容器,你需要安裝nvidia-docker,請按照repo里的步驟安裝nvidia-docker:
How to install nvidia-docker on Ubuntu 16.04
在完成兩步安裝後,需要更改docker守護進程默認的runtime參數,請將/etc/docker/daemon.json
文件中鍵default-runtime
對應的值修改為nvidia
,然後通過sudo service docker restart
重啟docker服務,這一步操作是為了避免之後運行與cuda或者cudnn庫相關的容器時每次都要指定runtime
參數的情況。
請務必確認docker被正確安裝,接下來我們將從基本概念開始介紹docker,一直到模型部署。
基本概念
首先引用百度百科的定義:
Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然後發布到任何流行的 Linux 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何介面。
其次是官網的定義:
Docker is a platform for developers and sysadmins to develop, deploy, and run applications with containers.
其實百度百科的總結已經足夠好了,更概括地,Docker是一個輕量級虛擬機製作、分發、部署工具。
Docker有兩個非常重要的概念,他們分別是鏡像(image)與容器(container),直觀地,我們可以將容器類比為虛擬機,這個虛擬機可能是正在運行的,也可能是已經停止的,而鏡像則是像配置文件一樣定義了這些虛擬機如何運行。
而事實上事情要比上面的例子複雜很多,鏡像和容器的本質一個文件系統:
在計算機中,文件系統(File System)是命名文件及放置文件的邏輯存儲和恢復的系統。
我們首先將以Overlay2為例,詳細介紹鏡像與容器的區別和聯繫。
Overlay2
接下來將簡要的介紹文件存儲驅動overlay2,以便於更好的理解容器與鏡像的關係。overlay2是Ubuntu上最新的Docker CE版本18.06.0上的默認存儲驅動。上段提到,本質上鏡像與容器都是文件系統,它們唯一的不同,就是鏡像是只讀的,而容器是可讀可寫的。
舉個例子,我們通過以下命令獲取Ubuntu的鏡像:
? overlay2 docker pull ubuntuUsing default tag: latestlatest: Pulling from library/ubuntuc64513b74145: Pull complete01b8b12bad90: Pull completec5d85cf7a05f: Pull completeb6b268720157: Pull completee12192999ff1: Pull completeDigest: sha256:3f119dc0737f57f704ebecac8a6d8477b0f6ca1ca0332c7ee1395ed2c6a82be7Status: Downloaded newer image for ubuntu:latest? overlay2 docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEubuntu latest 735f80812f90 2 weeks ago 83.5MB
可以看出,Ubuntu鏡像具有5層,這5層都是只讀的,我們可以在這個目錄看到他們:
? overlay2 pwd/var/lib/docker/overlay2? overlay2 lltotal 24Kdrwx------ 4 root root 4.0K 8月 13 19:52 0ba50fa3b79a5dc66ebb8f2939e77128b0ab7c3989fc776bd4268af366bd148 5drwx------ 3 root root 4.0K 8月 13 19:52 225c757add2a395c0cfc47e1bc4472bf8fccf9dedd42f76f99b21c7637cb2a7 6drwx------ 4 root root 4.0K 8月 13 19:53 40b4fd1a0dea16978cffe5f26deee9a5834c76752db8c3b2a86057037a12b5f 5drwx------ 4 root root 4.0K 8月 13 19:52 7bb93daf624b3fc798554d36b75940fced7713f0d165631131432e230718555 9drwx------ 4 root root 4.0K 8月 13 19:52 ea274fcefed09dd48b0c6baa45e66bcd00887d4abbddbee1ef804c9dc7cfba4 edrwxr-xr-x 2 root root 4.0K 8月 13 19:53 l
以及這個文件夾:
? l pwd/var/lib/docker/overlay2/l? l lltotal 20Klrwxrwxrwx 1 root root 72 8月 13 19:52 IBZJKDU6Z76YR2ZDYWHDVUVHEZ -> ../0ba50fa3b79a5dc66ebb8f2939e77128 b0ab7c3989fc776bd4268af366bd1485/difflrwxrwxrwx 1 root root 72 8月 13 19:52 NRJEUKQPNXJQSQBLGCULIHRT77 -> ../7bb93daf624b3fc798554d36b75940fc ed7713f0d165631131432e2307185559/difflrwxrwxrwx 1 root root 72 8月 13 19:52 UXY6233J7FGSMGWJ2KJKU4Z6U3 -> ../225c757add2a395c0cfc47e1bc4472bf 8fccf9dedd42f76f99b21c7637cb2a76/difflrwxrwxrwx 1 root root 72 8月 13 19:52 VYQ3FKAYCIQNRXABOBPQ3ACEEH -> ../ea274fcefed09dd48b0c6baa45e66bcd 00887d4abbddbee1ef804c9dc7cfba4e/difflrwxrwxrwx 1 root root 72 8月 13 19:53 ZFT2GFUH6ZW3BMC3A4VY7S6HZV -> ../40b4fd1a0dea16978cffe5f26deee9a5 834c76752db8c3b2a86057037a12b5f5/diff
可以發現,全部都是到各層diff
之間的軟鏈接,以IBZJKDU6Z76YR2ZDYWHDVUVHEZ
為例,我們觀察一下這個鏈接目錄:
? l cd IBZJKDU6Z76YR2ZDYWHDVUVHEZ? IBZJKDU6Z76YR2ZDYWHDVUVHEZ lltotal 4.0Kdrwxr-xr-x 3 root root 4.0K 7月 27 06:20 etc
發現除了etc
文件夾之外空空如也,再以NRJEUKQPNXJQSQBLGCULIHRT77
為例,觀察一下這個符號鏈接目錄的內容:
? NRJEUKQPNXJQSQBLGCULIHRT77 lltotal 16Kdrwxr-xr-x 4 root root 4.0K 7月 27 06:20 etcdrwxr-xr-x 2 root root 4.0K 7月 27 06:20 sbindrwxr-xr-x 3 root root 4.0K 7月 25 04:51 usrdrwxr-xr-x 3 root root 4.0K 7月 25 04:53 var
可以發現以上內容。事實上,每層的diff
即是文件系統在統一掛載時的掛載點,我們可以再進一步地觀察下一層,UXY6233J7FGSMGWJ2KJKU4Z6U3
的內容:
? UXY6233J7FGSMGWJ2KJKU4Z6U3 lltotal 76Kdrwxr-xr-x 2 root root 4.0K 7月 25 04:53 bindrwxr-xr-x 2 root root 4.0K 4月 24 16:34 bootdrwxr-xr-x 4 root root 4.0K 7月 25 04:51 devdrwxr-xr-x 29 root root 4.0K 7月 25 04:53 etcdrwxr-xr-x 2 root root 4.0K 4月 24 16:34 homedrwxr-xr-x 8 root root 4.0K 7月 25 04:51 libdrwxr-xr-x 2 root root 4.0K 7月 25 04:52 lib64drwxr-xr-x 2 root root 4.0K 7月 25 04:51 mediadrwxr-xr-x 2 root root 4.0K 7月 25 04:51 mntdrwxr-xr-x 2 root root 4.0K 7月 25 04:51 optdrwxr-xr-x 2 root root 4.0K 4月 24 16:34 procdrwx------ 2 root root 4.0K 7月 25 04:53 rootdrwxr-xr-x 4 root root 4.0K 7月 25 04:51 rundrwxr-xr-x 2 root root 4.0K 7月 25 04:53 sbindrwxr-xr-x 2 root root 4.0K 7月 25 04:51 srvdrwxr-xr-x 2 root root 4.0K 4月 24 16:34 sysdrwxrwxrwt 2 root root 4.0K 7月 25 04:53 tmpdrwxr-xr-x 10 root root 4.0K 7月 25 04:51 usrdrwxr-xr-x 11 root root 4.0K 7月 25 04:53 var
可以發現這一層彷彿就是一個Ubuntu了。到這裡我們可以知道,鏡像是由多個層組織並定義的,這些層本質上是文件,這些文件是只讀的,每層具體的文件存放在層標識符下的diff
目錄下。接下來我們將介紹他們是如何被組織起來的。
回過頭來,我們繼續觀察層標識符目錄:
? overlay2 pwd/var/lib/docker/overlay2? overlay2 lltotal 24Kdrwx------ 4 root root 4.0K 8月 13 19:52 0ba50fa3b79a5dc66ebb8f2939e77128b0ab7c3989fc776bd4268af366bd148 5drwx------ 3 root root 4.0K 8月 13 19:52 225c757add2a395c0cfc47e1bc4472bf8fccf9dedd42f76f99b21c7637cb2a7 6drwx------ 4 root root 4.0K 8月 13 19:53 40b4fd1a0dea16978cffe5f26deee9a5834c76752db8c3b2a86057037a12b5f 5drwx------ 4 root root 4.0K 8月 13 19:52 7bb93daf624b3fc798554d36b75940fced7713f0d165631131432e230718555 9drwx------ 4 root root 4.0K 8月 13 19:52 ea274fcefed09dd48b0c6baa45e66bcd00887d4abbddbee1ef804c9dc7cfba4 edrwxr-xr-x 2 root root 4.0K 8月 13 19:53 l
接著我們進入225c757add2a395c0cfc47e1bc4472bf8fccf9dedd42f76f99b21c7637cb2a7
這個目錄,觀察一下目錄結構:
? 225c757add2a395c0cfc47e1bc4472bf8fccf9dedd42f76f99b21c7637cb2a76 tree . -L 2.├── diff│ ├── bin│ ├── boot│ ├── dev│ ├── etc│ ├── home│ ├── lib│ ├── lib64│ ├── media│ ├── mnt│ ├── opt│ ├── proc│ ├── root│ ├── run│ ├── sbin│ ├── srv│ ├── sys│ ├── tmp│ ├── usr│ └── var└── link20 directories, 1 file
好像沒什麼特別的,接著我們進入0ba50fa3b79a5dc66ebb8f2939e77128b0ab7c3989fc776bd4268af366bd148
這個目錄,觀察一下目錄結構:
? overlay2 cd 0ba50fa3b79a5dc66ebb8f2939e77128b0ab7c3989fc776bd4268af366bd1485? 0ba50fa3b79a5dc66ebb8f2939e77128b0ab7c3989fc776bd4268af366bd1485 tree ..├── diff│ └── etc│ └── apt│ └── sources.list├── link├── lower└── work4 directories, 3 files? 0ba50fa3b79a5dc66ebb8f2939e77128b0ab7c3989fc776bd4268af366bd1485 cat lowerl/VYQ3FKAYCIQNRXABOBPQ3ACEEH:l/NRJEUKQPNXJQSQBLGCULIHRT77:l/UXY6233J7FGSMGWJ2KJKU4Z6U3#? 0ba50fa3b79a5dc66ebb8f2939e77128b0ab7c3989fc776bd4268af366bd1485 cat linkIBZJKDU6Z76YR2ZDYWHDVUVHEZ#
可以看出,link
文件描述了該層標識符的精簡版,而lower
文件描述了層序的組織關係。接著我們通過以下命令啟動一個容器:
? 0ba50fa3b79a5dc66ebb8f2939e77128b0ab7c3989fc776bd4268af366bd1485 docker run -it ubuntu
然後通過以下命令觀察overlay2聯合掛載情況:
root@7d01751deb92:/# mount | grep overlayoverlay on / type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/FSK5KQSBSQH67GQ5IEWQKL4YPF:/var/lib/docker/overlay2/l/ZFT2GFUH6ZW3BMC3A4VY7S6HZV:/var/lib/docker/overlay2/l/IBZJKDU6Z76YR2ZDYWHDVUVHEZ:/var/lib/docker/overlay2/l/VYQ3FKAYCIQNRXABOBPQ3ACEEH:/var/lib/docker/overlay2/l/NRJEUKQPNXJQSQBLGCULIHRT77:/var/lib/docker/overlay2/l/UXY6233J7FGSMGWJ2KJKU4Z6U3,upperdir=/var/lib/docker/overlay2/3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da/diff,workdir=/var/lib/docker/overlay2/3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da/work)root@7d01751deb92:/#
我們可以觀察到一些關鍵信息,例如lowerdir
,可以看到是這些層標識符:
FSK5KQSBSQH67GQ5IEWQKL4YPFZFT2GFUH6ZW3BMC3A4VY7S6HZVIBZJKDU6Z76YR2ZDYWHDVUVHEZVYQ3FKAYCIQNRXABOBPQ3ACEEHNRJEUKQPNXJQSQBLGCULIHRT77UXY6233J7FGSMGWJ2KJKU4Z6U3
這時我們再觀察overlay2
文件夾,發現在該文件夾和l
文件夾都多出了2個標識符:
? overlay2 ls | grep 3893895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da-init? l ll | grep 389lrwxrwxrwx 1 root root 77 8月 13 20:26 FSK5KQSBSQH67GQ5IEWQKL4YPF -> ../3895f4ddbd45f65e509ed996d39536d1 737647bf1b70c2b9c82b6765b2e376da-init/difflrwxrwxrwx 1 root root 72 8月 13 20:26 O5NQ7PKEES3VHMHNZAZHE54M2C -> ../3895f4ddbd45f65e509ed996d39536d1 737647bf1b70c2b9c82b6765b2e376da/diff
這一層是動態生成的,觀察其目錄結構:
? 3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da-init tree . -L 4.├── diff│ ├── dev│ │ └── console│ └── etc│ ├── hostname│ ├── hosts│ ├── mtab -> /proc/mounts│ └── resolv.conf├── link├── lower└── work └── work5 directories, 7 files
可以看出,它主要是一些配置文件構成的層。而不帶init
後綴的3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da
的情況就比較特殊了:
? 3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da tree . -L 2.├── diff├── link├── lower├── merged│ ├── bin│ ├── boot│ ├── dev│ ├── etc│ ├── home│ ├── lib│ ├── lib64│ ├── media│ ├── mnt│ ├── opt│ ├── proc│ ├── root│ ├── run│ ├── sbin│ ├── srv│ ├── sys│ ├── tmp│ ├── usr│ └── var└── work └── work23 directories, 2 files? 3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da cat lowerl/FSK5KQSBSQH67GQ5IEWQKL4YPF:l/ZFT2GFUH6ZW3BMC3A4VY7S6HZV:l/IBZJKDU6Z76
回憶一下225c757add2a395c0cfc47e1bc4472bf8fccf9dedd42f76f99b21c7637cb2a7
這個標識符:
? 225c757add2a395c0cfc47e1bc4472bf8fccf9dedd42f76f99b21c7637cb2a76 tree . -L 2.├── diff│ ├── bin│ ├── boot│ ├── dev│ ├── etc│ ├── home│ ├── lib│ ├── lib64│ ├── media│ ├── mnt│ ├── opt│ ├── proc│ ├── root│ ├── run│ ├── sbin│ ├── srv│ ├── sys│ ├── tmp│ ├── usr│ └── var└── link20 directories, 1 file
可以看出,3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da
這標識符多了一個文件夾merged
,與225c757add2a395c0cfc47e1bc4472bf8fccf9dedd42f76f99b21c7637cb2a76
的diff
文件夾相似,它正是容器的可讀可寫層。講到這裡,我們在回頭來觀察overlay2聯合掛載情況:
root@7d01751deb92:/# mount | grep overlayoverlay on / type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/FSK5KQSBSQH67GQ5IEWQKL4YPF:/var/lib/docker/overlay2/l/ZFT2GFUH6ZW3BMC3A4VY7S6HZV:/var/lib/docker/overlay2/l/IBZJKDU6Z76YR2ZDYWHDVUVHEZ:/var/lib/docker/overlay2/l/VYQ3FKAYCIQNRXABOBPQ3ACEEH:/var/lib/docker/overlay2/l/NRJEUKQPNXJQSQBLGCULIHRT77:/var/lib/docker/overlay2/l/UXY6233J7FGSMGWJ2KJKU4Z6U3,upperdir=/var/lib/docker/overlay2/3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da/diff,workdir=/var/lib/docker/overlay2/3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da/work)root@7d01751deb92:/#
我們可以看出,overlay2將lowerdir
、upperdir
、workdir
聯合掛載,形成最終的merged
掛載點,其中lowerdir
是鏡像只讀層,upperdir
是容器可讀可寫層,workdir
是執行涉及修改lowerdir
執行copy_up
操作的中轉層(例如,upperdir
中不存在,需要從lowerdir
中進行複製,該過程暫未詳細了解,遇到了再分析),接著我們可以做一個實驗,我們在容器中通過以下命令創建一個文件:
root@7d01751deb92:/# touch test.txt
接下來我們觀察容器的可讀寫層,與鏡像的只讀層:
? 3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da ll difftotal 0-rw-r--r-- 1 root root 0 8月 13 20:54 test.txt? 3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da ll mergedtotal 76Kdrwxr-xr-x 2 root root 4.0K 7月 25 04:53 bindrwxr-xr-x 2 root root 4.0K 4月 24 16:34 bootdrwxr-xr-x 1 root root 4.0K 8月 13 20:26 devdrwxr-xr-x 1 root root 4.0K 8月 13 20:26 etcdrwxr-xr-x 2 root root 4.0K 4月 24 16:34 homedrwxr-xr-x 8 root root 4.0K 7月 25 04:51 libdrwxr-xr-x 2 root root 4.0K 7月 25 04:52 lib64drwxr-xr-x 2 root root 4.0K 7月 25 04:51 mediadrwxr-xr-x 2 root root 4.0K 7月 25 04:51 mntdrwxr-xr-x 2 root root 4.0K 7月 25 04:51 optdrwxr-xr-x 2 root root 4.0K 4月 24 16:34 procdrwx------ 2 root root 4.0K 7月 25 04:53 rootdrwxr-xr-x 1 root root 4.0K 7月 27 06:20 rundrwxr-xr-x 1 root root 4.0K 7月 27 06:20 sbindrwxr-xr-x 2 root root 4.0K 7月 25 04:51 srvdrwxr-xr-x 2 root root 4.0K 4月 24 16:34 sys-rw-r--r-- 1 root root 0 8月 13 20:54 test.txtdrwxrwxrwt 2 root root 4.0K 7月 25 04:53 tmpdrwxr-xr-x 1 root root 4.0K 7月 25 04:51 usrdrwxr-xr-x 1 root root 4.0K 7月 25 04:53 var? 3895f4ddbd45f65e509ed996d39536d1737647bf1b70c2b9c82b6765b2e376da ll ../225c757add2a395c0cfc47e1bc4472bf8fccf9dedd42f76f99b21c7637cb2a76/difftotal 76Kdrwxr-xr-x 2 root root 4.0K 7月 25 04:53 bindrwxr-xr-x 2 root root 4.0K 4月 24 16:34 bootdrwxr-xr-x 4 root root 4.0K 7月 25 04:51 devdrwxr-xr-x 29 root root 4.0K 7月 25 04:53 etcdrwxr-xr-x 2 root root 4.0K 4月 24 16:34 homedrwxr-xr-x 8 root root 4.0K 7月 25 04:51 libdrwxr-xr-x 2 root root 4.0K 7月 25 04:52 lib64drwxr-xr-x 2 root root 4.0K 7月 25 04:51 mediadrwxr-xr-x 2 root root 4.0K 7月 25 04:51 mntdrwxr-xr-x 2 root root 4.0K 7月 25 04:51 optdrwxr-xr-x 2 root root 4.0K 4月 24 16:34 procdrwx------ 2 root root 4.0K 7月 25 04:53 rootdrwxr-xr-x 4 root root 4.0K 7月 25 04:51 rundrwxr-xr-x 2 root root 4.0K 7月 25 04:53 sbindrwxr-xr-x 2 root root 4.0K 7月 25 04:51 srvdrwxr-xr-x 2 root root 4.0K 4月 24 16:34 sysdrwxrwxrwt 2 root root 4.0K 7月 25 04:53 tmpdrwxr-xr-x 10 root root 4.0K 7月 25 04:51 usrdrwxr-xr-x 11 root root 4.0K 7月 25 04:53 var
可以發現,新創建的文件被存在了上述位置,而此時如果我們通過以下命令:
docker commit CONTAINER_ID
提交容器更改,則會將該容器的當前可讀可寫層轉化為只讀層,更新鏡像。總結一下,鏡像大體上,可以認為是多個只讀層通過某些特定的方式組織起來,而容器則是在其之上的一個可讀寫層,我們可以保存一個可讀寫層的更改,將它轉化為一個只讀層。
以上是對鏡像與容器,及其存儲驅動overlay2的一個簡要概述。
下一篇還沒想好是什麼。
推薦閱讀:
※從無到有:利用Docker部署項目
※記錄一次Linux Docker的部署過程
※微服務那麼火,我也該用微服務嗎?
※Docker 學習新手筆記:從入門到放棄
※跟我一起學docker(五)--倉庫
TAG:Docker | 容器 | TensorFlow |