云原生之深入解析如何限制Kubernetes集群中文件描述符与线程数量

一、背景

  • linux 中为了防止进程恶意使用资源,系统使用 ulimit 来限制进程的资源使用情况(包括文件描述符,线程数,内存大小等)。同样地在容器化场景中,需要限制其系统资源的使用量。
  • ulimit: docker 默认支持 ulimit 设置,可以在 dockerd 中配置 default-ulimits 可为宿主机所有容器配置默认的 ulimit,docker 启动时可添加 –ulimit 为每个容器配置 ulimit 会覆盖默认的设置,目前 k8s 暂不支持 ulimit。
  • cgroup: docker 默认支持 cgroup 中内存、cpu、pid 等的限制,对于线程限制可通过 –pids-limit 可限制每个容器的 pid 总数,dockerd 暂无默认的 pid limit 设置;k8s 限制线程数,可通过在 kubelet 中开启 SupportPodPidsLimit 特性,设置 pod 级别 pid limit。
  • /etc/securiy/limits.conf,systcl.confg:通过 ulimit 命令设置只对当前登录用户有效,永久设置可通过 limits.conf 配置文件实现,以及系统级别限制可通过 systcl.confg 配置文件。

二、实验对比

① 环境

  • 本地环境:os: Ubuntu 16.04.6 LTS 4.4.0-154-generic docker: 18.09.7 base-image: alpine:v3.9
  • k8s 环境:kubelet: v1.10.11.1 docker: 18.09.6

② ulimit

  • 用户级别资源限制,分为 soft 限制与 hard 限制;
    • soft :用户可修改,但不能超过硬限制;
    • hard:只有 root 用户可修改;
  • 修改方式:ulimit 命令,临时修改;/etc/security/limits.conf,永久修改;
  • 工作原理:根据 PAM ( Pluggable Authentication Modules 简称 PAM)机制,应用程序启动时,按 /etc/pam.d 配置加载 pam_xxxx.so 模块。/etc/pam.d 下包含了 login 、sshd 、su 、sudo 等程序的 PAM 配置文件, 因此用户重新登录时,将调用 pam_limits.so 加载 limits.conf 配置文件。

三、文件描述符限制

RLIMIT_NOFILEThis specifies a value one greater than the maximum filedescriptor number that can be opened by this process.Attempts (open(2), pipe(2), dup(2), etc.)  to exceed thislimit yield the error EMFILE.  (Historically, this limit wasnamed RLIMIT_OFILE on BSD.)Since Linux 4.5, this limit also defines the maximum number offile descriptors that an unprivileged process (one without theCAP_SYS_RESOURCE capability) may have "in flight" to otherprocesses, by being passed across UNIX domain sockets.  Thislimit applies to the sendmsg(2) system call.  For furtherdetails, see unix(7).
  • 根据定义,nofile 限制进程所能最多打开的文件数量,作用范围进程:
    • 设置 ulimit nofile 限制 soft 100/hard 200,默认启动为 root 用户;
$ docker run -d --ulimit nofile=100:200  cr.d.xiaomi.net/containercloud/alpine:webtool top
    • 进入容器查看, fd soft 限制为 100 个:
/ # ulimit -a
-f: file size (blocks)             unlimited
-t: cpu time (seconds)             unlimited
-d: data seg size (kb)             unlimited
-s: stack size (kb)                8192
-c: core file size (blocks)        unlimited
-m: resident set size (kb)         unlimited
-l: locked memory (kb)             64
-p: processes                      unlimited
-n: file descriptors               100
-v: address space (kb)             unlimited
-w: locks                          unlimited
-e: scheduling priority            0
-r: real-time priority             0
    • 使用 ab 测试,并发 90 个 http 请求,创建 90 个 socket,正常运行:
/ # ab -n 1000000 -c 90 http://61.135.169.125:80/ &
/ # lsof | wc -l 
108
/ # lsof | grep -c ab
94
    • 并发 100 个 http 请求,受到 ulimit 限制:
/ #  ab -n 1000000 -c 100 http://61.135.169.125:80/
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 61.135.169.125 (be patient)
socket: No file descriptors available (24)

四、线程限制

RLIMIT_NPROCThis is a limit on the number of extant process (or, more pre‐cisely on Linux, threads) for the real user ID of the callingprocess.  So long as the current number of processes belongingto this process's real user ID is greater than or equal tothis limit, fork(2) fails with the error EAGAIN.The RLIMIT_NPROC limit is not enforced for processes that haveeither the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capability.
  • 由定义可知,nproc 进程限制的范围是对于每个 uid,并且对于 root 用户无效。

五、容器 uid

  • 同一主机上运行的所有容器共享同一个内核(主机的内核),docker 通过 namspace 对 pid/utc/network 等进行了隔离,虽然 docker 中已经实现了 user namespace,但由于各种原因,默认没有开启,见 docker user namespace:
$ docker run -d  cr.d.xiaomi.net/containercloud/alpine:webtool top
  • 宿主机中查看 top 进程,显示 root 用户:
$ ps -ef |grep top
root      4096  4080  0 15:01 ?        00:00:01 top
  • 容器中查看 id,uid 为 0 对应宿主机的 root 用户,虽然同为 root 用户,但 Linux Capabilities 不同,实际权限与宿主机 root 要少很多。
  • 在容器中切换用户到 operator(uid 为 11),执行 sleep 命令,主机中查看对应进程用户为 app,对应 uid 同样为 11:
/ # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/ # su operator
/ $ id
uid=11(operator) gid=0(root) groups=0(root)
/ $ sleep 100
$ ps -ef |grep 'sleep 100'
app      19302 19297  0 16:39 pts/0    00:00:00 sleep 100
$ cat /etc/passwd | grep app
app❌11:0::/home/app:

六、验证不同用户下 ulimit 的限制

  • 设置 ulimit nproc 限制 soft 10/hard 20,默认启动为 root 用户:
$ docker run -d --ulimit nproc=10:20  cr.d.xiaomi.net/containercloud/alpine:webtool top
  • 进入容器查看, fd soft 限制为 100 个:
/ # ulimit -a
-f: file size (blocks)             unlimited
-t: cpu time (seconds)             unlimited
-d: data seg size (kb)             unlimited
-s: stack size (kb)                8192
-c: core file size (blocks)        unlimited
-m: resident set size (kb)         unlimited
-l: locked memory (kb)             64
-p: processes                      10
-n: file descriptors               1048576
-v: address space (kb)             unlimited
-w: locks                          unlimited
-e: scheduling priority            0
-r: real-time priority             0
  • 启动 30 个进程:
/ # for i in `seq 30`;do sleep 100 &; done
/ # ps | wc -l 
36
  • 切换到 operator 用户:
/ # su operator# 启动多个进程,到第11个进程无法进行fork
/ $ for i in `seq 8`; do
> sleep 100 &
> done
/ $ sleep 100 &
/ $ sleep 100 &
sh: can't fork: Resource temporarily unavailable
  • root 下查看:
/ # ps -ef | grep operator79 operator  0:00 sh99 operator  0:00 sleep 100100 operator  0:00 sleep 100101 operator  0:00 sleep 100102 operator  0:00 sleep 100103 operator  0:00 sleep 100104 operator  0:00 sleep 100105 operator  0:00 sleep 100106 operator  0:00 sleep 100107 operator  0:00 sleep 100109 root      0:00 grep operator
/ # ps -ef | grep operator| wc -l
10

七、验证 ulimit 在不同容器相同 uid 下的限制

  • 设置 ulimit nproc 限制 soft 3/hard 3,默认启动为 operator 用户,起 4 个容器,第四个启动失败:
$ docker run -d --ulimit nproc=3:3 --name nproc1 -u operator  cr.d.xiaomi.net/containercloud/alpine:webtool top
eeb1551bf757ad4f112c61cc48d7cbe959185f65109e4b44f28085f246043e65
$ docker run -d --ulimit nproc=3:3 --name nproc2 -u operator  cr.d.xiaomi.net/containercloud/alpine:webtool top
42ff29844565a9cb3af2c8dd560308b1f31306041d3dbd929011d65f1848a262
$ docker run -d --ulimit nproc=3:3 --name nproc3 -u operator  cr.d.xiaomi.net/containercloud/alpine:webtool top
b7c9b469e73f969d922841dd77265467959eda28ed06301af8bf83bcf18e8c23
$ docker run -d --ulimit nproc=3:3 --name nproc4 -u operator  cr.d.xiaomi.net/containercloud/alpine:webtool top
b49d8bb58757c88f69903059af2ee7e2a6cc2fa5774bc531941194c52edfd763
$
$ docker ps -a |grep nproc
b49d8bb58757        cr.d.xiaomi.net/containercloud/alpine:webtool      "top"                    16 seconds ago      Exited (1) 15 seconds ago                               nproc4
b7c9b469e73f        cr.d.xiaomi.net/containercloud/alpine:webtool      "top"                    23 seconds ago      Up 22 seconds                                           nproc3
42ff29844565        cr.d.xiaomi.net/containercloud/alpine:webtool      "top"                    31 seconds ago      Up 29 seconds                                           nproc2
eeb1551bf757        cr.d.xiaomi.net/containercloud/alpine:webtool      "top"                    38 seconds ago      Up 36 seconds                                           nproc1

八、总结

① ulimit

  • ulimit 限制 fd 总数,限制级别进程,可对所有用户生效;
  • ulimit 限制线程总数,限制级别用户(uid),限制同一个 uid 下所有线程/进程数,对于 root 账号无效;
  • 对于目前线上情况,有较小的概率因 ulimit 限制导致 fork 失败,如同一个宿主机中有多个 work 容器且基础镜像相同(即 uid 相同),若一个容器线程泄露,由于 ulimit 限制会影响其他容器正常运行。

② cgroup

  • cgroup 中对 pid 进行了隔离,通过更改 docker/kubelet 配置,可以限制 pid 总数,从而达到限制线程总数的目的。线程数限制与系统中多处配置有关,取最小值,参考 stackoverflow 上线程数的设置:
    • docker,容器启动时设置 –pids-limit 参数,限制容器级别 pid 总数;
    • kubelet,开启 SupportPodPidsLimit 特性,设置 –pod-max-pids 参数,限制 node 每个 pod 的 pid 总数,以 kubelet 为例,开启 SupportPodPidsLimit,–feature-gates=SupportPodPidsLimit=true
  • 配置 kubelet,每个 pod 允许最大 pid 数目为 150:
[root@node01 ~]# ps -ef |grep kubelet
root     18735     1 14 11:19 ?        00:53:28 ./kubelet --v=1 --address=0.0.0.0 --feature-gates=SupportPodPidsLimit=true --pod-max-pids=150 --allow-privileged=true --pod-infra-container-image=cr.d.xiaomi.net/kubernetes/pause-amd64:3.1 --root-dir=/home/kubelet --node-status-update-frequency=5s --kubeconfig=/home/xbox/kubelet/conf/kubelet-kubeconfig --fail-swap-on=false --max-pods=254 --runtime-cgroups=/systemd/system.slice/frigga.service --kubelet-cgroups=/systemd/system.slice/frigga.service --make-iptables-util-chains=false
  • 在 pod 中起测试线程,root 下起 100 个线程:
/ # for i in `seq 100`; do
> sleep 1000 &
> done
/ # ps | wc -l
106
  • operator 下,创建线程受到限制,系统最多只能创建 150 个:
/ # su operator
/ $ 
/ $ for i in `seq 100`; do
> sleep 1000 &
> done
sh: can't fork: Resource temporarily unavailable
/ $ ps | wc -l
150
  • 在 cgroup 中查看,pids 达到最大限制:
[root@node01 ~]# cat /sys/fs/cgroup/pids/kubepods/besteffort/pod8b61d4de-a7ad-11e9-b5b9-246e96ad0900/pids.current 
150
[root@node01 ~]# cat /sys/fs/cgroup/pids/kubepods/besteffort/pod8b61d4de-a7ad-11e9-b5b9-246e96ad0900/pids.max 
150
  • 总结 cgroup 对于 pid 的限制能够达到限制线程数目的,目前 docker 只支持对每个容器的限制,不支持全局配置;kubelet 只支持对于 node 所有 pod 的全局配置,不支持具体每个 pod 的配置。

③ limits.conf/sysctl.conf

  • limits.conf 是 ulimit 的具体配置,目录项 /etc/security/limit.d/ 中的配置会覆盖 limits.conf。
  • sysctl.conf 为机器级别的资源限制,root 用户可修改,目录项 /etc/security/sysctl.d/ 中的配置会覆盖 sysctl.conf,在 /etc/sysctl.conf 中添加对应配置(fd: fs.file-max = {}; pid: kernel.pid_max = {})
  • 测试容器中修改 sysctl.conf 文件:
$ docker run -d --ulimit nofile=100:200 cr.d.xiaomi.net/containercloud/alpine:webtool top
cb1250c8fd217258da51c6818fa2ce2e2f6e35bf1d52648f1f432e6ce579cf0d
$ docker exec -it cb1250c sh/ # ulimit -a
-f: file size (blocks)             unlimited
-t: cpu time (seconds)             unlimited
-d: data seg size (kb)             unlimited
-s: stack size (kb)                8192
-c: core file size (blocks)        unlimited
-m: resident set size (kb)         unlimited
-l: locked memory (kb)             64
-p: processes                      unlimited
-n: file descriptors               100
-v: address space (kb)             unlimited
-w: locks                          unlimited
-e: scheduling priority            0
-r: real-time priority             0
/ # 
/ # echo 10 > /proc/sys/kernel/pid_max
sh: can't create /proc/sys/kernel/pid_max: Read-only file system
/ # echo 10 > /proc/sys/kernel/pid_max
sh: can't create /proc/sys/kernel/pid_max: Read-only file system
/ # echo "fs.file-max=5" >> /etc/sysctl.conf
/ # sysctl -p
sysctl: error setting key 'fs.file-max': Read-only file system
  • 以 priviledged 模式测试,谨慎测试:
$ cat /proc/sys/kernel/pid_max
32768
$ docker run -d -- --ulimit nofile=100:200 cr.d.xiaomi.net/containercloud/alpine:webtool top
$ docker exec -it pedantic_vaughan sh
/ # cat /proc/sys/kernel/pid_max
32768
/ # echo 50000 > /proc/sys/kernel/pid_max
/ # cat /proc/sys/kernel/pid_max
50000
/ # exit
$ cat /proc/sys/kernel/pid_max
50000 # 宿主机的文件也变成50000
  • 由于 docker 隔离的不彻底,在 docker 中修改 sysctl 会覆盖主机中的配置,不能用来实现容器级别资源限制 limits.conf 可以在容器中设置,效果同 ulimit。

在这里插入图片描述

  • 推荐方案如下:
    • fd 限制:修改 dockerd 配置 default-ulimits,限制进程级别 fd;
    • thread 限制:修改 kubelet 配置 --feature-gates=SupportPodPidsLimit=true - -pod-max-pids={},cgroup 级别限制 pid,从而限制线程数;
    • 其他注意事项,调整节点 pid.max 参数;放开或者调大镜像中 ulimit 对非 root 账户 nproc 限制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/197956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

08、分析测试执行时间及获取pytest帮助

官方用例 # content of test_slow_func.py import pytest from time import sleeppytest.mark.parametrize(delay,(1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,1.0,0.1,0.2,0,3)) def test_slow_func(delay):print("test_slow_func {}".format(delay))sleep(delay)assert…

概率论中,相关性和独立性的关系

相关性和独立性是概率统计中两个关键的概念。 相关性&#xff08;Correlation&#xff09;&#xff1a; 定义&#xff1a; 相关性衡量两个变量之间的线性关系程度。如果两个变量的值在某种趋势下同时变化&#xff0c;我们说它们是相关的。相关性的取值范围在 -1 到 1 之间&…

同旺科技 USB TO SPI / I2C --- 调试W5500_TCP Client测试

所需设备&#xff1a; 内附链接 1、USB转SPI_I2C适配器(专业版); 首先&#xff0c;连接W5500模块与同旺科技USB TO SPI / I2C适配器&#xff0c;如下图&#xff1a; 网关IP地址寄存器(192.168.1.1)子网掩码寄存器(255.255.255.0)源MAC地址寄存器源IP地址寄存器(192.168.1.8)…

Django 模型基础(五)

一、models常用字段类型 (一 ) 索引&#xff0c;字符&#xff0c;数字 1、models.AutoField 自增列 如果没有&#xff0c;默认会生成一个名称为 id 的列&#xff0c; 如果要显示的自定义一个自增列&#xff0c;必须将给列设置为主键 primary_keyTru…

Maven 安装自己的依赖

命令 比如当前目录下的依赖包名称是 mytoolutils.jar&#xff0c;则在当前目录下执行 mvn install:install-file -Dfilemytoolutils.jar -DgroupIdutils -DartifactIdtool -Dversion1.0.0 -Dpackagingjar 引用 pom.xml 中引用 <dependency><groupId>utils</g…

ThreadPoolExecutor应用源码剖析(三)

3.3.5 ThreadPoolExecutor的Worker工作线程 Worker对象主要包含了两个内容 ● 工作线程要执行任务 ● 工作线程可能会被中断&#xff0c;控制中断 // Worker继承了AQS&#xff0c;目的就是为了控制工作线程的中断。 // Worker实现了Runnable&#xff0c;内部的Thread对象&…

QT4和 QT5 槽函数连接的区别

正常连接方式 //QT4官方用列QLabel *label new QLabel;QScrollBar *scrollBar new QScrollBar;QObject::connect(scrollBar, SIGNAL(valueChanged(int)),label, SLOT(setNum(int)));//QT5官方用列QLabel *label new QLabel;QLineEdit *lineEdit new QLineEdit;QObject::c…

STK Components 二次开发-飞行器

1.创建飞机 参数帮助文档 var poitList GetTracksData(); var waypointPropagator new WaypointPropagator(m_earth, poitList); var locationPoint waypointPropagator.CreatePoint();m_aircraft new Platform {Name "MH730",LocationPoint locationPoint,Or…

首次部署Linux系统的经历

我是一名电子信息工程专业的学生&#xff0c;有次在图书馆上自习的时候无意间看到其他同学的电脑屏幕&#xff0c;黑色的屏幕上显示着一行一行的代码&#xff0c;勾起了我无限的好奇&#xff0c;经过询问得知他是用的Linux操作系统&#xff0c;是和Windows完全不同的系统&#…

JDBC操作

本博客主要是介绍JDBC操作&#xff0c;即通过编译器操纵数据库中的数据。接下来以插入操作简单介绍该操作。 首先在创建的项目中&#xff0c;添加下列jar包&#xff08;点击可加载下载页面&#xff09;。 mysql-connector-java-5.1.49.jar 然后编写JDBC代码 public class JDB…

vue3 中使用 sse 最佳实践,封装工具

工具 // 接受参数 export interface SSEChatParams {url: string,// sse 连接onmessage: (event: MessageEvent) > void,// 处理消息的函数onopen: () > void,// 建立连接触发的事件finallyHandler: () > void,// 相当于 try_finally 中的 finally 部分&#xff0c;不…

机器学习(2)回归

0.前提 上一期&#xff0c;我们简单的介绍了一些有关机器学习的内容。学习机器学习的最终目的是为了服务我未来的毕设选择之一——智能小车&#xff0c;所以其实大家完全可以根据自己的需求来学习这门课&#xff0c;我做完另一辆小车后打算花点时间去进行一次徒步行&#xff0…

C++现代模板元编程

序 个人发现很多国外的大佬的演讲或者文章都很不错&#xff0c;但是鲜有人来进行分享&#xff0c;届后本人会时不时拿一些看起来很好的东西来给大家分享&#xff0c;主要也是搬运&#xff0c;不过也省去了大家去读英文的麻烦&#xff0c;同时文章中也会参杂着一些自己的见解。…

游戏mod制作--引擎与解包

摘要 游戏mod的制作过程第一步就是需要将原始的游戏工程文件进行解包&#xff0c;得到相应的资源文件&#xff08;贴图&#xff0c;音频&#xff0c;事件&#xff0c;模型甚至源代码等&#xff09;&#xff0c;这个时候下一步就是需要将解包出来的文件进行分类索引&#xff0c…

服务器内存使用率高的原因及解决方法_Maizyun

服务器内存使用率高的原因及解决方法 在服务器运行过程中&#xff0c;内存使用率过高可能会引发一系列问题&#xff0c;如性能下降、应用程序崩溃等。本文将深入探讨服务器内存使用率高的原因&#xff0c;并提出相应的解决方法。 一、内存使用率高的原因 应用程序缺陷&#…

20:kotlin 类和对象 --泛型(Generics)

类可以有类型参数 class Box<T>(t: T) {var value t }要创建类实例&#xff0c;需提供类型参数 val box: Box<Int> Box<Int>(1)如果类型可以被推断出来&#xff0c;可以省略 val box Box(1)通配符 在JAVA泛型中有通配符?、? extends E、? super E&…

25. K 个一组翻转链表

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值…

自媒体原创改写工具,自媒体首发改写软件

自媒体平台已成为许多创作者表达观点、分享知识和积累影响力的关键渠道。创作是需要技巧和经验的。本文将分享一些自媒体文章改写技巧&#xff0c;并推荐一系列优秀的自媒体文章改写工具&#xff0c;帮助您提升创作效率&#xff0c;创作出更优秀的文章。 自媒体文章改写技巧 …

Backend - Django makemigrations

目录 一、迁移命令 &#xff08;一&#xff09;前提 &#xff08;二&#xff09;生成迁移文件 &#xff08;三&#xff09;执行迁移 二、迁移问题 1. Error&#xff1a;No changes detected 2. Error&#xff1a;You are trying to add a non-nullable field XXX to XXX…

[读论文]BK-SDM: A Lightweight, Fast, and Cheap Version of Stable Diffusion

github: GitHub - Nota-NetsPresso/BK-SDM: A Compressed Stable Diffusion for Efficient Text-to-Image Generation [ICCV23 Demo] [ICML23 Workshop] ICML 2023 Workshop on ES-FoMo 简化方式 蒸馏方式&#xff08;训练Task蒸馏outKD-FeatKD&#xff09; 训练数据集 评测指标…