一、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 初學者都會有這個疑問。
下面來了解下Linux 作業系統由核心空間和使用者空間組成,如下圖所示:
rootfs
核心空間是 kernel,Linux 剛啟動時會加載 bootfs 檔案系統,之後 bootfs 會被解除安裝掉。
使用者空間的檔案系統是 rootfs,包含我們熟悉的 /dev, /proc, /bin 等目錄。
對于 base 鏡像來說,底層直接用 Host 的 kernel,自己隻需要提供 rootfs 就行了。
而對于一個精簡的 OS,rootfs 可以很小,隻需要包括最基本的指令、工具和程式庫就可以了。相比其他 Linux 發行版,CentOS 的 rootfs 已經算臃腫的了,alpine 還不到 10MB。
我們平時安裝的 CentOS 除了 rootfs 還會選裝很多軟體、服務、圖形桌面等,需要好幾個 GB 就不足為奇了。
base 鏡像提供的是最小安裝的 Linux 發行版。
下面是 CentOS 鏡像的 Dockerfile 的内容:
第二行 ADD 指令添加到鏡像的 tar 包就是 CentOS 7 的 rootfs。在制作鏡像時,這個 tar 包會自動解壓到 / 目錄下,生成 /dev, /porc, /bin 等目錄。
注:可在 Docker Hub 的鏡像描述頁面中檢視 Dockerfile 。
支援運作多種 Linux OS
不同 Linux 發行版的差別主要就是 rootfs。
比如 Ubuntu 14.04 使用 upstart 管理服務,apt 管理軟體包;而 CentOS 7 使用 systemd 和 yum。這些都是使用者空間上的差別,Linux kernel 差别不大。
是以 Docker 可以同時支援多種 Linux 鏡像,模拟出多種作業系統環境。
上圖 Debian 和 BusyBox上層提供各自的 rootfs,底層共用 Docker Host 的 kernel。
注意:base 鏡像隻是在使用者空間與發行版一緻,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 特性。
三、容器的可寫層
-
讀取檔案
在容器中讀取某個檔案時,Docker 會從上往下依次在各鏡像層中查找此檔案。一旦找到,打開并讀入記憶體。
-
修改檔案
在容器中修改已存在的檔案時,Docker 會從上往下依次在各鏡像層中查找此檔案。一旦找到,立即将其複制到容器層,然後修改之。
-
删除檔案
在容器中删除檔案時,Docker 也是從上往下依次在鏡像層中查找此檔案。找到後,會在容器層中記錄下此删除操作。