docker之鏡像結構原理

原文鏈接: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 的內容:
第八篇:Docker鏡像結構原理
第二行 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

第八篇:Docker鏡像結構原理
① 新鏡像不再是從 scratch 開始,而是直接在 Debian base 鏡像上構建。
② 安裝 emacs 編輯器。
③ 安裝 apache2。
④ 容器啓動時運行 bash。

構建過程如下圖所示:
第八篇:Docker鏡像結構原理
可以看到,新鏡像是從 base 鏡像一層一層疊加生成的。每安裝一個軟件,就在現有鏡像的基礎上增加一層。

問什麼 Docker 鏡像要採用這種分層結構呢?
最大的一個好處就是 - 共享資源

比如:有多個鏡像都從相同的 base 鏡像構建而來,那麼 Docker Host 只需在磁盤上保存一份 base 鏡像;同時內存中也只需加載一份 base 鏡像,就可以爲所有容器服務了。而且鏡像的每一層都可以被共享。

這時可能就有人會問了:如果多個容器共享一份基礎鏡像,當某個容器修改了基礎鏡像的內容,比如 /etc 下的文件,這時其他容器的 /etc 是否也會被修改?
答案:不會!因爲修改會被限制在單個容器內。

這就是我們接下來要學習的容器 Copy-on-Write 特性。

三、容器的可寫層

當容器啓動時,一個新的可寫層被加載到鏡像的頂部。
這一層通常被稱作“容器層”,“容器層”之下的都叫“鏡像層”。
第八篇:Docker鏡像結構原理
所有對容器的改動 - 無論添加、刪除、還是修改文件都只會發生在容器層中。
只有容器層是可寫的,容器層下面的所有鏡像層都是隻讀的
下面我們深入討論容器層的細節。
鏡像層數量可能會很多,所有鏡像層會聯合在一起組成一個統一的文件系統。如果不同層中有一個相同路徑的文件,比如 /a,上層的 /a 會覆蓋下層的 /a,也就是說用戶只能訪問到上層中的文件 /a。在容器層中,用戶看到的是一個疊加之後的文件系統。

  1. 添加文件
    在容器中創建文件時,新文件被添加到容器層中。

  2. 讀取文件
    在容器中讀取某個文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,打開並讀入內存。

  3. 修改文件
    在容器中修改已存在的文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,立即將其複製到容器層,然後修改之。

  4. 刪除文件
    在容器中刪除文件時,Docker 也是從上往下依次在鏡像層中查找此文件。找到後,會在容器層中記錄下此刪除操作。

只有當需要修改時才複製一份數據,這種特性被稱作 Copy-on-Write。可見,容器層保存的是鏡像變化的部分,不會對鏡像本身進行任何修改。
這樣就解釋了我們前面提出的問題:容器層記錄對鏡像的修改,所有鏡像層都是隻讀的,不會被容器修改,所以鏡像可以被多個容器共享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章