Docker的内核,性能与调优

摘要:
Docker内核、性能和调优。首先,我们提出三个问题:Docker容器内核和主机内核之间的关系是什么?Docker的性能参数有范围吗?如果你能回答这三个问题,你将对Docker的内核和调优策略有一定的了解。当映像运行时,它是Docker容器。与传统VM相比,Docker是一种操作系统虚拟化技术,不需要在映像中安装GuestOS。Docker在共享主机内核的基础上打包了内核提供的一系列API。这些API中最重要的是命名空间和cgroup。
Docker的内核,性能与调优

首先我们抛出3个问题:

  1. docker容器的内核与宿主机内核是怎样的关系?
  2. 容器在运行时如何调用系统资源?
  3. docker的性能参数有没有作用范围?

能够将这3个问题全部解答,关于docker的内核与调优策略便有了一定程度的认识。

 

一、容器与宿主机的内核关系 —— 共享内核

docker镜像是一个“应用程序和它运行依赖环境”的封装。当镜像运行起来后,即是docker容器。运行时的容器本质是操作系统下的一个进程,这些进程共享同一个宿主机OS的内核。

与传统VM相比,docker是一种操作系统虚拟化技术,并不需要在镜像内安装GuestOS。

docker在共享宿主机内核的基础上包装内核提供的一系列API,这些API中最重要的就是namespace和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的内核,性能与调优第1张

默认的情况下,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/opts/opts.go
func ValidateSysctl(val string) (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.",   
 } 
...

如上所示,只有被标识为 True 的 kernel.*, net.* 以及fs.mqueue.* 是可以传入参数并修改的

如果传入其他参数,会提示:for --sysctl: sysctl'kernel.acpi_video_flags=0' is not whitelisted

即白名单未通过

 

4.2 容器中看不到的参数

通常容器内可以修改的参数,都是可以通过sysctl -a查看到的,但有些则不行:

例如 net.core.rmem_max参数(定义内核用于所有类型的连接的最大接收缓冲大小)

root@host01:~/tmp# sysctl -a | grep rmem_max
net.core.rmem_max = 212992
root@host01:~/tmp# docker run hub.c.163.com/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 test hub.c.163.com/public/debian:7.9
a43e89ee85d36e250e0886331e9d6213094f31260eb9e1539b83f0e9cfc91848

# step3.在容器内修改进程数最大值
root@host01:~/tmp# docker exec test sysctl -w kernel.pid_max=86723    
kernel.pid_max = 86723

# step4.再次检查进程数最大值,发现变更成了上一步docker容器内设定的值
root@host01:~/tmp# sysctl -a | grep pid_max
kernel.pid_max = 86723

引入3中特殊情况对应的图形:

Docker的内核,性能与调优第2张1 doker 表示在白名单内; 2 visible 表示sysctl -a 容器内可见;3 namespace 表示不影响全局

综上,我们可以得出结论:

  • 程序白名单以外的参数不可调整;想调整请修改docker源码
  • 容器内systcl看不到的继承自宿主机
  • 容器内能影响宿主机的不要修改

针对docker容器的内存调优策略:

  • 请尽量在宿主机OS进行内核优化操作;
  • 需要特化&满足条件的参数请通过 --sysctl参数传入或写入dockerfile

 

五、操作系统参数调优

限于篇幅,本文对于操作系统的参数调优不再阐述,给与几篇相关扩展阅读:

  1. 文件句柄数 ulimit -n & /etc/security/limits.conf
  2. Docker Container继承自Docker Daemon的ulimit设置,也可以修改/etc/sysconfig/docker,指定docker-deamon启动参数
  3. TCP/IP协议栈优化、内核参数默认值和建议值

 

免责声明:文章转载自《Docker的内核,性能与调优》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇vs开启工程非常卡分析和解决应用程序开机自动启动(不登录账号)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

清理Docker占用的磁盘空间,迁移 /var/lib/docker 目录

https://blog.csdn.net/weixin_32820767/article/details/81196250?utm_source=blogxgwz0du -hs /var/lib/docker/ 命令查看磁盘使用情况。 linlf@dacent:~$ sudo du -hs /var/lib/docker/ 237G /var/l...

生产环境中使用Docker Swarm的一些建议

译者按: 实践中会发现,生产环境中使用单个Docker节点是远远不够的,搭建Docker集群势在必行。然而,面对Kubernetes, Mesos以及Swarm等众多容器集群系统,我们该如何选择呢?它们之中,Swarm是Docker原生的,同时也是最简单,最易学,最节省资源的,至少值得我们多了解一下。本文将介绍一些非常实用的建议。 原文: Tips for...

Docker 部署Confluence15.2

一、数据库准备 数据库版本:5.7 这里数据库并没有采用docker镜像方式,而是选择已有数据库。至于数据库安装这里不再说明。 注:我这里安装confluence时,需要在下面配置数据库信息时,在数据库地址链接后面加上?sessionVariables=tx_isolation='READ-COMMITTED',否则会报错 1) 创建数据库并授权 cre...

docker安装db2数据库

查询可安装的db2镜像 # docker search db2 [root@docker-servers ~]# docker search db2 INDEX NAME DESCRIPTION S...

使用docker安装宝塔面板

后端使用的命令太多了,容易忘记,所以记录在本文中,以便将来查询: 列出所有的容器 ID docker ps -aq 停止所有的容器 docker stop $(docker ps -aq) 删除所有的容器 docker rm $(docker ps -aq) 删除所有的镜像 docker rmi $(docker images -q) docker i...

Ubantu 16.04升级内核版本和还原到升级之前的内核版本的方法

一、查看系统信息 1、查看发布版本: 命令: lsb_release -a 运行结果: / 2、查看内核版本: 命令: uname -sr 运行结果: 二、升级内核的方法 1、内核下载地址:http://kernel.ubuntu.com/~kernel-ppa/mainline/ 。打开地址后,拖动鼠标到网页最底端,找到最新版本的内核v4.15...