原文鏈接:https://blog.51cto.com/liuleis/2070461
文章目錄
一、base 鏡像
base 鏡像含義:
1. 不依賴其他鏡像,從 scratch 構建。
2. 其他鏡像可以之爲基礎進行擴展。
base 鏡像的通常都是各種 Linux 發行版的 Docker 鏡像,比如 Ubuntu, Debian, CentOS 等,以 CentOS 爲例學習 base 鏡像包含哪些內容。
下載鏡像:
[root@docker ~]# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
af4b0a2388c6: Pull complete
Digest: sha256:2671f7a3eea36ce43609e9fe7435ade83094291055f1c96d9d1d1d7c0b986a5d
Status: Downloaded newer image for centos:latest ##下載centos最新鏡像
查看鏡像信息:
[root@docker ~]# docker images centos
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest ff426288ea90 4 weeks ago 207MB
使用docker pull centos下載最新版本的Centos鏡像也就207M左右,而我們平時下載一個原生的centos鏡像都是4G,對於 Docker 初學者都會有這個疑問。
Base鏡像提供的是最小化的發行版本,且不通的Base鏡像共用bootfs,各自有自己的rootfs
rootfs
內核空間是 kernel,Linux 剛啓動時會加載 bootfs 文件系統,之後 bootfs 會被卸載掉。
用戶空間的文件系統是 rootfs,包含我們熟悉的 /dev, /proc, /bin 等目錄。
對於 base 鏡像來說,底層直接用 Host 的 kernel,自己只需要提供 rootfs 就行了。
而對於一個精簡的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序庫就可以了。
base 鏡像提供的是最小安裝的 Linux 發行版。
下面是 CentOS 鏡像的 Dockerfile 的內容:
第二行 ADD 指令添加到鏡像的 tar 包就是 CentOS 7 的 rootfs。在製作鏡像時,這個 tar 包會自動解壓到 / 目錄下,生成 /dev, /porc, /bin 等目錄。
注:可在 Docker Hub 的鏡像描述頁面中查看 Dockerfile 。
不同 Linux 發行版的區別主要就是 rootfs。
比如 Ubuntu 14.04 使用 upstart 管理服務,apt 管理軟件包;而 CentOS 7 使用 systemd 和 yum。這些都是用戶空間上的區別,Linux kernel 差別不大。
對於linux上不同版本的問題,docker可以同時運行多個rootfs.
上圖 Debian 和 BusyBox上層提供各自的 rootfs,底層共用 Docker Host 的 kernel。
注意:base 鏡像只是在用戶空間與發行版一致,kernel 版本與髮型版是不同的,kernel 版本取決於宿主機。
[root@docker ~]# uname -r
3.10.0-514.el7.x86_64 ##Host kernel 爲 3.10.0-514
[root@docker ~]# docker run -ti centos ##啓動並進入 CentOS 容器
[root@263132669aa3 /]# cat /etc/redhat-release ##驗證容器是 CentOS 7
CentOS Linux release 7.4.1708 (Core)
[root@263132669aa3 /]# uname -r ##容器的 kernel 版本與 Host 一致
3.10.0-514.el7.x86_64
說明:
容器只能使用 Host 的 kernel,並且不能修改。所有容器都共用 host 的 kernel,在容器中沒辦法對 kernel 升級。如果容器對 kernel 版本有要求(比如應用只能在某個 kernel 版本下運行),則不建議用容器,這種場景虛擬機可能更合適。
二、鏡像的分層結構
Docker 支持通過擴展現有鏡像,創建新的鏡像。
實際上,Docker Hub 中 99% 的鏡像都是通過在 base 鏡像中安裝和配置需要的軟件構建出來的。比如我們現在構建一個新的鏡像,Dockerfile 如下:
[root@docker ~]# docker pull debian
Using default tag: latest
latest: Pulling from library/debian
723254a2c089: Pull complete
Digest: sha256:800943bdddf4511392fe453a0eb66eacadf322b392c521700bcac29c0b858582
Status: Downloaded newer image for debian:latest
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
liulei/centos 6.7 dc64de0c25c4 2 days ago 191MB
liulei/centos new dc64de0c25c4 2 days ago 191MB
liu/ubuntu v2 15caed782326 2 days ago 151MB
httpd latest 2e202f453940 13 days ago 179MB
ubuntu 16.04 0458a4468cbc 2 weeks ago 112MB
centos latest ff426288ea90 4 weeks ago 207MB
nginx latest 3f8a4339aadd 6 weeks ago 108MB
debian latest da653cee0545 8 weeks ago 100MB
hello-world latest f2a91732366c 2 months ago 1.85kB
training/webapp latest 6fae60ef3446 2 years ago 349MB
① 新鏡像不再是從 scratch 開始,而是直接在 Debian base 鏡像上構建。
② 安裝 emacs 編輯器。
③ 安裝 apache2。
④ 容器啓動時運行 bash。
構建過程如下圖所示:
可以看到,新鏡像是從 base 鏡像一層一層疊加生成的。每安裝一個軟件,就在現有鏡像的基礎上增加一層。
問什麼 Docker 鏡像要採用這種分層結構呢?
最大的一個好處就是 - 共享資源。
比如:有多個鏡像都從相同的 base 鏡像構建而來,那麼 Docker Host 只需在磁盤上保存一份 base 鏡像;同時內存中也只需加載一份 base 鏡像,就可以爲所有容器服務了。而且鏡像的每一層都可以被共享。
這時可能就有人會問了:如果多個容器共享一份基礎鏡像,當某個容器修改了基礎鏡像的內容,比如 /etc 下的文件,這時其他容器的 /etc 是否也會被修改?
答案:不會!因爲修改會被限制在單個容器內。
這就是我們接下來要學習的容器 Copy-on-Write 特性。
三、容器的可寫層
當容器啓動時,一個新的可寫層被加載到鏡像的頂部。
這一層通常被稱作“容器層”,“容器層”之下的都叫“鏡像層”。
所有對容器的改動 - 無論添加、刪除、還是修改文件都只會發生在容器層中。
只有容器層是可寫的,容器層下面的所有鏡像層都是隻讀的。
下面我們深入討論容器層的細節。
鏡像層數量可能會很多,所有鏡像層會聯合在一起組成一個統一的文件系統。如果不同層中有一個相同路徑的文件,比如 /a,上層的 /a 會覆蓋下層的 /a,也就是說用戶只能訪問到上層中的文件 /a。在容器層中,用戶看到的是一個疊加之後的文件系統。
-
添加文件
在容器中創建文件時,新文件被添加到容器層中。 -
讀取文件
在容器中讀取某個文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,打開並讀入內存。 -
修改文件
在容器中修改已存在的文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,立即將其複製到容器層,然後修改之。 -
刪除文件
在容器中刪除文件時,Docker 也是從上往下依次在鏡像層中查找此文件。找到後,會在容器層中記錄下此刪除操作。
只有當需要修改時才複製一份數據,這種特性被稱作 Copy-on-Write。可見,容器層保存的是鏡像變化的部分,不會對鏡像本身進行任何修改。
這樣就解釋了我們前面提出的問題:容器層記錄對鏡像的修改,所有鏡像層都是隻讀的,不會被容器修改,所以鏡像可以被多個容器共享。