Docker的内核,性能与调优
首先我们抛出3个问题:
1.docker容器的内核与宿主机内核是怎样的关系?
2.容器在运行时如何调用系统资源?
3.docker的性能参数有没有作用范围?
能够将这3个问题全部解答,关于docker的内核与调优策略便有了一定程度的认识。
一、容器与宿主机的内核关系 —— 共享内核
docker镜像是一个“应用程序和它运行依赖环境”的封装。当镜像运行起来后,即是docker容器。运行时的容器本质是操作系统下的一个进程,这些进程共享同一个宿主机OS的内核。
与传统VM相比,docker是一种操作系统虚拟化技术,并不需要在镜像内安装GuestOS。
docker在共享宿主机内核的基础上包装内核提供的一系列API,这些API中最重要的就是nam
espace和cgroup。通过namespace实现隔离,通过cgroup实现资源限制。
二、Namespace--命名空间
PIDnamespace:每当在此空间中启动一个程序,内核就给它分配唯一的ID。与宿主机所见的不同,容器内的进程都有自己的进程ID空间。
MNTnamespace:每个容器都有自己目录挂载的命名空间。
NETnamespace:每个容器都有自己单独的网络栈,其中的socket和网卡设备都是其他容器不能访问的。
UTSnamespace:在此命名空间中的进程拥有自己的主机名和NIS域名。
IPCnamespace:拥有相同IPC命名空间的进程才可以利用“共享内存、信号量、消息队列”方式进行通信。
User namespace:用于隔离容器中的UID,GID和根目录
三、Cgroup--控制组
顾名思义,控制和分组是用来对进程进行分层分组,在组的粒度上实现资源限制和策略控制。每个容器中的进程都由组策略控制。
Cgroup包含了很多控制器。
Cgroup对进程分组的控制是通过一个虚拟文件系统下的目录节点和节点文件实现的,控制器是目录节点中的文件,文件内容规定了系统资源的配额。
以全局cgroup为例 # ls /sys/fs/cgroup
默认的情况下,docker会在这些目录下面创建自己的节点子目录,而每个容器都会创建自己容器ID的节点子目录;这些目录都包含了对应层次的控制器文件,用于控制每一级的资源配额。下文简述一些控制器的功能:
cpu:限制组中进程的cpu使用量
cpuacct:对进程的CPU使用程度进行计量
memory:限制组中进程的内存使用量,并计量
blkio:限制组中进程对块设备的IO操作
net_prio:用于设置组相关网络包的优先级
hugetlb:用于限制和报告组内进程对大页面的使用量
freezer:用于组内进程的挂起和解冻
四、docker内核与调优
理解了上面的几部分,我们现在应该有个印象:
docker容器共享宿主机OS的内核
docker容器视为一个进程
docker容器的资源配额受docker引擎和宿主机OS限制
所以在进行docker内核调优时,可以推论:
docker的内核参数大多继承自宿主机内核
docker容器可以在某些情况、某些范围内调整自己的内核参数
那么某些情况和某些范围是什么意思呢?下面分享一些特殊情况。
4.1 docker的 --sysctl 参数的白名单
语法:docker run --sysctl key=value IMAGE:TAG CMD
该参数允许docker容器启动时设置某些内核参数,这些参数是有限制的,可以在docker源码中查看到
// docker/
funcValidateSysctl(valstring)(string,error){validSysctlMap:=map[string]bool{"kernel.msgmax":true,"kernel.msgmnb":truedocker进入容器,"kernel.msgmni":true,"kernel.sem":true,"kernel.shmall":true,"kernel.shmmax":true,"kernel.shmmni":true,"kernel.shm_rmid_forced":true,}validSysctlPrefixes:=[]string{"net.","fs.mqueue.",}...
如上所示,只有被标识为 True 的 kernel.*, net.* 以及fs.mqueue.* 是可以传入参数并修改的
如果传入其他参数,会提示:for --sysctl: sysctl'kernel.acpi_video_flags=0' is not whitelisted
即白名单未通过
4.2 容器中看不到的参数
通常容器内可以修改的参数,都是可以通过sysctl -a查看到的,但有些则不行:
例如 _max参数(定义内核用于所有类型的连接的最大接收缓冲大小)
root@host01:~/tmp# sysctl -a | grep rmem_max
_max =212992
root@host01:~/tmp# docker 163/public/debian:7.9 sysctl -a | grep rmem_max
root@host01:~/tmp#
原因是这些参数是隶属于kernel的namespace
4.3 不能被namespace化的参数
当一些内核参数在容器中修改后,会反过来作用于宿主机,这一类内核参数的特点是无法被namespace化;因为docker使用共享内核的机制,大多数和kernel相关的参数都有这样的特点:
# step1.检查当前进程数最大值
root@host01:~/tmp# sysctl -a | grep pid_max
kernel.pid_max =32768
# step2.启动一个测试用的容器,--privileged 表示获得root权限
root@host01:~/tmp# docker run -d --privileged --name 163/public/debian:7.9
a43e89ee85d36e250e60eb9e0e9cfc91848
# step3.在容器内修改进程数最大值

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。