一篇文章帶你吃透 Docker 原理

以終為始發表於2020-06-03

容器的實現原理

從本質上,容器其實就是一種沙盒技術。就好像把應用隔離在一個盒子內,使其執行。因為有了盒子邊界的存在,應用於應用之間不會相互干擾。並且像集裝箱一樣,拿來就走,隨處執行。其實這就是 PaaS 的理想狀態。

實現容器的核心,就是要生成限制應用執行時的邊界。我們知道,編譯後的可執行程式碼加上資料,叫做程式。而把程式執行起來後,就變成了程式,也就是所謂的應用。如果能在應用啟動時,給其加上一個邊界,這樣不就能實現期待的沙盒嗎?

在 Linux 中,實現容器的邊界,主要有兩種技術 CgroupsNamespace. Cgroups 用於對執行的容器進行資源的限制,Namespace 則會將容器隔離起來,實現邊界。

這樣看來,容器只是一種被限制的了特殊程式而已。

容器的隔離:Namespace

在介紹 Namespace 前,先看一個實驗:

# 使用 python3.6.8 的官方映象,建立了一個執行 django 的環境
# 進入該容器後,使用 ps 命令,檢視執行的程式
root@8729260f784a:/src# ps -A
  PID TTY          TIME CMD
    1 ?        00:01:22 gunicorn
   22 ?        00:01:20 gunicorn
   23 ?        00:01:24 gunicorn
   25 ?        00:01:30 gunicorn
   27 ?        00:01:16 gunicorn
   41 pts/0    00:00:00 bash
   55 pts/0    00:00:00 ps

可以看到,容器內 PID =1 的程式,是 gunicorn 啟動的 django 應用。熟悉 Linux 的同學都知道,PID =1 的程式是系統啟動時的第一個程式,也稱 init 程式。其他的程式,都是由它管理產生的。而此時,PID=1 確實是 django 程式。

接著,退出容器,在宿主機執行 ps 命令

# 環境為 Centos7
[root@localhost ~]# ps -ef | grep gunicorn
root      9623  8409  0 21:29 pts/0    00:00:00 grep --color=auto gunicorn
root     30828 30804  0 May28 ?        00:01:22 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi
root     31171 30828  0 May28 ?        00:01:20 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi
root     31172 30828  0 May28 ?        00:01:24 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi
root     31174 30828  0 May28 ?        00:01:30 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi
root     31176 30828  0 May28 ?        00:01:16 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi

如果以宿主機的視角,發現 django 程式 PID 變成了 30828. 這也就不難證明,在容器中,確實做了一些處理。把明明是 30828 的程式,變成了容器內的第一號程式,同時在容器還看不到宿主機的其他程式。這也說明容器內的環境確實是被隔離了。

這種處理,其實就是 Linux 的 Namespace 機制。比如,上述將 PID 變成 1 的方法就是通過PID Namespace。在 Linux 中建立執行緒的方法是 clone, 在其中指定 CLONE_NEWPID 引數,這樣新建立的程式,就會看到一個全新的程式空間。而此時這個新的程式,也就變成了 PID=1 的程式。

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL); 

在 Linux 類似於 PID Namespace 的引數還有很多,比如:

容器的限制:Cgroups

通過 Namespace 技術,我們實現了容器和容器間,容器與宿主機之間的隔離。但這還不夠,想象這樣一種場景,宿主機上執行著兩個容器。雖然在容器間相互隔離,但以宿主機的視角來看的話,其實兩個容器就是兩個特殊的程式,而程式之間自然存在著競爭關係,自然就可以將系統的資源吃光。當然,我們不能允許這麼做的。

Cgroups 就是 Linux 核心中用來為程式設定資源的一個技術。

Linux Cgroups 全稱是 Linux Control Group,主要的作用就是限制程式組使用的資源上限,包括 CPU,記憶體,磁碟,網路頻寬。

還可以對程式進行優先順序設定,審計,掛起和恢復等操作。

在之前的版本中,可通過 libcgroup tools 來管理 cgroup, 在 RedHat7 後,已經改為通過 systemctl 來管理。

我們知道,systemd 在 Linux 中的功能就是管理系統的資源。而為了管理的方便,衍生出了一個叫 Unit 的概念,比如一個 unit 可以有比較寬泛的定義,比如可以表示抽象的服務,網路的資源,裝置,掛載的檔案系統等。為了更好的區分,Linux 將 Unit 的型別主要分為 12 種。

型別 作用
.automount 用於自動掛載配置的掛載點
.swap 描述系統的交換區,反映了裝置或檔案的路徑
.target 在系統啟動或者改變狀態時,為其他 unit 提供同步點
.path 定義的檔案路徑,用於啟用。
.service 一個服務或者一個應用,具體定義在配置檔案中。
.socket 一個網路或者 IPC socket,FIFO buffer.
.device 描述一個需要被 systemd udevsysfs 檔案系統管理的裝置
.mount 定義的掛載點
.timer 定時器
.snapshot systemctl snapshot 命令自動建立的單元
.slice 用於關聯 Linux Control Group 節點,根據關聯的 slice 來限制程式。一個管理單元的組。Slice 並不包含任何程式,僅僅管理由 service 和 scope 組成的層級結構。
.scope systemd 從 bus 介面收到訊息後自動建立。Scope 封裝了任意程式通過 fork() 函式開啟或停止的程式,並且在 systemd 執行時註冊。例如:使用者 sessions,容器和虛擬機器。

Cgroup 中,主要使用的是 slice, scope and service 這三種型別。

如建立一個臨時 cgroup, 然後對其啟動的程式進行資源限制:

 # 建立一個叫 toptest 的服務,在名為 test 的 slice 中執行
[root@localhost ~]# systemd-run --unit=toptest --slice=test top -b
Running as unit toptest.service.

現在 toptest 的服務已經執行在後臺了

# 通過 systemd-cgls 來檢視 Cgroup 的資訊
[root@localhost ~]#  systemd-cgls
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
├─test.slice
│ └─toptest.service
│   └─6490 /usr/bin/top -b

# 通過 systemctl status 檢視服務的狀態
[root@localhost ~]# systemctl status toptest
● toptest.service - /usr/bin/top -b
   Loaded: loaded (/run/systemd/system/toptest.service; static; vendor preset: disabled)
  Drop-In: /run/systemd/system/toptest.service.d
           └─50-Description.conf, 50-ExecStart.conf, 50-Slice.conf
   Active: active (running) since Tue 2020-06-02 14:01:01 CST; 3min 50s ago
 Main PID: 6490 (top)
   CGroup: /test.slice/toptest.service
           └─6490 /usr/bin/top -b

現在對執行的 toptest 服務進行資源的限制。

# 先看下,沒有被限制前的 Cgroup 的資訊, 6490 為程式 PID
[root@localhost ~]# cat /proc/6490/cgroup
11:pids:/test.slice
10:blkio:/test.slice
9:hugetlb:/
8:cpuset:/
7:memory:/test.slice
6:devices:/test.slice
5:net_prio,net_cls:/
4:perf_event:/
3:freezer:/
2:cpuacct,cpu:/test.slice
1:name=systemd:/test.slice/toptest.service

# 對其使用的 CPU 和 記憶體進行限制
systemctl set-property toptest.service CPUShares=600 MemoryLimit=500M

# 再次檢視 Cgroup 的資訊,發現在 cpu 和 memory 追加了一些內容。
[root@localhost ~]# cat /proc/6490/cgroup
11:pids:/test.slice
10:blkio:/test.slice
9:hugetlb:/
8:cpuset:/
7:memory:/test.slice/toptest.service
6:devices:/test.slice
5:net_prio,net_cls:/
4:perf_event:/
3:freezer:/
2:cpuacct,cpu:/test.slice/toptest.service
1:name=systemd:/test.slice/toptest.service

這時可以在 /sys/fs/cgroup/memory/test.slice/sys/fs/cgroup/cpu/test.slice 目錄下,多出了一個叫 toptest.service 的目錄。

在其目錄下 cat toptest.service/cpu.shares 可以發現,裡面的 CPU 被限制了 600.

回到 Docker,其實 docker 和我們上面做的操作基本一致,具體需要限制哪些資源就是在 docker run 裡指定:

$ docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash

關於 docker 具體的限制,可以在 sys/fs/cgroup/cpu/docekr/ 等資料夾來檢視。

容器的檔案系統:容器映象 - rootfs

現在我們知道,容器技術的核心就是通過 Namespace 限制了容器看到的視野,通過 Cgroup限制了容器可訪問的資源。 但關於 Mount Namespace 還有一些特殊的地方,需要著重關注下。

Mount Namespace 特殊之處在於,除了在修改時需要程式對檔案系統掛載點的認證,還需要顯式宣告需要掛載那些目錄。在 Linux 系統中,有一個叫 chroot 的命令,可以改變程式的根目錄到指定的位置。而 Mount Namespace 正是基於 chroot 的基礎上發展出來的。

在容器內,應該看到完全獨立的檔案系統,而且不會受到宿主機以及其他容器的影響。這個獨立的檔案系統,就叫做容器映象。它還有一個更專業的名字叫 rootfs. rootfs 中包含了一個作業系統所需要的檔案,配置和目錄,但並不包含系統核心。 因為在 Linux 中,檔案和核心是分開存放的,作業系統只有在開啟啟動時才會載入指定的核心。這也就意味著,所有的容器都會共享宿主機上作業系統的核心。

在 PaaS 時代,由於雲端和本地的環境不同,應用打包的過程,一直是比較痛苦的過程。但有了 rootfs ,這個問題就被很好的解決了。因為在映象內,打包的不僅僅是應用,還有所需要的依賴,都被封裝在一起。這就解決了無論是在哪,應用都可以很好的執行的原因。

不光這樣,rootfs 還解決了可重用性的問題,想象這個場景,你通過 rootfs 打包了一個包含 java 環境的 centos 映象,別人需要在容器內跑一個 apache 的服務,那麼他是否需要從頭開始搭建 java 環境呢?docker 在解決這個問題時,引入了一個叫層的概念,每次針對 rootfs 的修改,都只儲存增量的內容,而不是 fork 一個新映象。

層級的想法,同樣來自於 Linux,一個叫 union file system (聯合檔案系統)。它最主要的功能就是將不同位置的目錄聯合掛載到同一個目錄下。對應在 Docker 裡面,不同的環境則使用了不同的聯合檔案系統。比如 centos7 下最新的版本使用的是 overlay2,而 Ubuntu 16.04 和 Docker CE 18.05 使用的是 AuFS.

可以通過 docker info 來查詢使用的儲存驅動,我這裡的是 overlay2

[root@localhost ~]# docker info
Client:
 Debug Mode: false

Server:
 Containers: 4
  Running: 4
  Paused: 0
  Stopped: 0
 Images: 4
 Server Version: 19.03.8
 Storage Driver: overlay2

接著我們來了解下,Overlay2 的檔案系統在 docker 中是如何使用的?

Overlay2

在 Linux 的主機上,OverlayFS 一般有兩個目錄,但在顯示時具體會顯示為一個目錄。這兩個目錄被稱為層,聯合在一起的過程稱為 union mount. 在其下層的目錄稱為 lowerdir, 上層的目錄稱為 upperdir. 兩者聯合後,暴露出來的檢視稱為 view. 聽起來有點抽象,先看下整體結構:

overlayfs lowerdir, upperdir, merged

可以看到,lowerdir 其實對應的就是映象層,upperdir 對應的就是容器器。而 merged 對應的就是兩者聯合掛載之後的內容。而且我們發現,當映象層和容器層擁有相同的檔案時,會以容器層的檔案為準(最上層的檔案為準)。通常來說,overlay2 支援最多 128 lower 層。

下面實際看下容器層和映象具體的體現,我這臺 linux 主機上,執行著 4 個 container。

Docker 一般的儲存位置在 /var/lib/docker,先看下里面的結構:

[root@localhost docker]# ls -l /var/lib/docker
total 16
drwx------.  2 root root   24 Mar  4 03:39 builder
drwx--x--x.  4 root root   92 Mar  4 03:39 buildkit
drwx------.  7 root root 4096 Jun  1 10:36 containers
drwx------.  3 root root   22 Mar  4 03:39 image
drwxr-x---.  3 root root   19 Mar  4 03:39 network
drwx------. 69 root root 8192 Jun  1 15:01 overlay2
drwx------.  4 root root   32 Mar  4 03:39 plugins
drwx------.  2 root root    6 Jun  1 15:00 runtimes
drwx------.  2 root root    6 Mar  4 03:39 swarm
drwx------.  2 root root    6 Jun  1 15:01 tmp
drwx------.  2 root root    6 Mar  4 03:39 trust
drwx------.  3 root root   45 May 18 10:28 volumes

需要著重關注的是 container, image, overlay2 這幾個資料夾。

  • container:這個不用多說,正在執行或建立的容器會在這個目錄下。
  • image:對應記錄的就是映象。
  • overlay2:記錄的是每個映象下包含的 lowerrdir.

之前提到,unionfs 的實現可能有多種,比如 overlay2,aufs,devicemapper 等。那麼自然在 image 資料夾下,就會存在多種驅動的資料夾,:

image/
└── overlay2
    ├── distribution
    ├── imagedb
    │   ├── content
    │   └── metadata
    ├── layerdb
    │   ├── mounts
    │   ├── sha256
    │   └── tmp
    └── repositories.json

這裡的 imagedblayerdb, 就是儲存後設資料的地方。之前我們瞭解到,容器的檔案系統構成就是通過 image 層 和 container 層聯合構成的,而每個 image 可能是由多個層構成。這就意味著,每個層可能會被多個 image 引用。那麼之間是如何關聯的呢?答案就在 imagedb 這個檔案下。

這裡我以 mysql 映象為例:

# 檢視 mysql 的映象 id
[root@localhost docker]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ctg/mysql           5.7.29              84164b03fa2e        3 months ago        456MB

# 進入到 imagedb/content/sha256 目錄, 可以找到對應的映象 id
[root@localhost docker]# ls -l image/overlay2/imagedb/content/sha256/
...
-rw-------. 1 root root  6995 Apr 27 02:45 84164b03fa2ecb33e8b4c1f2636ec3286e90786819faa4d1c103ae147824196a

# 接著看下里面記錄的內容, 這裡擷取有用的部分
cat  image/overlay2/imagedb/content/sha256/84164b03fa2ecb33e8b4c1f2636ec3286e90786819faa4d1c103ae147824196a
{
.........
  "os": "linux",
  "rootfs": {
    "type": "layers",
    "diff_ids": [
      "sha256:f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da",
      "sha256:a9f6b7c7101b86ffaa53dc29638e577dabf5b24150577a59199d8554d7ce2921",
      "sha256:0c615b40cc37ed667e9cbaf33b726fe986d23e5b2588b7acbd9288c92b8716b6",
      "sha256:ad160f341db9317284bba805a3fe9112d868b272041933552df5ea14647ec54a",
      "sha256:1ea6ef84dc3af6506c26753e9e2cf7c0d6c1c743102b85ebd3ee5e357d7e9bc4",
      "sha256:6fce4d95d4af3777f3e3452e5d17612b7396a36bf0cb588ba2ae1b71d139bab9",
      "sha256:6de3946ea0137e75dcc43a3a081d10dda2fec0d065627a03800a99e4abe2ede4",
      "sha256:a35a4bacba4d5402b85ee6e898b95cc71462bc071078941cbe8c77a6ce2fca62",
      "sha256:1ff9500bdff4455fa89a808685622b64790c321da101d27c17b710f7be2e0e7e",
      "sha256:1cf663d0cb7a52a3a33a7c84ff5290b80966921ee8d3cb11592da332b4a9e016",
      "sha256:bcb387cbc5bcbc8b5c33fbfadbce4287522719db43d3e3a286da74492b7d6eca"
    ]
  }
}

可以看到 mysql 映象由 11 層組成,其中 f2cb 是最低層,bcb3 是最上層。

接著,我們看下 layerdb 的內容:

[root@localhost docker]# ls -l  image/overlay2/layerdb/
total 8
drwxr-xr-x.  6 root root 4096 May 13 13:38 mounts
drwxr-xr-x. 39 root root 4096 Apr 27 02:51 sha256
drwxr-xr-x.  2 root root    6 Apr 27 02:51 tmp

# 首先看下 sha256 目錄下的內容
[root@localhost docker]# ls -l  image/overlay2/layerdb/sha256/
total 0
....
drwx------. 2 root root 71 Apr 27 02:45 bbb9cccab59a16cb6da78f8879e9d07a19e3a8d49010ab9c98a2c348fa116c87
drwx------. 2 root root 71 Apr 27 02:45 f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da
....

可以發現,在這裡僅能找到最底層的層 ID,原因在於層之間的關聯是通過 chainID 的方式儲存的,簡單來說就是通過 sha256 演算法後能計算出一層的容器 id.

比如這裡,最底層 id 是 f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da , 上一層 id 是 a9f6b7c7101b86ffaa53dc29638e577dabf5b24150577a59199d8554d7ce2921, 那麼對應在 sha256 目錄下的下一層 id 的計算方法就是:

[root@localhost docker]# echo -n "sha256:f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da sha256:a9f6b7c7101b86ffaa53dc29638e577dabf5b24150577a59199d8554d7ce2921" | sha256sum
bbb9cccab59a16cb6da78f8879e9d07a19e3a8d49010ab9c98a2c348fa116c87  -

接著我們可以在 sha256 目錄下,找到 bbb9.. 這層的內容。

OK,現在我們已經把映象和層關聯起來,但之前說過,image 下村的都是後設資料。真實的 rootfs 其實在另一個地方 - /docker/overlay2 下。

# 通過查詢 cache-id,得到就是真實的 rootfs 層
[root@localhost docker]# cat  image/overlay2/layerdb/sha256/f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da/cache-id
2996b24990e75cbd304093139e665a45d96df8d7e49334527827dcff820dbf16[

進入到 /docker/overlay2 下檢視:

[root@localhost docker]# ls -l overlay2/
total 4
...
drwx------. 3 root root   47 Apr 27 02:45 2996b24990e75cbd304093139e665a45d96df8d7e49334527827dcff820dbf16
...
drwx------. 2 root root 4096 May 13 13:38 l

這樣真實的 rootfs 層也被找到了。

這裡重新梳理下,我們先是在 mage/overlay2/imagedb/content/sha256/ ,根據 image id 檢視該 image 具有所有的層ID,然後根據最底層ID和上層ID通過 sha256 計算得到,引用的上一層 ID, 依次類推,關聯所有的層。最後通過每一層的 cache-id,將後設資料和真實的 rootfs 層資料對應起來了。

最後總結一下,rootfs 的構成。

每個 rootfs 由映象層(lowerdir)和 容器層(upperdir)構成,其中映象層只能只讀,而容器層則能讀寫。而且映象層可有最多128層構成。

其實,rootfs 構成還有另外一層,但由於在進行提交或編譯時,不會把這層加進去,所以就沒把這層算在rootfs裡面,但實際上存在的。

在之前我們檢視 ls -l /var/lib/docker/overlay2/ 下映象層,會看到好幾個以 -init 結尾的目錄,而且數量恰好等於容器的數量。這層夾在映象層之上,容器層之下。是由 docker 內部單獨生成的一層,專門用於存放 etc/hosts、/etc/resolv.conf 等配置資訊。存在的目的,是由於使用者在容器啟動時,需要配置一些特定的值,比如 hostname,dns 等,但這些配置僅對當前容器有效,放到其他環境下自然有別的配置,所以這層被單獨拿出來,在提交映象時,忽略這一層。

容器與虛擬機器技術的對比

下面這張圖是 docker 官方中,擷取下來的,基於上面我們學習的內容,重新分析下 docker 和 傳統 VM 的區別:

遷移性和效能:

  • 傳統 VM: 需要基於 Hypervisor 的硬體虛擬化技術,模擬出 CPU,記憶體等硬體。然後在其上搭建一套完整的作業系統,自然在效能上會有很大的損失。遷移自然更不用說,傳統的 ova 匯出後就是一個完整的作業系統。
  • Docker:Docker 將 Hypervisor 的位置換成自己的 Docekr Engine. 然後執行的容器僅僅是一個特殊的程式,自然效能不會有太大的損失。並且可以應用和其所需要的系統檔案打包成映象,無論在哪讀可以正常執行,而且相對於 ova 來說體積也小了更多。(需要核心支援)

一般來說,執行著 CentOS 的 KVM,啟動後,在不做優化的前提下,需要佔用 100~200 M 記憶體。在加上使用者對宿主機的呼叫,需要通過虛擬化軟體攔截和處理,又是一層效能損耗,特別是對計算資源,網路和磁碟I/O等。

隔離性:

  • 傳統 VM:由於是虛擬化出一套完整的作業系統,所以隔離性非常好。比如微軟的 Azure 平臺,就是在 Windows 伺服器上,虛擬出大量的 Linux 虛擬機器。

  • Docker:在隔離性上相差就很多了,因為本身上容器就是一種程式,而所有的程式都需要共享一個系統核心。

    • 這就意味著,在 Windows 上執行 Linux 容器,或者 Linux 宿主機執行高版本核心的容器就無法實現。

    • 在 Linux 核心中,有許多資源和物件不能 Namespace 化,如時間,比如通過 settimeofday(2) 系統呼叫 修改時間,整個宿主機的實際都會被修改。

    • 安全的問題,共享宿主機核心的事實,容器暴露出的攻擊面更大。

資源的限制:

  • 傳統 VM:非常便於管理,控制資源的使用,依賴於虛擬的作業系統。
  • Docker:由於 docker 內資源的限制通過 Cgroup 實現,而 Cgroup 有很多不完善的地方,比如
    • 對 /proc 的處理問題。進入容器後,執行 top 命令,看到的資訊和宿主機是一樣的,而不是配置後的容器的資料。(可以通過 lxcfs 修正)。
    • 在執行 java 程式時,給容器內設定的記憶體為 4g,使用預設的 jvm 配置。而預設的 jvm 讀取的記憶體是宿主機(可能大於 4g),這樣就會出現 OOM 的情況。

解決的問題

  1. 容器是如何進行隔離的?

    在建立新程式時,通過 Namespace 技術,如 PID namespaces 等,實現隔離性。讓執行後的容器僅能看到本身的內容。

    比如,在容器執行時,會預設加上 PID, UTS, network, user, mount, IPC, cgroup 等 Namespace.

  2. 容器是如何進行資源限制的?

    通過 Linux Cgroup 技術,可為每個程式設定限制的 CPU,Memory 等資源,進而設定程式訪問資源的上限。

  3. 簡述下 docker 的檔案系統?

    docker 的檔案系統稱為 rootfs,它的實現的想法來自與 Linux unionFS 。將不同的目錄,掛載到一起,形成一個獨立的檢視。並且 docker 在此基礎上引入了層的概念,解決了可重用性的問題。

    在具體實現上,rootfs 的儲存區分根據 linux 核心和 docker 本身的版本,分為 overlay2 , overlay, aufs, devicemapper 等。rootfs(映象)其實就是多個層的疊加,當多層存在相同的檔案時,上層的檔案會將下層的檔案覆蓋掉。

  4. 容器的啟動過程?

    1. 指定 Linux Namespace 配置
    2. 設定指定的 Cgroups 引數
    3. 切換程式的根目錄
  5. 容器內執行多個應用的問題?

    首先更正一個概念,我們都說容器是一個單程式的應用,其實這裡的單程式不是指在容器中只允許著一個程式,而是指只有一個程式時可控的。在容器內當然可以使用 ping,ssh 等程式,但這些程式時不受 docker 控制的。

    容器內的主程式,也就是 pid =1 的程式,一般是通過 DockerFile 中 ENTRYPOINT 或者 CMD 指定的。如果在一個容器內如果存在著多個服務(程式),就可能出現主程式正常執行,但是子程式退出掛掉的問題,而對於 docker 來說,僅僅控制主程式,無法對這種意外的情況作出處理,也就會出現,容器明明正常執行,但是服務已經掛掉的情況,這時編排系統就變得非常困難。而且多個服務,在也不容易進行排障和管理。

    所以如果真的想要在容器內執行多個服務,一般會通過帶有 systemd 或者 supervisord 這類工具進行管理,或者通過 --init 方法。其實這些方法的本質就是讓多個服務的程式擁有同一個父程式。

    但考慮到容器本身的設計,就是希望容器和服務能夠同生命週期。所以這樣做,有點背道而馳的意味。

    控制(回收和生命週期的管理)

參考

Cgroup 介紹

Overlay2介紹

docker 官網

在一個容器內搭建多個服務

相關文章