在传统虚拟机领域,通过调整一些系统参数来提供(高)系统性能是一种常见的方法。例如对于经常访问的服务器,可以通过设置net.ipv4.ip_local_port_range=102465000(默认3276861000)让系统开放更多的端口。今天这篇文章的讨论重点不在Linux内核调优的讨论上。传统领域对内核调优的讨论在下面的链接中有更详细的介绍。有兴趣的读者可以了解一下:http://colobu.com/2014/09/18/...。本文主要通过对比docker和linux内核调优的区别来介绍docker容器的内核调优。Docker内核调优与Linux内核调优的区别Docker允许你在启动容器时指定--sysctl参数来设置系统参数,通过这些参数调整系统性能。下面着重介绍一下它与Linux调整系统参数的区别。一般来说,容器比linux的可调项少,容器的可调参数需要满足三个条件:1.不受docker限制Docker使用一个ValidateSysctl函数来限制sysctl参数可以传入的项。源码是如下://docker/opts/opts.gofuncValidateSysctl(valstring)(string,error){validSysctlMap:=map[string]bool{"kernel.msgmax":true,"kernel.msgmnb":true,"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.",}...也就是说只有上面列出的kernel.xxx部分和以net为前缀的部分。和fs.mqueue允许由docker调整。如果尝试调整其他项,会报whitelistverificationfailederror:root@hzwangxing01:~/tmp#dockerrun-it--sysctlkernel.acpi_video_flags=0hub.c.163.com/public/debian:7.9bashinvalid--sysctl的参数“kernel.acpi_video_flags=0”:sysctl'kernel.acpi_video_flags=0'未列入白名单2。该配置项在容器中可见,在所有主机上不可见。在容器中都是可见的,比如net.core.rmem_max参数(定义内核对所有类型连接使用的最大接收缓冲区大小):root@hzwangxing01:~/tmp#sysctl-a|greprmem_maxnet.core.rmem_max=212992root@hzwangxing01:~/tmp#dockerrunhub.c.163.com/public/debian:7.9sysctl-a|greprmem_maxroot@hzwangxing01:~/tmp#之所以在容器中不可见与docker无关,应该是kernelnamespaceissue3。配置项可以命名空间。配置项不能带命名空间,也就是说配置项是全局的,不能为每个命名空间生成独立的配置。一般来说,主机和容器是一对多的关系。一个不能命名空间的配置项,调整后会影响所有其他容器和宿主机本身,这是我们无法接受的。一个典型的例子是,由于容器共享内核的特性,大部分与内核相关的参数都不能命名空间。例如:root@hzwangxing01:~/tmp#sysctl-a|greppid_maxkernel.pid_max=32768root@hzwangxing01:~/tmp#dockerrun-d--privileged--nametesthub.c.163.com/public/debian:7.9a43e89ee85d36e250e0886331e9d6213094f31260eb9e1539b83f0e9cfc91848root@hzwangxing01:~/tmp#dockerexectestsysctl-wkernel.pid_max=86723kernel.pid_max=86723root@hzwangxing01:~/tmp#sysctl-a|greppid_maxkernel.pid_max=86723从上面的例子可以看出来,如果容器中设置了内核的pid_max属性,相应地,宿主机的相应属性也会被修改。限制条件组合详解根据上面列出的三个docker设置参数,简单画个图然后展开说明:上图是一个简单的韦氏图:dvn:满足三个条件的属性集可以通过在参数设置中通过--sysctl并达到预期效果dv(只满足d和v,即d&&v&&!n):虽然满足其他条件,但是不能命名空间的属性集是无法修复的,除非你自己修改kernel,patch(不推荐)dn:在容器中不可见,不能通过--sysctl设置,会报错relatedfilescannotfindroot@hzwangxing01:~/tmp#dockerrun-d--sysctlnet.core.rmem_max=1024hub.c.163.com/public/debian:7.9e2353339b7c9ef52a573d92c0136a20ab7373fc7e06345575cf5efe4cf10256adocker:来自守护程序的错误响应:无效的头字段值“oci运行时错误:container_linux.go:247:启动容器进程导致”process_linux:it359.goincontainer导致\"打开/proc/sys/net/core/rmem_max:没有这样的文件或目录\""n"。这种情况是无法修复的。vn:这个类别是可以修复的,只需要在docker源码中添加一个白名单项即可d,v,n:由于不能同时满足“在容器中可见”和“可命名空间”这两个条件,所以这三个类别也是不可挽回的补充说明。这里需要指出的一点是,有些人可能会认为满足条件d的是docker验证同时支持dvn的。不幸的是,这种情况并非如此。Docker明确定义的内核调整项和fs.mqueue前缀项确实可以同时兼容dvn,但主要问题还是在于net前缀项过于宽泛。还有一些不符合vn的词条,这里就不一一解释了。.从上面的讨论可以得出Docker的可配置项,只有dvn和vn(对docker代码稍做调整)是可配置的,所以所有的可配置项都包含dvn+vn,即v&&n,其中:v容易获取,只需在正在运行的容器中使用sysctl-a即可查看所有可见的配置项;在v的基础上,找出可以命名空间的配置项,这个方法在上面的例子中其实已经用过了,这里再强调一下:启动一个有privileged权限的容器(保证你有设置配置的权限容器中的项),在容器中使用sysctl-w将某个配置项设置为不同的值,并确认宿主机上的配置是否改变,如果没有改变,则说明该项满足n。通过这两步,就可以得到当前环境下所有的容器内核可调配置集。
