一、容器
使用docker运行一个httpd
容器。因为接下来要在容器内执行ps -ef
命令,有些容器没有这个命令,例如nginx
的官方镜像运行的容器就没有这个命令。
[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容器中运行一个命令,如下是在容器内的进程:
[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
[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了。
[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
在主机上执行:可以看到
[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
[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容器内的所有进程号(在宿主机上的进程编号),限制了这些进程能够访问的资源。
[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的内存。
[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
。