深入剖析Kubernetes学习笔记-06 | 白话容器基础(二):隔离与限制

简介: 深入剖析Kubernetes学习笔记-06 | 白话容器基础(二):隔离与限制

一、为什么选择容器而不是虚拟机


使用虚拟化技术作为应用沙盒,就必须要由 Hypervisor 来负责创建虚拟机,这个虚拟机是真实存在的,并且它里面必须运行一个完整的 Guest OS 才能执行用户的应用进程。这就不可避免地带来了额外的资源消耗和占用。

1.1 虚拟机所耗费的资源


一个运行着 CentOS 的 KVM 虚拟机启动后,在不做优化的情况下,虚拟机自己就需要占用 100~200 MB 内存。


用户应用运行在虚拟机里面,它对宿主机操作系统的调用就不可避免地要经过虚拟化软件的拦截和处理,这本身又是一层性能损耗,尤其对计算资源、网络和磁盘 I/O 的损耗非常大

1.2 容器所耗费的资源


容器化后的用户应用,却依然还是一个宿主机上的普通进程,这就意味着这些因为虚拟化而带来的性能损耗都是不存在的;


使用 Namespace 为隔离手段的容器并不需要单独的 Guest OS,这就使得容器额外的资源占用几乎可以忽略不计。


“敏捷”和“高性能”是容器相较于虚拟机最大的优势,也是它能够在 PaaS 这种更细粒度的资源管理平台上大行其道的重要原因。

二、更精确的隔离方式


Linux Namespace 的隔离机制相比于虚拟化技术也有很多不足之处,其中最主要的问题就是:隔离得不彻底。

2.1 容器共享宿主机的操作系统内核。


尽管你可以在容器里通过 Mount Namespace 单独挂载其他不同版本的操作系统文件,比如 CentOS 或者 Ubuntu,但这并不能改变共享宿主机内核这意味着,如果你要在 Windows 宿主机上运行 Linux 容器,或者在低版本的 Linux 宿主机上运行高版本的 Linux 容器,都是行不通的。


而相比之下,拥有硬件虚拟化技术和独立 Guest OS 的虚拟机就要方便得多了。最极端的例子是,Microsoft 的云计算平台 Azure,实际上就是运行在 Windows 服务器集群上的,但这并不妨碍你在它上面创建各种 Linux 虚拟机出来。


带来的问题:


容器给应用暴露出来的攻击面是相当大的,应用“越狱”的难度自然也比虚拟机低得多。


尽管在实践中我们确实可以使用 Seccomp 等技术,对容器内部发起的所有系统调用进行过滤和甄别来进行安全加固,但这种方法因为多了一层对系统调用的过滤,一定会拖累容器的性能。何况,默认情况下,谁也不知道到底该开启哪些系统调用,禁止哪些系统调用。在生产环境中,没有人敢把运行在物理机上的 Linux 容器直接暴露到公网上

2.2 时间不能被Namespace 化


在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,最典型的例子就是:时间。


如果你的容器中的程序使用 settimeofday(2) 系统调用修改了时间,整个宿主机的时间都会被随之修改。


这显然不符合用户的预期。相比于在虚拟机里面可以随便折腾的自由度,在容器里部署应用的时候,什么能做,什么不能做,就是用户必须考虑的一个问题。

三、容器的“限制”


3.1 Linux Cgroups


Linux Cgroups 就是 Linux 内核中用来为进程设置资源限制的一个重要功能。

Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。


Cgroups 还能够对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。


在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。


Ubuntu 18.04  mount 指令把它们展示出来

root@ubuntu:/home/wx# mount -t cgroup 
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
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/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)

它的输出结果,是一系列文件系统目录。如果你在自己的机器上没有看到这些目录,那你就需要自己去挂载 Cgroupscpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是这台机器当前可以被 Cgroups 进行限制的资源种类

root@ubuntu:/home/wx# ls /sys/fs/cgroup/cpu
cgroup.clone_children  cpuacct.stat       cpuacct.usage_percpu       cpuacct.usage_sys   cpu.cfs_quota_us  docker             system.slice
cgroup.procs           cpuacct.usage      cpuacct.usage_percpu_sys   cpuacct.usage_user  cpu.shares        notify_on_release  tasks
cgroup.sane_behavior   cpuacct.usage_all  cpuacct.usage_percpu_user  cpu.cfs_period_us   cpu.stat          release_agent      user.slice

fs_period cfs_quota 这两个参数需要组合使用,可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 CPU 时间。

3.2 如何使用


需要在对应的子系统下面创建一个目录

root@ubuntu:/home/wx# cd /sys/fs/cgroup/cpu
root@ubuntu:/sys/fs/cgroup/cpu# pwd
/sys/fs/cgroup/cpu
root@ubuntu:/sys/fs/cgroup/cpu# ls container/
cgroup.clone_children  cpuacct.stat   cpuacct.usage_all     cpuacct.usage_percpu_sys   cpuacct.usage_sys   cpu.cfs_period_us  cpu.shares  cpu.uclamp.max  notify_on_release
cgroup.procs           cpuacct.usage  cpuacct.usage_percpu  cpuacct.usage_percpu_user  cpuacct.usage_user  cpu.cfs_quota_us   cpu.stat    cpu.uclamp.min  tasks
root@ubuntu:/sys/fs/cgroup/cpu# 

这个目录就称为一个控制组”。。你会发现,操作系统会在你新创建的 container 目录下,自动生成该子系统对应的资源限制文件。


现在,我们在后台执行这样一条脚本:

root@ubuntu:/sys/fs/cgroup/cpu# while : ; do : ; done &
[1] 15035

top 指令来确认一下 CPU 有没有被打满

top - 07:08:29 up  7:23,  1 user,  load average: 0.97, 0.35, 0.12
Tasks: 316 total,   2 running, 247 sleeping,   0 stopped,   0 zombie
%Cpu(s): 97.0 us,  3.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

查看 container 目录下的文件,看到 container 控制组里的 CPU quota 还没有任何限制(即:-1),CPU period 则是默认的 100 ms(100000 us):长度为 100 ms的时间内,只能被分配到总量为 cfs_quota 的 CPU 时间是没有限制。

root@ubuntu:/sys/fs/cgroup/cpu#  cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us 
-1
root@ubuntu:/sys/fs/cgroup/cpu# cat /sys/fs/cgroup/cpu/container/cpu.cfs_period_us 
100000

通过修改这些文件的内容来设置限制


container 组里的 cfs_quota 文件写入 20 ms(20000 us)

echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us

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


除 CPU 子系统外,Cgroups 的每一项子系统都有其独有的资源限制能力,比如:

  1. blkio,为块设备设定I/O 限制,一般用于磁盘等设备;
  2. cpuset,为进程分配单独的 CPU 核和对应的内存节点;
  3. memory,为进程设定内存使用的限制。

被限制的进程的 PID 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了:

root@ubuntu:/sys/fs/cgroup/cpu# 
root@ubuntu:/sys/fs/cgroup/cpu# echo 15035 > /sys/fs/cgroup/cpu/container/tasks 

被限制的进程的 PID 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了:

top - 07:14:06 up  7:28,  1 user,  load average: 0.69, 0.80, 0.42
Tasks: 315 total,   2 running, 247 sleeping,   0 stopped,   0 zombie
%Cpu(s): 20.4 us,  5.4 sy,  0.0 

计算机的 CPU 使用率立刻降到了 20%(%Cpu0 : 20.3 us)


除 CPU 子系统外,Cgroups 的每一项子系统都有其独有的资源限制能力,比如:

  1. blkio,为块设备设定I/O 限制,一般用于磁盘等设备;
  2. cpuset,为进程分配单独的 CPU 核和对应的内存节点;
  3. 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 带宽。


如何删除cgroup的配置?

04aedd78a6bc4cbfbaf84b33ec3f8a5d.png

四、总结


一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。容器是一个“单进程”模型。

问题: /proc 文件系统目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等


它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据?如何解决?


lxcfs

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
8天前
|
人工智能 弹性计算 运维
ACK Edge与IDC:高效容器网络通信新突破
本文介绍如何基于ACK Edge以及高效的容器网络插件管理IDC进行容器化。
|
11天前
|
监控 NoSQL 时序数据库
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
142 77
|
9天前
|
人工智能 运维 监控
阿里云ACK容器服务生产级可观测体系建设实践
本文整理自2024云栖大会冯诗淳(花名:行疾)的演讲,介绍了阿里云容器服务团队在生产级可观测体系建设方面的实践。冯诗淳详细阐述了容器化架构带来的挑战及解决方案,强调了可观测性对于构建稳健运维体系的重要性。文中提到,阿里云作为亚洲唯一蝉联全球领导者的容器管理平台,其可观测能力在多项关键评测中表现优异,支持AI、容器网络、存储等多个场景的高级容器可观测能力。此外,还介绍了阿里云容器服务在多云管理、成本优化等方面的最新进展,以及即将推出的ACK AI助手2.0,旨在通过智能引擎和专家诊断经验,简化异常数据查找,缩短故障响应时间。
阿里云ACK容器服务生产级可观测体系建设实践
|
10天前
|
运维 Kubernetes 调度
阿里云容器服务 ACK One 分布式云容器企业落地实践
阿里云容器服务ACK提供强大的产品能力,支持弹性、调度、可观测、成本治理和安全合规。针对拥有IDC或三方资源的企业,ACK One分布式云容器平台能够有效解决资源管理、多云多集群管理及边缘计算等挑战,实现云上云下统一管理,提升业务效率与稳定性。
|
21天前
|
运维 Kubernetes Docker
深入理解容器化技术:Docker与Kubernetes的协同工作
深入理解容器化技术:Docker与Kubernetes的协同工作
43 1
|
21天前
|
Kubernetes Cloud Native 持续交付
容器化、Kubernetes与微服务架构的融合
容器化、Kubernetes与微服务架构的融合
40 1
|
23天前
|
Kubernetes Cloud Native API
深入理解Kubernetes——容器编排的王者之道
深入理解Kubernetes——容器编排的王者之道
36 1
|
25天前
|
Kubernetes Cloud Native 云计算
云原生入门:Kubernetes 和容器化基础
在这篇文章中,我们将一起揭开云原生技术的神秘面纱。通过简单易懂的语言,我们将探索如何利用Kubernetes和容器化技术简化应用的部署和管理。无论你是初学者还是有一定经验的开发者,本文都将为你提供一条清晰的道路,帮助你理解和运用这些强大的工具。让我们从基础开始,逐步深入了解,最终能够自信地使用这些技术来优化我们的工作流程。
|
19天前
|
监控 Docker 容器
在Docker容器中运行打包好的应用程序
在Docker容器中运行打包好的应用程序
|
3天前
|
关系型数据库 应用服务中间件 PHP
实战~如何组织一个多容器项目docker-compose
本文介绍了如何使用Docker搭建Nginx、PHP和MySQL的环境。首先启动Nginx容器并查看IP地址,接着启动Alpine容器并安装curl测试连通性。通过`--link`方式或`docker-compose`配置文件实现服务间的通信。最后展示了Nginx配置文件和PHP代码示例,验证了各服务的正常运行。
18 3
实战~如何组织一个多容器项目docker-compose
下一篇
DataWorks