【K8s】白话容器基础(二):隔离与限制

news2024/12/28 18:22:08

白话容器基础(二):隔离与限制

容器与虚拟机

在上一篇文章中,我详细介绍了 Linux 容器中用来实现“隔离”的技术手段:Namespace。而通过这些讲解,你应该能够明白,Namespace 技术实际上修改了应用进程看待整个计算机“视图”,即它的“视线”被操作系统做了限制,只能“看到”某些指定的内容。但对于宿主机来说,这些被“隔离”了的进程跟其他进程并没有太大区别。

说到这一点,相信你也能够知道我在上一篇文章最后给你留下的第一个思考题的答案了:在之前虚拟机与容器技术的对比图里,不应该把 Docker Engine 或者任何容器管理工具放在跟 Hypervisor 相同的位置,因为它们并不像 Hypervisor 那样对应用进程的隔离环境负责,也不会创建任何实体的“容器”,真正对隔离环境负责的是宿主机操作系统本身:
在这里插入图片描述

所以,在这个对比图里,我们应该把 Docker 画在跟应用同级别并且靠边的位置。这意味着,用户运行在容器里的应用进程,跟宿主机上的其他进程一样,都由宿主机操作系统统一管理,只不过这些被隔离的进程拥有额外设置过的 Namespace 参数。而 Docker 项目在这里扮演的角色,更多的是旁路式的辅助和管理工作。

我在后续分享 CRI 和容器运行时的时候还会专门介绍,其实像 Docker 这样的角色甚至可以去掉。

这样的架构也解释了为什么 Docker 项目比虚拟机更受欢迎的原因。

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

根据实验,一个运行着 CentOS 的 KVM 虚拟机启动后,在不做优化的情况下,虚拟机自己就需要占用 100~200 MB的内存。此外,用户应用运行在虚拟机里面,它对宿主机长治县人的调用就不可避免地要经过虚拟化软件的拦截和处理,这本身又是一层性能损耗,尤其对计算资源、网络和磁盘I/O的损耗非常大。

而相比之下,容器化后的用户应用,却依然还是一个宿主机上的普通进程,这就意味着这些因为虚拟化而带来的性能损耗都是不存在的;而另一方面,使用 Namespace 作为隔离手段的容器并不需要单独的Guest OS,这就使得容器额外的资源占用几乎可以忽略不计。

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

容器隔离得不彻底

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

首先,既然容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。

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

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

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

这就意味着,如果你的容器中的程序使用 settimeofday(2) 系统调用修改了时间,整个宿主机的时间都会被随之修改,这显然不符合用户的预期。相比于在虚拟机里面可以随便折腾的自由度,在容器里部署应用的时候,“什么能做,什么不能做”,就是用户必须考虑的一个问题。

此外,由于上述问题,尤其是共享宿主机内核的事实,容器给应用暴露出来的攻击面是相当大的,应用“越狱”的难度自然也比虚拟机低得多。

更为棘手的是,尽管在实践中我们确实可以使用 Seccomp 等技术,对容器内部发起的所有系统调用进行过滤和甄别来进行安全加固,但这种方法因为多了一层对系统调用的过滤,必然会拖累容器的性能。何况,默认情况下,谁也不知道到底该开启哪些系统调用,禁止哪些系统调用。

所以,在生产环境中,没有人敢把运行在物理机上的 Linux 容器直接暴露到公网上。当然,我后续会讲到的基于虚拟化或者独立内核技术的容器实现,则可以比较好地在隔离与性能之间做出平衡。

容器的限制

在介绍完容器的“隔离”技术之后,我们再来研究一下容器的“限制”问题。

也许你会好奇,我们不是已经通过 Linux Namespace 创建了一个“容器”吗,为什么还需要对容器做“限制”呢?

我还是以 PID Namespace 为例,来给你解释这个问题。

虽然容器内的第1号进程在『障眼法』的干扰下只能看到容器里的情况,但是在宿主机上,它作为第100号进程与其他所有进程之间依然是平等的竞争关系。这就意味着,虽然第100号进程表面上被隔离了起来,但是它所能够使用到的资源(比如CPU、内存),却是可以随时被宿主机上的其他进程(或其他容器)占用的。当然,这个100号进程自己也可能把所有的资源吃光。这些情况,显然不是一个『沙盒』应该表现出来的合理行为。

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

有意思的是,Google 的工程师在 2006 年发起这项特性的时候,曾将它命名为“进程容器”(process container)。实际上,在 Google 内部,“容器”这个术语长期以来都被用于形容被 Cgroups 限制过的进程组。后来 Google 的工程师们说,他们的 KVM 虚拟机也运行在 Borg 所管理的“容器”里,其实也是运行在 Cgroups“容器”当中。这和我们今天说的 Docker 容器差别很大。

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

此外,Cgroups 还能够对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。在今天的分享中,我只和你重点讨论它与容器关系最紧密的『限制』能力,并通过一组实践带你认识一下 Cgroups。

在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroups 路径下。在Ubuntu16.04 机器里,我可以用 mount 指令把它们展示出来,这条命令是:

$ mount -t cgroup 
cpuset on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cpu on /sys/fs/cgroup/cpu type cgroup (rw,nosuid,nodev,noexec,relatime,cpu)
cpuacct on /sys/fs/cgroup/cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct)
blkio on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
memory on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)

它的输出结果,是一系列文件系统目录。如果你在自己的机器上没有看到这些目录,那你就需要自己去挂载 Cgroups,具体做法可以自行 Google。

可以看到,在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是我这台机器当前可以被 Cgroups 进行限制的资源种类。而在子系统对应的资源种类下,你就可以看到该类资源具体可以被限制的方法。比如,对 CPU 子系统来说,我们就可以看到如下几个配置文件,这个指令是:

$ ls /sys/fs/cgroup/cpu
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us  cpu.shares notify_on_release
cgroup.procs      cpu.cfs_quota_us  cpu.rt_runtime_us cpu.stat  tasks

如果熟悉 Linux CPU 管理的话,你就会在它的输出里注意到 cfs_period 和 cfs_quota 这样的关键词。这两个参数需要组合使用,可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_qupta 的 CPU 时间。

而这样的配置文件又如何使用呢?

你需要在对应的子系统下面创建一个目录,比如,我们现在进入 /sys/fs/cgroup/cpu 目录下:

root@ubuntu:/sys/fs/cgroup/cpu$ mkdir container
root@ubuntu:/sys/fs/cgroup/cpu$ ls container/
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us  cpu.shares notify_on_release
cgroup.procs      cpu.cfs_quota_us  cpu.rt_runtime_us cpu.stat  tasks

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

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

$ while : ; do : ; done &
[1] 226

显然,它执行了一个死循环,可以把计算机的 CPU 吃到 100%,根据它的输出,我们可以看到这个脚本在后台运行的进程号(PID)是 226。

这样,我们可以用 top 指令来确认一下 CPU 有没有被打满:

$ top
%Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

在输出里可以看到,CPU 的使用率已经 100% 了(%Cpu0 :100.0 us)。

而此时,我们可以通过查看 container 目录下的文件,看到 container 控制组里的 CPU quota 还没有任何限制(即:-1),CPU period 则是默认的 100 ms(100000 us):

$ cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us 
-1
$ 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 带宽。

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

$ echo 226 > /sys/fs/cgroup/cpu/container/tasks 

我们可以用 top 指令查看一下:

$ top
%Cpu0 : 20.3 us, 0.0 sy, 0.0 ni, 79.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

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

除 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 带宽。

总结
在这篇文章中,我首先介绍了容器使用 Linux Namespace 作为隔离手段的优势和劣势,对比了 Linux 容器跟虚拟机技术的不同,进一步明确了『容器只是一种特殊的进程』这个结论。

除了创建 Namespace 之外,在后续关于容器网络的分享中,我还会介绍一些其他 Namespace 的操作,比如看不见摸不着的 Linux Namespace 在计算机中到底如何表示、一个进程如何『加入』到其他进程的 Namespace 当中,等等。

紧接着,我详细介绍了容器在做好了隔离工作之后,又如何通过 Linux Cgroups 实现资源的限制,并通过一系列简单的实验,模拟了 Docker 项目创建容器限制的过程。

通过以上讲述,你现在应该能够理解,一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。

这也是容器技术中一个非常重要的概念,即:容器是一个『单进程』模型。

由于一个容器的本质就是一个进程,用户的应用进程实际上就是容器里 PID=1 的进程,也是其他后续创建的所有进程的父进程。这就意味着,在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程。

但是,在后面分享容器设计模式时,我还会推荐其他更好的解决办法。这是因为容器本身的设计,就是希望容器和应用能够同生命周期,这个概念对后续的容器编排非常重要。否则,一旦出现类似于『容器是正常运行的,但是里面的应用早已经挂了』的情况,编排系统处理起来就非常麻烦了。

另外,跟 Namespace 的情况类似,Cgroups 对资源的限制能力也有很多不完善的地方,被提及最多的自然是 /proc 文件系统的问题。

众所周知,Linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统消息的主要数据来源。

但是,你如果在容器里执行 top 指令,就会发现,它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据。

造成这个问题的原因就是,/proc 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,即:/proc 文件系统不了解 Cgroups 限制的存在。

在生产环境中,这个问题必须进行修正,否则应用程序在容器里读取到的 CPU 核数、可用内存等信息都是宿主机上的数据,这会给应用的运行带来非常大的困惑和风险。这也是在企业中,容器化应用碰到的一个常见问题,也是容器相较于虚拟机另一个不尽如人意的地方。

思考题
1、你是否知道如何修复容器中的 top 指令以及/proc 文件系统中的信息呢?(提示:lxcfs)
2、在从虚拟机向容器迁移应用的过程中,你还遇到哪些容器与虚拟机的不一致问题?

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

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

相关文章

如何本地部署Jellyfin影音服务器并实现在公网访问

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及,各种各样的使用需求也被开发出来&…

如何做好企业的设备维护和保养?报修工单管理系统软件有哪些?

随着信息化技术的飞速发展,企业运营的各个方面都在逐步实现信息化。设备维护作为企业运营中的重要环节,其可靠性对于企业的正常运营至关重要。报修工单管理系统软件作为解决这一问题的有效方案,已经受到业界的广泛关注。本文将从测评专家的角…

window安装es服务及删除

elasticsearch-service.bat install 删除es服务,先停止es服务运行,管理员cmd模式,sc delete "elasticsearch-service-x64"

基于安卓Android的城市公交查询app

项目介绍 本课题城市公交线路查询,采用安卓平台,所完成的可扩展性、可靠性以及可重用性的城市公交线路查询系统,以满足现实生活的需要。数据库选用MySQL。 前端为移动端,采用安卓框架uniapp,开发软件为Android Studio…

【方法】Excel表格如何禁止查看公式?

在日常工作中,很多人会选择用Excel来做数据表格,有时候还要通过公式来做数据。那如果计算数据所用的公式不想让别人看到,可以怎么做呢?今天小编就来分享一下,如何设置Excel表格禁止查看公式。 以下图表格为例&#xf…

String 字符串不可变带来的好处是什么?

目录 1. 线程安全(数据安全) 2. 节约内存 3. 提高集合的存取效率 1. 线程安全(数据安全) 众所周知,String 字符串是默认被 final 修饰的,是不可变的,那么首先能想到的一个优点就是线程安全,String 是存放在堆中的,是…

NSSCTF 2nd Web 题目复现

php签到 考点&#xff1a; 1.上传表单html的编写 2./. 绕过黑名单&#xff08;在Linux系统下1.php.是一个合法的文件名&#xff0c;系统不会自动把最后的点去掉并把文件当成php文件执行&#xff0c;所以点绕过只在Windows下有用&#xff09; 源代码&#xff1a; <?phpfun…

ICS TRIPLEX T9432 电源模块

电源模块是电子装备中的重要组成部分&#xff0c;用于供给电能以供给装备中的各种电子元件和电路。电源模块具备多种特征&#xff0c;以保证供给稳定、否靠的电源&#xff0c;顺应不同运用的需要。以下是电源模块的一些主要特征&#xff1a; 电压和电流输入&#xff1a; 电源模…

纬创出售印度子公司给塔塔集团,结束iPhone代工业务 | 百能云芯

纬创&#xff08;Wistron&#xff09;董事会于10月27日通过决议&#xff0c;同意以1.25亿美元的价格出售其印度子公司Wistron InfoComm Manufacturing (India) Private Limited&#xff08;WMMI&#xff09;的100%股权给塔塔集团&#xff0c;交割将尽快完成。此举将意味着纬创退…

高效学习之anki新手入门指南(ios端,包括ipad、ihpone设备)————创建、使用、备份、相关资料

文章目录 0 背景0.1 闭环学习0.2 什么是anki 1 开始使用1.1 导入1.2 创建空白组1.3 创建卡片1.3.1 利用anki创建卡片的两种方法1.3.2 复习材料分类 2 操作卡牌&#xff08;位于卡牌界面中“游览”&#xff09;2.1 清空卡牌状态&#xff08;清空之前的“重来”、“困难”、“简单…

电源模块测试用例之电压上升时间测试方案

电压上升时间是电源模块一个非常重要的参数&#xff0c;它直接影响着电路的稳定性。电源模块电压上升过快或过慢都有可能会使系统发生故障&#xff0c;造成设备器件受损。因此&#xff0c;上升时间测试是电源模块测试非常重要的环节。纳米软件电源模块测试系统助力自动化测试&a…

GNN 简介

A Gentle Introduction to Graph Neural Networks A Gentle Introduction to Graph Neural Networks GNN简介 图神经网络&#xff08;GNN&#xff09;是一种基于图结构数据的深度学习模型&#xff0c;用于处理和分析图数据。图数据由节点&#xff08;顶点&#xff09;和边&a…

在Win11上部署ChatGLM3详细步骤

023年10月27日&#xff0c;智谱AI于2023中国计算机大会&#xff08;CNCC&#xff09;上&#xff0c;推出了全自研的第三代基座大模型ChatGLM3及相关系列产品&#xff0c;这也是智谱AI继推出千亿基座的对话模型ChatGLM和ChatGLM2之后的又一次重大突破。此次推出的ChatGLM3采用了…

【计算机网络】浏览器的通信能力

1. 用户代理 浏览器可以代替用户完成http请求&#xff0c;代替用户解析响应结果&#xff0c;所以我们称之为用户代理 user agent。 浏览器两大核心能力&#xff1a; 自动发送请求的能力自动解析响应的能力 1.1 自动发送请求的能力 用户在地址栏输入了一个url地址&#xff0…

Mac 上安装 Emscripten

背景&#xff1a;Web 端需要使用已有的 C 库&#xff0c;需要将 C 项目编译成 WebAssembly(.wasm) 供 js 调用。 Emscripten 可以将 C 编译成 .wasm 一、下载源码 # 下载 emsdk 源码 git clone https://github.com/emscripten-core/emsdk.git# 下载完成后进入到 emsdk 项目根…

voco品牌入华三周年,以“妙趣重生”之姿共绘酒店永续发展新风向

入华三年高速发展&#xff0c;乘酒店存量市场之潮&#xff0c;用艺术诠释绿色环保&#xff0c;趣享可持续旅程 2023年10月30日&#xff0c;西安 – 近日&#xff0c;洲际酒店集团旗下高端酒店品牌voco迎来进入大中华市场三周年&#xff0c;并于西安经开voco酒店举办周年庆典&a…

回收废品抢派单小程序开源版开发

回收废品派单抢派单小程序开源版开发 在这个废品回收抢单派单小程序开源版开发中&#xff0c;我们将构建一个专业且富有趣味性的平台&#xff0c;以深度的模式来重塑废品回收体验。 我们将提供一个会员注册功能&#xff0c;用户可以通过小程序授权注册和手机号注册两种方式快…

chatgpt账号,官方账号获取

有需要帮助可以联系我&#xff0c;我可以帮助获取&#xff08;有偿&#xff09;。

vue页面el-tab控件标签栏加入按钮功能

vue页面el-tab控件标签栏加入按钮功能 显示效果为&#xff1a; <el-tabs v-model"activeName" type"border-card" style"margin-right:5px"><el-tab-pane label"模型管理" name"first"><span slot"l…

安装Pytorch的详细步骤

若为安装Anaconda的友友&#xff0c;可以移步到这篇文章&#xff0c;先安装anaconda&#xff1a; https://blog.csdn.net/mariodf/article/details/134119941 一、anaconda创建虚拟环境 1、首先输入&#xff1a; conda env list 可以查看当前的虚拟环境&#xff1a; 2、创…