一、容器
使用docker運作一個httpd容器。因為接下來要在容器内執行ps -ef指令,有些容器沒有這個指令,例如nginx的官方鏡像運作的容器就沒有這個指令。
shell複制代碼[root@dev1 ~]# docker run -d --name httpd centos/httpd-24-centos7
latest: Pulling from centos/httpd-24-centos7
73808be511e558e3098c0f513e5bfd274a701751b004292116ae971b8beebcb7
[root@dev1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
73808be511e5 centos/httpd-24-centos7 "container-entrypoin…" 35 seconds ago Up 33 seconds 8080/tcp, 8443/tcp httpd
在這個啟動好的nginx容器中運作一個指令,如下是在容器内的程序:
shell複制代碼[root@dev1 ~]# docker exec httpd ps -ef
UID PID PPID C STIME TTY TIME CMD
default 1 0 0 23:35 ? 00:00:00 httpd -D FOREGROUND
default 41 1 0 23:35 ? 00:00:00 /usr/bin/cat
default 42 1 0 23:35 ? 00:00:00 /usr/bin/cat
default 43 1 0 23:35 ? 00:00:00 /usr/bin/cat
default 44 1 0 23:35 ? 00:00:00 /usr/bin/cat
default 45 1 0 23:35 ? 00:00:00 httpd -D FOREGROUND
default 50 1 0 23:35 ? 00:00:00 httpd -D FOREGROUND
default 67 1 0 23:35 ? 00:00:00 httpd -D FOREGROUND
default 69 1 0 23:35 ? 00:00:00 httpd -D FOREGROUND
default 70 1 0 23:35 ? 00:00:00 httpd -D FOREGROUND
default 91 0 0 23:36 ? 00:00:00 ps -ef
在啟動好的容器,沒有ip addr指令檢視不了容器ip,不過可以通過docker inspect指令檢視配置設定給httpd容器的ip是多少。運作後可以看到配置設定到的ip是172.7.4.2
csharp複制代碼[root@dev1 ~]# docker inspect httpd | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.7.4.2",
"IPAddress": "172.7.4.2",
學習過或者使用過容器都知道,容器之間是互相隔離的,每個容器都有自己的檔案系統,運作的程序和網絡也是獨立的。并且是和主機上的檔案系統、程序以及網絡上都是隔離的。如下所示:
容器都是怎麼做到檔案系統、程序、網絡等環境互相隔離的,核心就是Namespace和Cgroups可以讓一程式在一個資源可控的獨立環境中運作,進而做到隔離,這就是容器。
二、指令空間:Namespace
在上面在容器裡面執行過指令,檢視了容器内的程序,現在在主機上執行:ps -ef | grep httpd。如下主機上的有關httd的程序,可以看到程序号是不一樣的。這時候就要說到Namespace了。
yaml複制代碼[root@dev1 ~]# ps -ef | grep httpd
1001 1895 1875 2 22:48 ? 00:00:00 httpd -D FOREGROUND
1001 1965 1895 0 22:48 ? 00:00:00 httpd -D FOREGROUND
1001 1966 1895 0 22:48 ? 00:00:00 httpd -D FOREGROUND
1001 1972 1895 0 22:48 ? 00:00:00 httpd -D FOREGROUND
1001 1982 1895 0 22:48 ? 00:00:00 httpd -D FOREGROUND
1001 1990 1895 0 22:48 ? 00:00:00 httpd -D FOREGROUND
root 2054 1675 0 22:48 pts/0 00:00:00 grep --color=auto httpd
在主機上執行:可以看到
shell複制代碼[root@dev1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
73808be511e5 centos/httpd-24-centos7 "container-entrypoin…" 16 hours ago Up 30 minutes 8080/tcp, 8443/tcp httpd
[root@dev1 ~]# ps -ef | grep containerd
root 901 1 0 22:47 ? 00:00:01 /usr/bin/containerd
root 1061 1 0 22:47 ? 00:00:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root 1875 1 0 22:48 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 73808be511e558e3098c0f513e5bfd274a701751b004292116ae971b8beebcb7 -address /run/containerd/containerd.sock
root 12941 1675 0 23:18 pts/0 00:00:00 grep --color=auto containerd
一張圖來诠釋主機程序以及容器程序的關系:
Linux在建立容器的時候會建立出一個PID Namespace,這PID就是容器裡面的1号程序,然後不同容器的1号程序會建立其子程序。是以containerd-shim在建立容器程序時,會建立一個該程序的Namespace,Namespace下的程序号會從1開始編号,被containerd-shim出來的程序就是1号程序,也就init程序(容器内),被建立出來的Namespace下的程序是看不到其他Namespace裡面的程序。
是以通過PID Namespace便實作了程序隔離。
但是在主控端下是可以看到所有的在此主機上建立出來的Namespace的程序,Host PID Namespace(主控端命名空間),可以看到它的所有子PID Namespace,這些子命名空間内的程序會在父命名空間裡重新被編号。
Namespace就是一種隔離機制,可以隔離運作在同一個主控端上的程序,讓這些程序之間不能通路彼此的資源。
2.1 其他的Namespace
玩過容器的都知道,根據鏡像不一樣,運作出來的容器裡面的檔案系統也不一樣。可以得出檔案系統也是我們做的鏡像,例如想容器的網絡、檔案挂載等,其實都是有對應的Namespace。除了常見的PID Namespace還有實作網絡隔離的Network Namespace、實作獨立于主控端檔案系統隔離的Mount Namespace。在Linux Program's Manual中可以看到所有Linux支援的Namespace:cgroup/ipc/network/pid/mount/time/user/uts。
三、源自控制組群:Cgroups
全稱: Control Groups,是Linux核心的功能,用來限制、控制并分離一個程序的資源(CPU、記憶體、磁盤等)。在我們通過Namespace隔離出一個容器後,如何讓限制這個容器能夠通路的資源,例如限制CPU的使用率,記憶體使用量以及I/O等資源。是支撐容器化的第二個技術Cgroups。
- CPU子系統:用來限制一組程序能夠使用的最大CPU
- Memory子系統:用來限制一組程序最大的記憶體使用量
- pids子系統:用來限制一組程序内最多可以運作多少個程序
- cpuset子系統:用來控制一組程序可以在哪幾個實體CPU上運作
在容器啟動後會在Cgroups子系統下建立一個目錄,這個目錄也被稱作控制組。例如在主控端下:/sys/fs/cgroup/memory/system.slice
shell複制代碼[root@dev1 cgroup]# pwd
/sys/fs/cgroup
[root@dev1 cgroup]# ll
total 0
drwxr-xr-x. 4 root root 0 Jul 16 22:47 blkio
lrwxrwxrwx. 1 root root 11 Jul 16 22:47 cpu -> cpu,cpuacct
lrwxrwxrwx. 1 root root 11 Jul 16 22:47 cpuacct -> cpu,cpuacct
drwxr-xr-x. 4 root root 0 Jul 16 22:47 cpu,cpuacct
drwxr-xr-x. 3 root root 0 Jul 16 22:47 cpuset
drwxr-xr-x. 4 root root 0 Jul 16 22:47 devices
drwxr-xr-x. 3 root root 0 Jul 16 22:47 freezer
drwxr-xr-x. 3 root root 0 Jul 16 22:47 hugetlb
drwxr-xr-x. 4 root root 0 Jul 16 22:47 memory
lrwxrwxrwx. 1 root root 16 Jul 16 22:47 net_cls -> net_cls,net_prio
drwxr-xr-x. 3 root root 0 Jul 16 22:47 net_cls,net_prio
lrwxrwxrwx. 1 root root 16 Jul 16 22:47 net_prio -> net_cls,net_prio
drwxr-xr-x. 3 root root 0 Jul 16 22:47 perf_event
drwxr-xr-x. 4 root root 0 Jul 16 22:47 pids
drwxr-xr-x. 4 root root 0 Jul 16 22:47 systemd
[root@dev1 cgroup]# cd memory/
[root@dev1 memory]# cd system.slice/
[root@dev1 system.slice]# ll | grep docker
drwxr-xr-x. 2 root root 0 Jul 16 22:48 data-docker-overlay2-27ff338930f9111ae251b3b4e08078f785e41759e70fc881e1c8d06f6378eb36-merged.mount
drwxr-xr-x. 2 root root 0 Jul 16 22:48 docker-73808be511e558e3098c0f513e5bfd274a701751b004292116ae971b8beebcb7.scope
drwxr-xr-x. 2 root root 0 Jul 16 22:47 docker.service
drwxr-xr-x. 2 root root 0 Jul 16 23:03 run-docker-netns-08a9607d2553.mount
docker-73808be511e558e3098c0f513e5bfd274a701751b004292116ae971b8beebcb7.scope這個目錄下的cgroup.procs存儲着httpd容器的控制組資訊,因為httpd容器的ID就是73808be511e558e3098c0f513e5bfd274a701751b004292116ae971b8beebcb7。
如下所示可以看到是httpd容器内的所有程序号(在主控端上的程序編号),限制了這些程序能夠通路的資源。
shell複制代碼[root@dev1 docker-73808be511e558e3098c0f513e5bfd274a701751b004292116ae971b8beebcb7.scope]# cat cgroup.procs
1895
1961
1962
1963
1964
1965
1966
1972
1982
1990
在這個容器的目錄下,例如memory.limit_in_bytes檔案可以限制容器73808be511e558e3098c0f513e5bfd274a701751b004292116ae971b8beebcb7内程序能夠通路到的記憶體總量,寫入1073741824到memory.limit_in_bytes,即可限制httpd容器最大能通路主控端1G的記憶體。
shell複制代碼[root@dev1 docker-73808be511e558e3098c0f513e5bfd274a701751b004292116ae971b8beebcb7.scope]# ll
total 0
-rw-r--r--. 1 root root 0 Jul 16 22:48 cgroup.clone_children
--w--w--w-. 1 root root 0 Jul 16 22:48 cgroup.event_control
-rw-r--r--. 1 root root 0 Jul 16 22:48 cgroup.procs
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.failcnt
--w-------. 1 root root 0 Jul 16 22:48 memory.force_empty
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.kmem.failcnt
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.kmem.limit_in_bytes
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.kmem.max_usage_in_bytes
-r--r--r--. 1 root root 0 Jul 16 22:48 memory.kmem.slabinfo
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.kmem.tcp.failcnt
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.kmem.tcp.limit_in_bytes
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.kmem.tcp.max_usage_in_bytes
-r--r--r--. 1 root root 0 Jul 16 22:48 memory.kmem.tcp.usage_in_bytes
-r--r--r--. 1 root root 0 Jul 16 22:48 memory.kmem.usage_in_bytes
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.limit_in_bytes
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.max_usage_in_bytes
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.memsw.failcnt
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.memsw.limit_in_bytes
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.memsw.max_usage_in_bytes
-r--r--r--. 1 root root 0 Jul 16 22:48 memory.memsw.usage_in_bytes
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.move_charge_at_immigrate
-r--r--r--. 1 root root 0 Jul 16 22:48 memory.numa_stat
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.oom_control
----------. 1 root root 0 Jul 16 22:48 memory.pressure_level
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.soft_limit_in_bytes
-r--r--r--. 1 root root 0 Jul 16 22:48 memory.stat
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.swappiness
-r--r--r--. 1 root root 0 Jul 16 22:48 memory.usage_in_bytes
-rw-r--r--. 1 root root 0 Jul 16 22:48 memory.use_hierarchy
-rw-r--r--. 1 root root 0 Jul 16 22:48 notify_on_release
-rw-r--r--. 1 root root 0 Jul 16 22:48 tasks
四、總結
Linux的兩大技術Namespace和Cgroups是用于試下容器的特性,Namespace幫助容器實作各類計算資源的隔離,Cgroups主要對容器的能通路主控端資源的多少。是以可以說,容器就是Namespace+Cgroups。