容器的四大基礎(chǔ)技術(shù)
在本文中,我研究了容器是如何在一些特殊的 Linux 技術(shù)基礎(chǔ)上實(shí)現(xiàn)的,這其中包括命名空間和控制組。
圖1:對(duì)容器有貢獻(xiàn)的 Linux 技術(shù)(Nived Velayudhan, CC BY-SA 4.0)
這些 Linux 技術(shù)構(gòu)成了在系統(tǒng)上構(gòu)建和運(yùn)行容器進(jìn)程的基礎(chǔ):
- 命名空間
- 控制組(cgroups)
- Seccomp
- SELinux
1. 命名空間
命名空間namespace 為容器提供了一個(gè)隔離層,給容器提供了一個(gè)看起來(lái)是獨(dú)占的 Linux 文件系統(tǒng)的視圖。這就限制了進(jìn)程能訪(fǎng)問(wèn)的內(nèi)容,從而限制了它所能獲得的資源。
在創(chuàng)建容器時(shí),Docker 或 Podman 和其他容器技術(shù)使用了 Linux 內(nèi)核中的幾個(gè)命名空間:
- [nivedv@homelab ~]$ docker container run alpine ping 8.8.8.8
- [nivedv@homelab ~]$ sudo lsns -p 29413
- NS TYPE NPROCS PID USER COMMAND
- 4026531835 cgroup 299 1 root /usr/lib/systemd/systemd --switched...
- 4026531837 user 278 1 root /usr/lib/systemd/systemd --switched...
- 4026533105 mnt 1 29413 root ping 8.8.8.8
- 4026533106 uts 1 29413 root ping 8.8.8.8
- 4026533107 ipc 1 29413 root ping 8.8.8.8
- 4026533108 pid 1 29413 root ping 8.8.8.8
- 4026533110 net 1 29413 root ping 8.8.8.8
用戶(hù)
用戶(hù)(user)命名空間將用戶(hù)和組隔離在一個(gè)容器內(nèi)。這是通過(guò)分配給容器與宿主系統(tǒng)有不同的 UID 和 GID 范圍來(lái)實(shí)現(xiàn)的。用戶(hù)命名空間使軟件能夠以 root 用戶(hù)的身份在容器內(nèi)運(yùn)行。如果入侵者攻擊容器,然后逃逸到宿主機(jī)上,他們就只能以受限的非 root 身份運(yùn)行了。
掛載
掛載(mnt)命名空間允許容器有自己的文件系統(tǒng)層次結(jié)構(gòu)視圖。你可以在 Linux 系統(tǒng)中的 /proc/
UTS
Unix 分時(shí)系統(tǒng)Unix Timeharing System(UTS)命名空間允許容器擁有一個(gè)唯一主機(jī)名和域名。當(dāng)你運(yùn)行一個(gè)容器時(shí),即使使用 - name 標(biāo)簽,也會(huì)使用一個(gè)隨機(jī)的 ID 作為主機(jī)名。你可以使用 unshare 命令 來(lái)了解一下這個(gè)工作原理。
- nivedv@homelab ~]$ docker container run -it --name nived alpine sh
- / # hostname
- 9c9a5edabdd6
- / #
- nivedv@homelab ~]$ sudo unshare -u sh
- sh-5.0# hostname isolated.hostname
- sh-5.0# hostname
- isolated.hostname
- sh-5.0#
- sh-5.0# exit
- exit
- [nivedv@homelab ~]$ hostname
- homelab.redhat.com
IPC
進(jìn)程間通信Inter-Process Communication(IPC)命名空間允許不同的容器進(jìn)程之間,通過(guò)訪(fǎng)問(wèn)共享內(nèi)存或使用共享消息隊(duì)列來(lái)進(jìn)行通信。
- [root@demo /]# ipcmk -M 10M
- Shared memory id: 0
- [root@demo /]# ipcmk -M 20M
- Shared memory id: 1
- [root@demo /]#
- [root@demo /]# ipcs
- ------ Message Queues --------
- key msqid owner perms used-bytes messages
- ------ Shared Memory Segments --------
- key shmid owner perms bytes nattch status
- 0xd1df416a 0 root 644 10485760 0
- 0xbd487a9d 1 root 644 20971520 0
- ------ Semaphore Arrays --------
- key semid owner perms nsems
PID
進(jìn)程 IDProcess ID(PID)命名空間確保運(yùn)行在容器內(nèi)的進(jìn)程與外部隔離。當(dāng)你在容器內(nèi)運(yùn)行 ps 命令時(shí),由于這個(gè)命名空間隔離的存在,你只能看到在容器內(nèi)運(yùn)行的進(jìn)程,而不是在宿主機(jī)上。
網(wǎng)絡(luò)
網(wǎng)絡(luò)(net)命名空間允許容器有自己網(wǎng)絡(luò)接口、IP 地址、路由表、端口號(hào)等視圖。容器如何能夠與外部通信?你創(chuàng)建的所有容器都會(huì)被附加到一個(gè)特殊的虛擬網(wǎng)絡(luò)接口上進(jìn)行通信。
- [nivedv@homelab ~]$ docker container run --rm -it alpine sh
- / # ping 8.8.8.8
- PING 8.8.8.8 (8.8.8.8): 56 data bytes
- 64 bytes from 8.8.8.8: seq=0 ttl=119 time=21.643 ms
- 64 bytes from 8.8.8.8: seq=1 ttl=119 time=20.940 ms
- ^C
- [root@homelab ~]# ip link show veth84ea6fc
- veth84ea6fc@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
- master docker0 state UP mode DEFAULT group default
2. 控制組
控制組(cgroup)是組成一個(gè)容器的基本模塊??刂平M會(huì)分配和限制容器所使用的資源,如 CPU、內(nèi)存、網(wǎng)絡(luò) I/O 等。容器引擎會(huì)自動(dòng)創(chuàng)建每種類(lèi)型的控制組文件系統(tǒng),并在容器運(yùn)行時(shí)為每個(gè)容器設(shè)置配額。
- [root@homelab ~]# lscgroup | grep docker
- cpuset:/docker
- net_cls,net_prio:/docker
- cpu,cpuacct:/docker
- hugetlb:/docker
- devices:/docker
- freezer:/docker
- memory:/docker
- perf_event:/docker
- blkio:/docker
- pids:/docker
容器運(yùn)行時(shí)為每個(gè)容器設(shè)置了控制組值,所有信息都存儲(chǔ)在 /sys/fs/cgroup/*/docker。下面的命令將確保容器可以使用 50000 微秒的 CPU 時(shí)間片,并將內(nèi)存的軟、硬限制分別設(shè)置為 500M 和 1G。
- [root@homelab ~]# docker container run -d --name test-cgroups --cpus 0.5 --memory 1G --memory-reservation 500M httpd
- [root@homelab ~]# lscgroup cpu,cpuacct:/docker memory:/docker
- cpu,cpuacct:/docker/
- cpu,cpuacct:/docker/c3503ac704dafea3522d3bb82c77faff840018e857a2a7f669065f05c8b2cc84
- memory:/docker/
- memory:/docker/c3503ac704dafea3522d3bb82c77faff840018e857a2a7f669065f05c8b2cc84
- [root@homelab c....c84]# cat cpu.cfs_period_us
- 100000
- [root@homelab c....c84]# cat cpu.cfs_quota_us
- 50000
- [root@homelab c....c84]# cat memory.soft_limit_in_bytes
- 524288000
- [root@homelab c....c84]# cat memory.limit_in_bytes
- 1073741824
3. SECCOMP
Seccomp 意思是“安全計(jì)算secure computing”。它是一項(xiàng) Linux 功能,用于限制應(yīng)用程序進(jìn)行的系統(tǒng)調(diào)用的集合。例如,Docker 的默認(rèn) seccomp 配置文件禁用了大約 44 個(gè)系統(tǒng)調(diào)用(總計(jì)超過(guò) 300 個(gè))。
這里的思路是讓容器只訪(fǎng)問(wèn)所必須的資源。例如,如果你不需要容器改變主機(jī)上的時(shí)鐘時(shí)間,你可能不會(huì)使用 clock_adjtime 和 clock_settime 系統(tǒng)調(diào)用,屏蔽它們是合理的。同樣地,你不希望容器改變內(nèi)核模塊,所以沒(méi)有必要讓它們使用 create_module、 delete_module 系統(tǒng)調(diào)用。
4. SELinux
SELinux 是“安全增強(qiáng)的 Linuxsecurity-enhanced Linux”的縮寫(xiě)。如果你在你的宿主機(jī)上運(yùn)行的是 Red Hat 發(fā)行版,那么 SELinux 是默認(rèn)啟用的。SELinux 可以讓你限制一個(gè)應(yīng)用程序只能訪(fǎng)問(wèn)它自己的文件,并阻止任何其他進(jìn)程訪(fǎng)問(wèn)。因此,如果一個(gè)應(yīng)用程序被破壞了,它將限制該應(yīng)用程序可以影響或控制的文件數(shù)量。通過(guò)為文件和進(jìn)程設(shè)置上下文環(huán)境以及定義策略來(lái)實(shí)現(xiàn),這些策略將限制一個(gè)進(jìn)程可以訪(fǎng)問(wèn)和更改的內(nèi)容。
容器的 SELinux 策略是由 container-selinux 包定義的。默認(rèn)情況下,容器以 container_t 標(biāo)簽運(yùn)行,允許在 /usr 目錄下讀取(r)和執(zhí)行(x),并從 /etc 目錄下讀取大部分內(nèi)容。標(biāo)簽container_var_lib_t 是與容器有關(guān)的文件的通用標(biāo)簽。
總結(jié)
容器是當(dāng)今 IT 基礎(chǔ)設(shè)施的一個(gè)重要組成部分,也是一項(xiàng)相當(dāng)有趣的技術(shù)。即使你的工作不直接涉及容器化,了解一些基本的容器概念和方法,也能讓你體會(huì)到它們?nèi)绾螏椭愕慕M織。容器是建立在開(kāi)源的 Linux 技術(shù)之上的,這使它們變得更加美好。