橘子学K8S02之容器中所谓的限制

这篇具有很好参考价值的文章主要介绍了橘子学K8S02之容器中所谓的限制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前面我们知道了关于隔离在Linux中的实现是通过一组NameSpace做到的,而且实际上他只是修改了应用进程看到计算机的视图,对他的视野做了限制,只能看到某些特定的内容,但是当你把视角切换到宿主机的操作系统来看的时候,这些所谓的容器和被隔离的进程其实和其他进程没有区别。
这使得他作为一个容器就很便捷的实现了一些隔离功能,但是这个优点也不是很牛逼的,他和虚拟化技术相比有很多不足之处,就是隔离的不彻底。

首先既然容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的其实还就是一个宿主机的操作系统内核。
尽管你可以在容器中通过前面说的Mount Namespae单独挂载其他不同版本的操作系统文件,但是这也不能改变他共享宿主机内核的事实,这就意味着,如果你在win的宿主机上运行Linux容器,或者在低版本上的Linux宿主机上运行高版本的linux容器都是行不通的,因为他们的宿主机的内核版本不一样,这肯定无法共享。而相比之下,拥有硬件虚拟化技术和独立Guest OS 的虚拟机就要方便得多了,最极端的例子就是Microsoft 的云计算平台Azure ,实际上就是运行在win服务器集群上的,但这并不妨碍你在它上面创建各种Linux虚拟机出来。

其次,在Linux内核中,很多资源和对象是不能Namespacce化的,最典型的例子就是:时间。
这就意味着,如果你的容器中的程序使用settimeofday(2)系统调用修改了时间,整个宿主机的时间都会被随之修改,这显然不符合用户的预期,想比在虚拟机里面这种里面完全的虚拟化,甚至连硬件资源都是能虚拟化的,你可以随意折腾,啥都能做。但是容器里部署应用的时候,什么能做,什么不能做,就得是用户必须考虑的一个问题。
所以我们现在可以了解一下关于限制的问题了。

一、关于限制

前面我们通过Namespace技术成功的把容器隔离在自己的一个视角下,现在你的容器进程成功被隔离开了。但是为什么还是需要限制呢?
我们说过,隔离的各个容器之间虽然是看不到其他的进程的,但是他们之间还是共享的宿主机的内核资源。换言之你多个容器之间其实还是在一起使用内核资源。比如cpu 比如内存,你的隔离进程自己就可以占用到百分之百,吃尽所有的资源。当然你的资源也可能被其他的隔离进程抢占。这种模式下的沙盒显然和我们理解的那种隔离不是一个概念,所以就需要做到限制每个沙盒的资源。

而 Linux Cgroups 就是 Linux 内核中用来为进程设置资源限制的一个重要功能。Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。此外,Cgroups 还能够对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。拥有控制这些资源的能力,不仅仅是限制,当然我们这里只研究一下限制,毕竟这是容器的一个核心概念。

二、Cgroups的使用

在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。简单来说他是一组文件,通过文件暴露给用户,供你使用功能,他的功能就封装在这组文件中,在 我的机器里,我可以用 mount 指令把它们展示出来,这条命令是:

mount -t cgroup
显示出所有挂载类型为cgroup的文件。我的内容为:
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_prio,net_cls)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)

橘子学K8S02之容器中所谓的限制,# K8S,kubernetes,容器,云原生
它的输出结果,是一系列文件系统目录。如果你在自己的机器上没有看到这些目录,那你就需要自己去挂载 Cgroups。
可以看到,在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是我这台机器当前可以被 Cgroups 进行限制的资源种类。比如说/sys/fs/cgroup/cpu这个就表示我的系统可以限制cpu,因为group挂载文件里面包含cpu的限制类型。

而在子系统对应的资源种类下,你就可以看到该类资源具体可以被限制的方法。比如,对 CPU 子系统来说,我们就可以看到如下几个配置文件,这个指令是:

列出所有的cpu限制资源的限制方法:
ls /sys/fs/cgroup/cpu

橘子学K8S02之容器中所谓的限制,# K8S,kubernetes,容器,云原生
你会在它的输出里注意到 cfs_period 和 cfs_quota 这样的关键词。这两个参数需要组合使用,可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 CPU 时间。也就是说他能够限制你的进程对cpu的使用,在一段时间内系统分配给你这个进程的时间长度。我们就可以通过操作这个参数来限制我们的容器对于cpu的占用率。

1、cgroups限制cpu资源

而这样的配置文件又如何使用呢?你需要在对应的子系统下面创建一个目录,比如,我们现在进入 /sys/fs/cgroup/cpu 目录下,然后创建一个叫做levi的目录:mkdir levi

[root@iZ2ze1q2h6sy9dblhemmhmZ cpu]# ls ./levi/
cgroup.clone_children  cgroup.event_control  cgroup.procs  cpuacct.stat  cpuacct.usage  cpuacct.usage_percpu  cpu.cfs_period_us  cpu.cfs_quota_us  cpu.rt_period_us  cpu.rt_runtime_us  cpu.shares  cpu.stat  notify_on_release  tasks

此时我们发现在我创建好levi目录之后,系统会为我们在这个目录下自动建立一系列的文件,其实就是我们在cpu的限制目录下建立了一个目录,自动就创建了一堆可以用来限制cpu的文件。此时我们的这个levi文件夹就被称之为一个控制组,自动生成该子系统(cpu子系统)对应的一组资源限制文件。
然后,我们在后台执行这样一条脚本:该脚本的含义就是死循环,把cup拉到百分百。

$ while : ; do : ; done &

橘子学K8S02之容器中所谓的限制,# K8S,kubernetes,容器,云原生
执行之后我们看到我们这个shell脚本的进程就被启动了,他的进程号是11792(记住这个数字)。然后我们打开top观察一下cpu的使用情况。我们看到11792这个进程把cpu拉的很高。
橘子学K8S02之容器中所谓的限制,# K8S,kubernetes,容器,云原生
而此时,我们可以通过查看 levi 目录下的文件,看到 levi 控制组里的 CPU quota 还没有任何限制(即:-1),CPU period 则是默认的 100 ms(100000 us):

[root@iZ2ze1q2h6sy9dblhemmhmZ cpu]# cat /sys/fs/cgroup/cpu/levi/cpu.cfs_quota_us
-1
[root@iZ2ze1q2h6sy9dblhemmhmZ cpu]# cat /sys/fs/cgroup/cpu/levi/cpu.cfs_period_us
100000
~~~shell
因为此时我们啥也没干,我们这个levi控制组就是个摆设,谁也没控制,于是我们现在就用这个控制组来控制一下我们这个11792进程。让他不要这么肆无忌惮的使用我的资源。
1、向 levi组里的 cfs_quota 文件写入 20 ms(20000 us):
~~~shell
$ echo 20000 > /sys/fs/cgroup/cpu/levi/cpu.cfs_quota_us

它意味着在每 100 ms 的时间里,被该控制组限制的进程只能使用 20 ms 的 CPU 时间,也就是说这个进程只能使用到 20% 的 CPU 带宽。

但是此时我们只是修改了这个控制组,你这个控制组要控制谁呢,也就说你的控制组要和你要控制的进程关联起来。才能做到指定控制。
2、我们把被限制的进程的 PID 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了:

echo 11792 > /sys/fs/cgroup/cpu/levi/tasks

此时我们就完成了控制,按照我们的预期,我们希望刚才那个拉满cpu的进程,现在在限制下只能使用百分之20的cpu资源,那么我们用top来看一下。
橘子学K8S02之容器中所谓的限制,# K8S,kubernetes,容器,云原生
我们看到监控下的占用和我们的预期一样的。这就表示我们的限制是成功的。

2、如何理解docker的限制

除 CPU 子系统外,Cgroups 的每一个子系统都有其独有的资源限制能力,比如:
blkio,为​​​块​​​设​​​备​​​设​​​定​​​I/O 限​​​制,一般用于磁盘等设备;
cpuset,为进程分配单独的 CPU 核和对应的内存节点;
memory,为进程设定内存使用的限制。
Linux Cgroups 的设计还是比较易用的,它就是一个子系统目录加上一组资源限制文件的组合。而对于 Docker 等 Linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的 PID 填写到对应控制组的 tasks 文件中就可以了。
而至于在这些控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定了,比如这样一条命令:

$ docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash

在启动这个容器后,我们可以通过查看 Cgroups 文件系统下,CPU 子系统中,“docker”这个控制组里的资源限制文件的内容来确认:

$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_period_us 
100000
$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_quota_us 
20000

这就意味着这个 Docker 容器,只能使用到 20% 的 CPU 带宽。
我们通过一个对cpu占用的方式模拟了docker限制的规则,其实你就可以自己简单实现docker的这个小功能了。

三、总结

所以,一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。
这也是容器技术中一个非常重要的概念,即:容器是一个“单进程”模型。由于一个容器的本质就是一个进程,用户的应用进程实际上就是容器里 PID=1 的进程,也是其他后续创建的所有进程的父进程。这就意味着,在一个容器中,你没办法同时运行两个不同的应用,因为docker的理念就是容器就是应用,通过监控应用来表达容器的状态,所以一对一的这种最能达到效果,如果你运行两个进程,但是只有一个能表达PID=1,那么就存在另一个进程挂了,但是docker不知道,因为他是和PID=1的进程挂钩的。
除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这样当子进程挂了会发给父进程(PID=1)一个信号,这样对于父进程也是能感知的,父进程能感知,dockler也就能感知了,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程。
这是因为容器本身的设计,就是希望容器和应用能够同生命周期,这个概念对后续的容器编排非常重要。否则,一旦出现类似于“容器是正常运行的,但是里面的应用早已经挂了”的情况,编排系统处理起来就非常麻烦了。
另外,跟 Namespace 的情况类似,Cgroups 对资源的限制能力也有很多不完善的地方,被提及最多的自然是 /proc 文件系统的问题。
众所周知,Linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。但是,你如果在容器里执行 top 指令,就会发现,它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据。造成这个问题的原因就是,/proc 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,即:/proc 文件系统不了解 Cgroups 限制的存在。在生产环境中,这个问题必须进行修正,否则应用程序在容器里读取到的 CPU 核数、可用内存等信息都是宿主机上的数据,这会给应用的运行带来非常大的困惑和风险。这也是在企业中,容器化应用碰到的一个常见问题,也是容器相较于虚拟机另一个不尽如人意的地方。后面我会补充这个解决方案的内容。文章来源地址https://www.toymoban.com/news/detail-754726.html

到了这里,关于橘子学K8S02之容器中所谓的限制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 容器化进阶Kubernetes(K8S)详解

    1.1.1 Kubernetes是什么及作用 Kubernetes(K8S)是Google在2014年发布的一个开源项目,用于自动化容器化应用程序的部署、扩展和管理。 Kubernetes通常结合docker容器工作,并且整合多个运行着docker容器的主机集群。 官网地址 Kubernetes 中文社区 Kubernetes(k8s)中文文档 目录_Kubernetes中文社

    2024年02月05日
    浏览(74)
  • 容器技术,1. Docker,2. Kubernetes(K8s):

    目录 容器技术 1. Docker: 2. Kubernetes(K8s): Docker和Kubernetes 容器的主要应用场景有哪些? 有效的将单个操作系统的资源划分到孤立的组中,以便更好的在孤立的组之间平衡有冲突的资源使用需求,这种技术就是容器技术。 容器技术指通过在物理主机操作系统上创建一个一个

    2024年02月11日
    浏览(66)
  • 打破限制,随时随地练习K8S!在线Kubernetes平台开启你的技术之旅!

    是不是有很多小伙伴想学习k8s,但是又没有机器去练习。使用自己的笔记本电脑或者主机只能搭建单机版本的k8s来练习。 现在福利来了,给大家介绍一个在线多节点k8s练习平台:Play with Kubernetes。 Play with Kubernetes 一个提供了在浏览器中使用免费 CentOS Linux 虚拟机的体验平台,

    2024年04月14日
    浏览(44)
  • Kubernetes(k8s)容器编排Pod介绍和使用

    Pod是kubernetes中你可以创建和部署的最小也是最简的单位,一个Pod代表着集群中运行的一个进程。 Pod有两个必须知道的特点 通过yaml文件或者json描述Pod和其内容器的运行环境和期望状态,例如一个最简单的运行nginx应用的pod,定义如下 3.1.1 参数描述 下面简要分析一下上面的

    2024年02月08日
    浏览(78)
  • Kubernetes(K8s):容器化应用的航空母舰

    Kubernetes(K8s)是一个开源的容器编排系统,它的出现就像是为容器化应用提供了一艘强大的航空母舰。在这艘母舰上,你的应用容器就像是一架架战斗机,Kubernetes负责指挥它们起飞、飞行、降落,确保它们能在正确的时间、正确的地点执行任务。 Pod: Kubernetes的基本飞行编队

    2024年04月08日
    浏览(64)
  • kubernetes(k8s)为容器和 Pod 分配内存资源

    展示如何将内存请求(request)和内存限制(limit)分配给一个容器。 我们保障容器拥有它请求数量的内存,但不允许使用超过限制数量的内存。 创建新的命名空间 编辑yaml文件 配置文件的 args 部分提供了容器启动时的参数。 “–vm-bytes”, “150M” 参数告知容器尝试分配 15

    2024年02月15日
    浏览(54)
  • Kubernetes (K8s) 解读:微服务与容器编排的未来

    🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🐅🐾猫头虎建议程序员必备技术栈一览表📖: 🛠️ 全栈技术 Full Stack : 📚 MERN/MEAN/MEVN Stack | 🌐 Jamstack | 🌍 GraphQL | 🔁 RESTful API | ⚡ WebSockets | 🔄 CI/CD | 🌐 Git Version Control | 🔧 DevOps 🌐 前端技术 Frontend : 🖋️ HTML CSS |

    2024年02月09日
    浏览(41)
  • K8S 1.27 动态调整容器CPU和内存资源限制,无需重启应用程序

    如果您在部署Pod时指定了 CPU 和内存资源,更改资源大小需要重新启动 Pod。到目前为止,重启对于正在运行工的作负载是一种破坏性操作。 Kubernetes 1.27 中的 alpha 功能发布。其中一项能够自动调整 Pod 的 CPU 和内存限制的大小,只需修补正在运行的 Pod 定义即可更改它们,而无

    2024年02月07日
    浏览(45)
  • 【Kubernetes】k8s中容器之间、pod之间如何进行网络通信?

    首先来回顾一下Pod: Pod 是用于构建应用程序的最小可部署对象。单个 Pod 代表集群中正在运行的工作负载,并 封装一个或多个 Docker 容器、任何所需的存储以及唯一的 IP 地址 。 集群中每一个 Pod 都会获得自己的、 独一无二的 IP 地址。一个Pod里的一组容器共享相同的IP地址。

    2024年04月28日
    浏览(69)
  • 橘子学K8S04之重新认识Docker容器

    我们之前分别从 Linux Namespace 的隔离能力、Linux Cgroups 的限制能力,以及基于 rootfs 的文件系统三个角度来理解了一下关于容器的核心实现原理。 这里一定注意说的是Linux环境,因为Linux Docker (namespaces + cgroups + rootfs) != Docker on Mac (based on virtualization) != Windows Docker (based on virtual

    2024年01月19日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包