容器的本质就是一组特殊的进程,它使用namespace做隔离,用cgroup做限制。
- 这里的容器可以是docker ,rkt等
- 因为容器是一组特殊的进程,所以他们是跑在同一个内核上的,隔离性没有虚拟机好。
- 还因为进程带来的性能损耗比虚拟机小很多,它也是特别轻量的虚拟化。
如何使用namespace对容器做隔离的
容器是如何使用namespace做隔离的,因为namespace的种类也很多(pid,mount,network,ipc,user,UTS),这里以PID namespace为例。
首先看一下关于PID 的一个小实验:
环境说明:
- 宿主机ubuntu 20.04
- docker 容器
- docker 加入了root组,所以不用输入sudo,容器启动的进程也是在root组中
实验步骤:
- 启动一个centos的交互终端
docker run -it centos /bin/bash
-
看看容器内部bash进程的pid
bash_pid.png -
看看宿主机上bash进程的pid,用户是root的那个pid.
宿主机pid.png
由上面的例子可以看到,容器启动的bash在容器内部看到的pid是1,在数组上看到的PID是31840,这是怎么做到的,其实很简单:
正常我们clone一个进程使用下面代码,
int pid = clone(child_main, stack_size, SIGCHLD, NULL);
如果要想这个新进程只能看到自己,以及由自己clone出来的进程(在上面的例子中就是容器内执行的ps进程),不能看到其他进程,使用这段代码
int pid = clone(child_main, stack_size, CLONE_NEWPID | SIGCHLD, NULL);
唯一的区别就是加入了CLONE_NEWPID,其他的namespace隔离也是使用相同的方式
int pid = clone(child_main, stack_size, CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | SIGCHLD, NULL);
这就是同时对,UTS, IPC,PID同时做namespace的隔离。
这里有点不同是mount namespace ,因为mount namespace一定是伴随着mount动作才会生效。mount namespace由chroot 命令发展而来,chroot: change root file system,将根目录"/",挂载到指定的位置。通常我们说的容器镜像,就是挂载在根目录的文件系统,它为隔离后的容器提供文件系统,专业称之为"rootfs".
如何使用cgroup 对资源做限制
cgroup是一个内核功能,它能限制一个或者一组进程对进程资源(cpu,内存,网络等)的使用量不超过被分配的量。cgroup 给用户暴露出来的的操作系统接口是文件系统
mount -t cgroup
可以看到有哪些可以做cgroup限制的类型。
下面演示一个对cpu类型的cgroup做限制的实例。
环境说明:
- 宿主机ubuntu 20.04
- docker 容器
- docker 加入了root组,所以不用输入sudo,容器启动的进程也是在root组中
实验步骤:
- 启动一个centos的交互终端
docker run -it centos /bin/bash
- 查看cpu 限制文件参数
[root@f7ab6d1d8b37 /]# ls /sys/fs/cgroup/cpu
cgroup.clone_children cpu.shares cpuacct.stat cpuacct.usage_percpu_sys notify_on_release
cgroup.procs cpu.stat cpuacct.usage cpuacct.usage_percpu_user tasks
cpu.cfs_period_us cpu.uclamp.max cpuacct.usage_all cpuacct.usage_sys
cpu.cfs_quota_us cpu.uclamp.min cpuacct.usage_percpu cpuacct.usage_user
这些文件中重要的有,cpu.cfs_period_us和cpu.cfs_quota_us ,表示在时间长度为cpu.cfs_period_us的时间内,可以分配到的CPU时间是cpu.cfs_quota_us ,单位都是us;
默认是没有限制的
[root@f7ab6d1d8b37 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
-1
[root@f7ab6d1d8b37 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
100000
- 写一个死循环,并放到后台执行,记下后台进程的PID
[root@f7ab6d1d8b37 /]# sh deadloop.sh &
[1] 39
[root@f7ab6d1d8b37 /]# cat deadloop.sh
while true :;
do :;
done
[root@f7ab6d1d8b37 /]#
后台进程的PID=39
-
使用top查看刚才死循环的CPU使用率100%
cpu_100.png
- 现在使用限制cpu方式启动容器,
设置cpu 100ms(即100000us)可以使用30ms(即30000us)
docker run -it --cpu-period=100000 --cpu-quota=30000 centos /bin/bash
-
查看cgroup中的参数设置
cgroup30.png - 运行同样的死循环程序
[root@c10f06c1832b /]# sh deadloop.sh &
[1] 17
[root@c10f06c1832b /]# cat deadloop.sh
while true :;
do :;
done
后台进程的PID=17
-
使用top查看刚才死循环的CPU使用率约等于30%,说明CPU使用率设置生效。
top30.png
其他类型的Cgroup也是使用类似的方式做资源限制的。
网友评论