深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs
通過這篇文章你可以了解到 Docker 容器的核心實現(xiàn)原理,包括 Namespace、Cgroups、Rootfs 等三個核心功能。
如果你對云原生技術(shù)充滿好奇,想要深入了解更多相關(guān)的文章和資訊,歡迎關(guān)注微信公眾號。
搜索公眾號【探索云原生】即可訂閱
后續(xù)文章會演示如何從零實現(xiàn)一個簡易的 Docker,這里先簡單了解下 Docker 的核心原理。
首先我們思考一個問題:容器與進程有何不同?
-
進程:就是程序運行起來后的計算機執(zhí)行環(huán)境的總和。
即:計算機內(nèi)存中的數(shù)據(jù)、寄存器里的值、堆棧中的指令、被打開的文件,以及各種設(shè)備的狀態(tài)信息的一個集合。
-
容器:核心就是通過約束和修改進程的動態(tài)表現(xiàn),從而為其創(chuàng)造出一個“邊界”。
對于 Docker 等大多數(shù) Linux 容器來說,Cgroups 技術(shù)是用來制造約束的主要手段,而 Namespace 技術(shù)則是用來修改進程視圖的主要方法。
1. 基于 Namespace 的視圖隔離
當我們通過 docker run -it 啟動并進入一個容器之后,會發(fā)現(xiàn)不論是進程、網(wǎng)絡(luò)還是文件系統(tǒng),好像都被隔離了,就像這樣:
[root@docker cpu]# docker run -it busybox
/ #
/ # ps
PID USER TIME COMMAND
1 root 0:00 sh
7 root 0:00 ps
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
120: eth0@if121: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ls
bin dev etc home lib lib64 proc root sys tmp usr var
- ps 命令看不到宿主機上的進程
- ip 命令也只能看到容器內(nèi)部的網(wǎng)卡
- ls 命令看到的文件好像也和宿主機不一樣
這就是 Docker 核心之一,借助 Linux Namespace 技術(shù)實現(xiàn)了視圖隔離。
看起來容器和宿主機隔離開了
在 Linux 下可以根據(jù)隔離的屬性不同分為不同的 Namespace :
- 1)PID Namespace
- 2)Mount Namespace
- 3)UTS Namespace
- 4)IPC Namespace
- 5)Network Namespace
- 6)User Namespace
通過不同類型的 Namespace 就可以實現(xiàn)不同資源的隔離,比如前面通過 ip a 只能看到容器中的網(wǎng)卡信息,就是通過 Network Namespace進行了隔離。
不過 Linux Namespace 技術(shù)實際上修改了應用進程看待整個計算機“視圖”,即它的“視線”被操作系統(tǒng)做了限制,只能“看到”某些指定的內(nèi)容。
我們只需要進入到對應 namespace 就可以突破這個隔離了,演示一下:
首先啟動一個 busybox,然后使用 ip a 查看網(wǎng)卡信息
[root@docker ~]# docker run --rm -it busybox /bin/sh
/ #
/ # ip a show eth0
116: eth0@if117: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
容器中 ip 為 172.17.0.2
然后在新終端中通過 nsenter 進入到該容器 network namespace 試試:
首先通過 docker inspect 命令找到容器對應的 PID
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
75e821d24261 busybox "/bin/sh" 32 seconds ago Up 31 seconds great_heisenberg
[root@docker ~]# docker inspect -f '{{.State.Pid}}' 75e821d24261
3533
然后使用 nsenter --net 命令進入該 PID 對應進程的 network namespace
[root@docker ~]# nsenter --target 3533 --net
[root@docker ~]# ip a show eth0
116: eth0@if117: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
可以看到,此時我們執(zhí)行 ip a 拿到的信息和在容器中執(zhí)行是完全一致的。
說明 Docker 確實是使用 namespace 進行隔離的。
這里順便提一下 Namespace 存在的問題,Namespace 最大的問題就是隔離得不徹底。
- 首先,既然容器只是運行在宿主機上的一種特殊的進程,那么多個容器之間使用的就還是同一個宿主機的操作系統(tǒng)內(nèi)核。
所以,也出現(xiàn)了像 Firecracker、gVisor、Kata 之類的沙箱容器,不使用共享內(nèi)核來提升安全性。
- 其次,在 Linux 內(nèi)核中,有很多資源和對象是不能被 Namespace 化的,最典型的例子就是:時間。
容器中修改了時間,實際修改的是宿主機的時間,會導致所有容器時間都被修改,因為是共享的。
2. 基于 Cgroups 的資源限制
docker run 啟動容器時可以通過增加 --cpus 或者 --memory flag 來指定 cpu、內(nèi)存限制。
就像這樣:通過 --cpus=0.5 限制只能使用 0.5 個核心,然后執(zhí)行一個 while 死循環(huán),并查看 cpu 占用情況。
[root@docker ~]# docker run -d --cpus 0.5 busybox sh -c "while true; do :; done"
d281fb2dc96cff371e9607197502c6ea3e04f4d0f3fd2ad38991c2321271736b
查看 CPU 占用情況
[root@docker ~]# top
top - 15:38:20 up 286 days, 4:02, 3 users, load average: 0.72, 0.46, 0.36
Tasks: 96 total, 2 running, 48 sleeping, 0 stopped, 0 zombie
%Cpu(s): 52.0 us, 0.0 sy, 0.0 ni, 47.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.3 st
KiB Mem : 1006956 total, 157876 free, 201008 used, 648072 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 538972 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3763 root 20 0 4392 400 336 R 50.0 0.0 0:49.43 sh
3790 root 20 0 162112 4416 3724 R 0.3 0.4 0:00.01 top
1 root 20 0 43884 4280 2552 S 0.0 0.4 1:56.18 systemd
可以看到,因為限制了 cpu 為 0.5,因此只占用了 0.5 核心,也就是 top 命令中看到的 50。
這就是 Docker 另一個核心功能,基于 Linux Cgroups 技術(shù)實現(xiàn)的資源限制。
Linux Cgroups 就是 Linux 內(nèi)核中用來為進程設(shè)置資源限制的一個重要功能。
Linux Cgroups 的全稱是 Linux Control Group。
它最主要的作用,就是限制一個進程組能夠使用的資源上限,包括 CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)帶寬等等。
在 Linux 中,Cgroups 給用戶暴露出來的操作接口是文件系統(tǒng),即它以文件和目錄的方式組織在操作系統(tǒng)的 /sys/fs/cgroup 路徑下,可以使用
mount -t cgroup 命令進行查看,大概長這樣:
[root@docker ~]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
可以看到,在/sys/fs/cgroup 下面有很多諸如 cpuset、cpu、 memory 這樣的子目錄,也叫子系統(tǒng)。
即:這臺機器當前可以被 Cgroups 進行限制的資源種類。
比如,對 CPU 子系統(tǒng)來說,我們就可以看到如下幾個配置文件:
[root@docker ~]# ls /sys/fs/cgroup/cpu
cgroup.clone_children cgroup.sane_behavior cpuacct.stat cpuacct.usage_all cpuacct.usage_percpu_sys cpuacct.usage_sys cpu.cfs_period_us cpu.rt_period_us cpu.shares docker release_agent tasks
cgroup.procs cpuacct.usage cpuacct.usage_percpu cpuacct.usage_percpu_user cpuacct.usage_user cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat notify_on_release system.slice user.slice
這些配置文件定義了如何對 CPU 進行限制,以及需要對哪些進程進行限制。
那么配置文件又如何使用呢?下面我們來演示一下具體使用。
例子:限制 CPU 使用
你需要在對應的子系統(tǒng)下面創(chuàng)建一個目錄,比如,我們現(xiàn)在進入 /sys/fs/cgroup/cpu 目錄下創(chuàng)建一個名為 container 的目錄:
[root@docker ~]# cd /sys/fs/cgroup/cpu
[root@docker cpu]# mkdir container
這個目錄就是一個“控制組”。
你會發(fā)現(xiàn),操作系統(tǒng)會在你新創(chuàng)建的 container 目錄下,自動生成該子系統(tǒng)對應的資源限制文件。
[root@docker cpu]# ls container
cgroup.clone_children cpuacct.stat cpuacct.usage_all cpuacct.usage_percpu_sys cpuacct.usage_sys cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.procs cpuacct.usage cpuacct.usage_percpu cpuacct.usage_percpu_user cpuacct.usage_user cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
接下來我們就通過修改配置文件對 CPU 進行限制,這里就用前面創(chuàng)建的 container 這個“控制組”。
主要通過以下三個文件來實現(xiàn)
- cpu.cfs_quota_us:每個控制周期內(nèi),進程可以使用的 cpu 時間,默認為 -1,即不做限制。
- cpu.cfs_period_us:控制周期,默認為 100 ms
- tasks:記錄被限制進程的 PID 列表
cgroups 會限制所有在 tasks 中的進程,在 cpu.cfs_period_us 周期內(nèi),最多只能使用 cpu.cfs_quota_us 的 cpu 資源。
比如,100ms 能限制只能使用 20ms,即最多占用 0.2 核心
首先,我們在后臺執(zhí)行這樣一條腳本:
[root@docker cpu]# while : ; do : ; done &
[1] 3892
顯然,它執(zhí)行了一個死循環(huán),可以把計算機的 CPU 吃到 100%。根據(jù)它的輸出,我們可以看到這個腳本在后臺運行的進程號(PID)是 3892。
執(zhí)行 Top 查看一下 CPU 占用,可以看到這個 3892 進程占用了差不多 100% 的 CPU,把一個核心占滿了。
[root@docker cpu]# top
top - 16:07:06 up 286 days, 4:31, 3 users, load average: 0.59, 0.50, 0.50
Tasks: 97 total, 2 running, 48 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1006956 total, 166520 free, 190840 used, 649596 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 549216 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3892 root 20 0 115684 532 0 R 92.0 0.1 0:48.64 bash
此時,我們就可以通過配置 cgroups 來實現(xiàn)對該進程的 CPU 使用情況進行限制。
默認情況下 container 控制組里的 CPU quota 還沒有任何限制(即:-1),CPU period 則是默認的 100 ms(100000 us),因此上述進程可以占用整個 CPU。
[root@docker cpu]# cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
-1
[root@docker cpu]# cat /sys/fs/cgroup/cpu/container/cpu.cfs_period_us
100000
接下來,我們可以通過修改這配置文件來設(shè)置 CPU 限制。比如,向 container 組里的 cfs_quota 文件寫入 20 ms(20000 us)來做限制。
[root@docker cpu]# echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
[root@docker cpu]# cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
20000
最后則是將進程 PID 寫入 tasks 文件里,是配置生效。
[root@docker cpu]# echo 3892 > /sys/fs/cgroup/cpu/container/tasks
[root@docker cpu]# cat /sys/fs/cgroup/cpu/container/tasks
3892
然后查看是否生效:
[root@docker cpu]# top
top - 16:13:56 up 286 days, 4:38, 3 users, load average: 0.20, 0.61, 0.59
Tasks: 94 total, 2 running, 48 sleeping, 0 stopped, 0 zombie
%Cpu(s): 21.6 us, 0.0 sy, 0.0 ni, 78.1 id, 0.0 wa, 0.0 hi, 0.0 si, 0.3 st
KiB Mem : 1006956 total, 166552 free, 190808 used, 649596 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 549248 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3892 root 20 0 115684 532 0 R 19.9 0.1 5:56.94 bash
可以看到,果然 3892 CPU 被限制到了 20%。
除 CPU 子系統(tǒng)外,Cgroups 的每一個子系統(tǒng)都有其獨有的資源限制能力,比如:
- blkio,為塊設(shè)備設(shè)定I/O 限制,一般用于磁盤等設(shè)備;
- cpuset,為進程分配單獨的 CPU 核和對應的內(nèi)存節(jié)點;
- memory,為進程設(shè)定內(nèi)存使用的限制。
Linux Cgroups 的設(shè)計還是比較易用的,簡單粗暴地理解呢,它就是一個子系統(tǒng)目錄加上一組資源限制文件的組合。
而對于 Docker 等 Linux 容器項目來說,它們只需要在每個子系統(tǒng)下面,為每個容器創(chuàng)建一個控制組(即創(chuàng)建一個新目錄),然后在啟動容器進程之后,把這個進程的 PID 填寫到對應控制組的 tasks 文件中就可以了。
而至于在這些控制組下面的資源文件里填上什么值,就靠用戶執(zhí)行 docker run 時的參數(shù)指定了,比如這樣一條命令:
docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash
在啟動這個容器后,我們可以通過查看 Cgroups 文件系統(tǒng)下,CPU 子系統(tǒng)中,“docker”這個控制組里的資源限制文件的內(nèi)容來確認:
$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_period_us
100000
$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_quota_us
20000
3. 容器鏡像的秘密
這部分主要解釋以下三個問題
- 1)為什么在容器中修改了文件宿主機不受影響?
- 2)容器中的文件系統(tǒng)是哪兒來的?
- 3)docker 鏡像又是怎么實現(xiàn)的?
這也是 Docker 的第三個核心功能:容器鏡像(rootfs),將運行環(huán)境打包成鏡像,從而避免環(huán)境問題導致應用無法運行。
1. 文件系統(tǒng)
容器中的文件系統(tǒng)是什么樣子的?
因為容器中的文件系統(tǒng)經(jīng)過 Mount Namespace 隔離,所以應該是獨立的。
其中 Mount Namespace 修改的,是容器進程對文件系統(tǒng)“掛載點”的認知。只有在“掛載”這個操作發(fā)生之后,進程的視圖才會被改變。而在此之前,新創(chuàng)建的容器會直接繼承宿主機的各個掛載點。
不難想到,我們可以在容器進程啟動之前重新掛載它的整個根目錄“/”。而由于 Mount Namespace 的存在,這個掛載對宿主機不可見,所以容器進程就可以在里面隨便折騰了。
Linux 中 chroot 命令(change root file system)就能很方便的完成上述工作。
而 Mount Namespace 正是基于對 chroot 的不斷改良才被發(fā)明出來的,它也是 Linux 操作系統(tǒng)里的第一個 Namespace。
至此,第一個問題 為什么在容器中修改了文件宿主機不受影響?有答案了,因為使用 Mount Namespace 隔離了。
2. rootfs
上文提到 Mount Namespace 會修改容器進程對文件系統(tǒng)掛載點的認知,而這個掛載在容器根目錄上、用來為容器進程提供隔離后執(zhí)行環(huán)境的文件系統(tǒng),就是所謂的“容器鏡像”。它還有一個更為專業(yè)的名字,叫作:rootfs(根文件系統(tǒng))。
rootfs 只是一個操作系統(tǒng)所包含的文件、配置和目錄,并不包括操作系統(tǒng)內(nèi)核。在 Linux 操作系統(tǒng)中,這兩部分是分開存放的,操作系統(tǒng)只有在開機啟動時才會加載指定版本的內(nèi)核鏡像。
所以說,rootfs 只包括了操作系統(tǒng)的“軀殼”,并沒有包括操作系統(tǒng)的“靈魂”。實際上,同一臺機器上的所有容器,都共享宿主機操作系統(tǒng)的內(nèi)核。
這也是容器相比于虛擬機的主要缺陷之一:畢竟后者不僅有模擬出來的硬件機器充當沙盒,而且每個沙盒里還運行著一個完整的 Guest OS 給應用隨便折騰。
不過,正是由于 rootfs 的存在,容器才有了一個被反復宣傳至今的重要特性:一致性。由于 rootfs 里打包的不只是應用,而是整個操作系統(tǒng)的文件和目錄,也就意味著,應用以及它運行所需要的所有依賴,都被封裝在了一起。
第二個問題:容器中的文件系統(tǒng)是哪兒來的?實際上是我們構(gòu)建鏡像的時候打包進去的,然后容器啟動時掛載到了根目錄下。
3. 鏡像層(Layer)
Docker 在鏡像的設(shè)計中,引入了層(layer)的概念。也就是說,用戶制作鏡像的每一步操作,都會生成一個層,也就是一個增量 rootfs。
通過引入層(layer)的概念,實現(xiàn)了 rootfs 的復用。不必每次都重新創(chuàng)建一個 rootfs,而是基于某一層進行修改即可。
Docker 鏡像層用到了一種叫做聯(lián)合文件系統(tǒng)(Union File System)的能力。Union File System 也叫 UnionFS,最主要的功能是將多個不同位置的目錄聯(lián)合掛載(union mount)到同一個目錄下。
例如將目錄 A 和目錄 B 掛載到目錄 C 下面,這樣目錄 C 下就包含目錄 A 和目錄 B 的所有文件。
由于看不到目錄 A 和 目標 B 的存在,因此就好像 C 目錄就包含這么多文件一樣
Docker 鏡像分為多個層,然后使用 UFS 將這多個層掛載到一個目錄下面,這樣這個目錄就包含了完整的文件了。
UnionFS 在不同系統(tǒng)有各自的實現(xiàn),所以 Docker 的不同發(fā)行版使用的也不一樣,可以通過 docker info 查看。常見有 aufs(ubuntu 常用)、overlay2(centos 常用)
就像下圖這樣:union mount 在最上層,提供了統(tǒng)一的視圖,用戶看起來好像整個系統(tǒng)只有一層一樣,實際上下面包含了很多層。
鏡像只包含了靜態(tài)文件,但是容器會產(chǎn)生實時數(shù)據(jù),所以容器的 rootfs 在鏡像的基礎(chǔ)上增加了可讀寫層和 Init 層。
即容器 rootfs 包括:只讀層(鏡像rootfs)+ init 層(容器啟動時初始化修改的部分數(shù)據(jù)) + 可讀寫層(容器中產(chǎn)生的實時數(shù)據(jù))。
只讀層(鏡像rootfs)
它是這個容器的 rootfs 最下面的幾層,即鏡像中的所有層的總和,它們的掛載方式都是只讀的(ro+wh,即 readonly+whiteout)
可讀寫層(容器中產(chǎn)生的實時數(shù)據(jù))
它是這個容器的 rootfs 最上面的一層,它的掛載方式為:rw,即 read write。在沒有寫入文件之前,這個目錄是空的。
而一旦在容器里做了寫操作,你修改產(chǎn)生的內(nèi)容就會以增量的方式出現(xiàn)在這個層中,刪除操作實現(xiàn)比較特殊(類似于標記刪除)。
AUFS 的 whiteout 的實現(xiàn)是通過在上層的可寫的目錄下建立對應的 whiteout 隱藏文件來實現(xiàn)的。
為了實現(xiàn)刪除操作,aufs(UnionFS 的一種實現(xiàn)) 會在可讀寫層創(chuàng)建一個 whiteout 文件,把只讀層里的文件“遮擋”起來。
比如,你要刪除只讀層里一個名叫 foo 的文件,那么這個刪除操作實際上是在可讀寫層創(chuàng)建了一個名叫.wh.foo 的文件。這樣,當這兩個層被聯(lián)合掛載之后,foo 文件就會被.wh.foo 文件“遮擋”起來,“消失”了。
init 層(容器啟動時初始化修改的部分數(shù)據(jù))
它是一個以“-init”結(jié)尾的層,夾在只讀層和讀寫層之間,Init 層是 Docker 項目單獨生成的一個內(nèi)部層,專門用來存放 /etc/hosts、/etc/resolv.conf 等信息。
為什么需要 init 層?
比如 hostname 這樣的數(shù)據(jù),原本是屬于鏡像層的一部分,要修改的話只能在可讀寫層進行修改,但是又不想在 docker commit 的時候把這些信息提交上去,所以使用 init 層來保存這些修改。
可以理解為提交代碼的時候一般也不會把各種配置信息一起提交上去。
docker commit 只會提交 只讀層和可讀寫層。
最后一個問題:docker 鏡像又是怎么實現(xiàn)的?通過引入 layer 概念進行分層,借助 聯(lián)合文件系統(tǒng)(Union File System)進行疊加,最終構(gòu)成了完整的鏡像。
這里只是鏡像的主要內(nèi)容,具體怎么把這些內(nèi)容打包成 image 格式就是 OCI 規(guī)范了
4. 小結(jié)
至此,我們大致清楚了 Docker 容器的實現(xiàn)主要使用了如下 3 個功能:
- 1)Linux Namespace 的隔離能力
- 2)Linux Cgroups 的限制能力
- 3)基于 rootfs 的文件系統(tǒng)
如果你對云原生技術(shù)充滿好奇,想要深入了解更多相關(guān)的文章和資訊,歡迎關(guān)注微信公眾號。
搜索公眾號【探索云原生】即可訂閱
5. 參考
https://draveness.me/docker/
https://en.wikipedia.org/wiki/Linux_namespaces
https://0xax.gitbooks.io/linux-insides/content/Cgroups/linux-cgroups-1.html
https://coolshell.cn/articles/17061.html
深入剖析Kubernetes
總結(jié)
以上是生活随笔為你收集整理的深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小学科学实践研究论文
- 下一篇: 10gb硬盘存储容量为