前言

Linux 容器的本质,是一个被隔离和限制的进程。

与虚拟机不同,容器无需虚拟化一个完整的操作系统,所以它比虚拟机更轻量级,效率也更高。

Linux 容器通过 namespaces 技术来隔离容器的视图,使得容器进程只能看到当前 namespace 内的 进程PID、网络、挂载、UTS、IPC 和用户等资源;再通过 cgroups 技术限制容器进程的例如 cpu、内存、网络带宽、磁盘 IO 等资源的使用,避免容器间资源占用的相互影响,甚至出现一个容器就耗尽所有资源的极端情况;最后,再通过 pivot_root 系统调用,改变容器进程的根文件系统,使得容器进程只能访问自身的文件系统,避免影响到宿主机。

隔离

Linux 容器的隔离,依赖的是 namespaces 技术。

unshare 是 Linux 中的一个命令,用于在新的命名空间中运行程序。为了方便,本文使用 unshare 命令来实践,而不是直接调用clone 等系统函数。

以隔离 PID 为例,直接带上--pid 参数即可:

> unshare --pid --mount --fork bash
> psPID TTY          TIME CMD501089 pts/2    00:00:00 bash501100 pts/2    00:00:00 unshare501101 pts/2    00:00:00 bash501108 pts/2    00:00:00 ps

新的 bash 终端运行在新的 namespace 中,且隔离了 mount 和 pid。但此时ps 命令返回的进程依然和宿主机中是一样的,pid 隔离看似没有生效,因为 ps 命令是依靠读取/proc** 文件系统来工作的**。

重新挂载 /proc,再次执行 ps 会发现,进程看到的是一个全新的 PID 视图,当前 bash 是1号进程,而 ps 是10号进程。

> mount -t proc proc /proc
> psPID TTY          TIME CMD1 pts/2    00:00:00 bash10 pts/2    00:00:00 ps

--mount-proc 参数支持在新的命名空间中挂载独立的 /proc 文件系统,上面的命令可以简化为:

> unshare --mount --mount-proc --pid --fork bash
> psPID TTY          TIME CMD1 pts/3    00:00:00 bash8 pts/3    00:00:00 ps

在新的命名空间中,我们开启一个进程执行 sleep,可以看到,执行 sleep 的进程 ID 是8。

# 新的命名空间内执行
> sleep 99 &
[1] 8> ps -ef | grep sleep
root           8       1  0 15:34 pts/1    00:00:00 sleep 99
root          13       1  0 15:35 pts/1    00:00:00 grep --color=auto sleep

在宿主机中新开一个终端,发现这个 sleep 进程ID 是 698787。

# 在宿主机中执行
> ps -ef | grep sleep
root      698787  698780  0 15:34 pts/1    00:00:00 sleep 99
root      698794  698699  0 15:35 pts/2    00:00:00 grep --color=auto sleep

这俩就是同一个进程,sleep 进程的真实进程ID是 698787,只不过在新的命名空间内,内核的 namespace 技术给进程施加了“障眼法”,让命名空间内的进程误以为 sleep 进程是 8号进程。

除了 PID 的隔离,Linux Namespaces 技术还支持 UTS、IPC、Network、Mount、User 等资源的隔离。

和虚拟化一个完整的操作系统不同,Linux Namespaces 的隔离机制存在缺陷,那就是资源“隔离的不彻底”。容器本质上和运行在宿主机上的其它进程没有本质区别,依赖的还是操作系统的内核,尽管你可以在容器里通过 Mount Namespace 单独挂载其他不同版本的操作系统文件,比如 CentOS 或者 Ubuntu,但这并不能改变容器共享宿主机内核的事实。

另外,在 Linux 中很多资源和对象,是无法被 Namespaces 隔离的,最典型的就是“时间”。如果某个容器进程修改了系统时间,那么宿主机的时间就会被修改,所有的容器读取系统时间都会受到影响,牵一发而动全身。所以,使用容器部署应用,“什么能做,什么不能做”是开发者必须要考虑的。

限制

容器的隔离技术,更多的是“障眼法”,它只是改变了容器进程看待系统的“视图”,如果不对容器加以限制,就可能出现下面这种局面:

在操作系统看来,容器进程和其它进程没有区别,它们在抢夺资源时是平等的竞争关系,如果某个容器进程直接把内存或 cpu 等资源耗尽,就会导致宿主机上的其它容器或进程无法工作,甚至整个操作系统崩溃,这显然不应该是“容器”具备的破坏力。

Linux 内核提供了 cgroups(Linux Control Group)技术,它可以限制、记录和隔离进程组的资源使用,它允许系统管理员和开发者对系统资源进行精细的控制。

cgroups 功能概览:

  • 限制进程 CPU、内存、磁盘 I/O 和网络带宽等资源的使用
  • 为不同的进程组分配不同的资源优先级,确保关键任务获得足够的资源
  • 将进程分组,可以实现资源的隔离,防止一个进程组的资源消耗影响到其他进程组
  • 监控进程组的资源使用情况,帮助进行性能分析和调优
  • 动态地将进程加入或移出 cgroups,灵活管理进程的资源使用

以 CPU 资源限制为例,演示一个限制进程占用 0.5 个 CPU 核心的示例。

cgroups 通过一个特殊的虚拟文件系统来管理和操作,文件系统挂载在/sys/fs/cgroup 目录下,创建一个文件夹,内核会自动创建 cgroup 所需的文件。

> mkdir /sys/fs/cgroup/mygroup
> cd /sys/fs/cgroup/mygroup
> ls
cgroup.controllers        hugetlb.2MB.events
cgroup.events             hugetlb.2MB.events.local
cgroup.freeze             hugetlb.2MB.max
cgroup.kill               hugetlb.2MB.rsvd.current
cgroup.max.depth          hugetlb.2MB.rsvd.max
cgroup.max.descendants    io.max
cgroup.procs              io.pressure
cgroup.stat               io.prio.class
cgroup.subtree_control    io.stat
cgroup.threads            io.weight
cgroup.type               memory.current
cpu.idle                  memory.events
cpu.max                   memory.events.local
cpu.max.burst             memory.high
cpu.pressure              memory.low
cpu.stat                  memory.max
cpu.uclamp.max            memory.min
cpu.uclamp.min            memory.numa_stat
cpu.weight                memory.oom.group
cpu.weight.nice           memory.pressure
cpuset.cpus               memory.stat
cpuset.cpus.effective     memory.swap.current
cpuset.cpus.partition     memory.swap.events
cpuset.mems               memory.swap.high
cpuset.mems.effective     memory.swap.max
hugetlb.1GB.current       misc.current
hugetlb.1GB.events        misc.max
hugetlb.1GB.events.local  pids.current
hugetlb.1GB.max           pids.events
hugetlb.1GB.rsvd.current  pids.max
hugetlb.1GB.rsvd.max      rdma.current
hugetlb.2MB.current       rdma.max

在这个子目录在,cpu.max 文件配置的就是 cpu 资源的限制,格式:<max_quota> <max_period> ,max_period 是时间周期,单位是微妙,默认是 100000μs,即 100ms。max_quota 是在这个时间周期内,进程最多可以占用 cpu 的时间,默认是 20000μs,即 20ms。默认配置,意味着进程最多可以占用 1/5 个cpu 核心。

写入我们的自定义配置,在 100ms 内进程最多使用 50ms 的 CPU,即 0.5 个核心。

> echo '50000 100000' > /sys/fs/cgroup/mygroup/cpu.max

把进程 ID 写入cgroup.procs ,交给 cgroups 管理

> echo $$ > /sys/fs/cgroup/mygroup/cgroup.procs

接着,当前进程执行死循环,尝试把 CPU 打满

>  while : ; do : ; done

新开一个终端,top 命令查看,会发现死循环进程,最多占用 0.5 颗 CPU。因为笔者的服务器是2核的,所以总的 CPU 负载大约在 25%。

其它类型的资源限制,操作上同理。

切换根文件系统

隔离了容器进程的视图,限制了容器进程资源的占用,最后一步,就是给容器进程切换到一个全新的“根文件系统”,使得每个容器进程都有自己的根文件系统,容器可以在自己的文件系统里面任意折腾,而不会影响到宿主机和其它容器。

在这个全新的根文件系统里,包含容器运行的所有依赖库和用户应用程序,最后把这个文件系统打包,就是我们熟知的“镜像”。有了镜像,就可以一键部署应用,再也不会出现“应用在测试环境部署没问题,到线上就部署失败”的场景,解决了应用程序的环境依赖问题。

pivot_root 是 Linux 内核中的一个系统调用,主要用于改变当前进程的根文件系统。

pivot_root 使用的基本流程:

  1. 准备一个新的根文件系统(必须包含必要的文件和依赖库)
  2. 挂载到宿主机的某个目录
  3. 执行 pivot_root 切换当前进程的根文件系统
  4. cd / 切换到新的根文件系统
  5. 卸载旧根文件系统

pivot_root 需要 root 权限,且新根文件系统必须是一个挂载点,旧根必须挂载到新根的子目录下。

示例,/container 目录下有个镜像文件 image.tar,它是基于 BusyBox 构建的 Linux 环境,仅有 4M 大小的根文件系统。执行下面的命令,unshare 进入新的 mount 命名空间,解压文件系统到 /container/rootfs,最后 pivot_root 切换到新的根文件系统。

> unshare --mount  --fork -- bash -c '
# 创建新根目录
mkdir -p /container/rootfs
# 挂载
mount -t tmpfs rootfs /container/rootfs
# 解压根文件系统到新根目录,确保新根文件系统有必要的文件
tar -xf /container/image.tar -C /container/rootfs
# 创建旧根目录
mkdir -p /container/rootfs/old_rootfs
# 切换到新根,同时挂载旧根到/container/rootfs/old_rootfs
pivot_root /container/rootfs /container/rootfs/old_rootfs
cd /
exec /bin/sh
'

新的命名空间内的进程切换根文件系统后,列出根目录下的文件,会发现和宿主机是不同的,当前文件系统任意折腾,都不会影响宿主机,确保容器有一个隔离、安全的环境。

> ls /
bin         etc         lib         old_rootfs  root        tmp         var
dev         home        lib64       proc        sys         usr

尾巴

Linux 容器的本质就是一个被 Namespaces 隔离视图、被 cgroups 限制资源,以及被 pivot_root 切换了根文件系统的进程而已。相较于虚拟机,容器实现了高效的资源利用和快速的启动时间,同时保持了应用的隔离性和安全性。

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

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

相关文章

LeetCode 第75题:颜色分类

给定一个包含红色、白色和蓝色、共n个元素的数组nums&#xff0c;原地对它们进行排序&#xff0c;使得相同颜色的元素相邻&#xff0c;并按照红色、白色、蓝色顺序排序。 使用整数0、1和2分布表示红色、白色和蓝色。 必须在不使用库内置sort函数的情况下解决这个问题。 示例1&a…

PHP基础-函数

函数是一段可重复使用的代码块&#xff0c;可以将一系列操作封装起来&#xff0c;使代码更加模块化、可维护和可重用&#xff0c;来大大节省我们的开发时间和代码量&#xff0c;提高编程效率。在PHP中你可以使用&#xff1a; 内置函数&#xff08;如 strlen()、array_merge()&a…

【FastAPI高级实战】结合查询参数与SQLModel Joins实现高效多表查询(分页、过滤、计数)

想象一下&#xff0c;你正在开发一个超酷的Web应用&#xff0c;比如一个博客平台或者一个在线商店。你的API不仅要能把数据&#xff08;比如文章列表、商品信息&#xff09;展示给用户&#xff0c;更要聪明到能理解用户的各种“小心思”&#xff1a;用户可能想看最新的文章、搜…

华为OD-2024年E卷-通过软盘拷贝文件[200分] -- python

问题描述&#xff1a; 有一名科学家想要从一台古董电脑中拷贝文件到自己的电脑中加以研究。但此电脑除了有一个3.5寸软盘驱动器以外&#xff0c;没有任何手段可以将文件持贝出来&#xff0c;而且只有一张软盘可以使用。因此这一张软盘是唯一可以用来拷贝文件的载体。科学家想要…

Keepalived 高可用,nginx + keepalived , lvs + keepalived、 数据库+keepalived

keepalived 官网 Keepalived 可以用来防止服务器单点故障的发生 # 原理 是基于VRRP协议实现的&#xff0c;当backup收不到vrrp包时&#xff0c;就认为master宕机了&#xff0c;这时就需要根据VRRP的优先级来选举一个backup 当master&#xff0c;就实现服务的HA&#xff08;高…

开疆智能Devicenet转ModbusTCP网关连接台达从站通讯模块配置案例

本案例是通过开疆智能Devicenet转ModbusTCP网关连接台达Devicenet从站通讯模块DVPDT02-H2的配置案例&#xff0c;网关作为ModbusTCP服务器和Devicenet主站&#xff0c;连接台达Devicenet从站&#xff0c; 配置过程&#xff1a; 首先配置Devicenet从站&#xff0c;先设置从站De…

网络NAT是什么

网络NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;是一种用于计算机网络中的技术&#xff0c;主要目的是在私有网络与公有网络&#xff08;比如互联网&#xff09;之间转换IP地址&#xff0c;实现私有网络中的多台设备通过一个公网IP访问外…

React状态管理——react-redux

目录 一、redux介绍 二、安装 三、基本实现步骤 3.1 创建Action Types 3.2 创建counterAction 3.3 创建counterReducer 3.4 结合所有Reducer 3.5 创建store 3.6 入口文件中提供store 3.7 在组件中的使用 3.8 使用thunk实现异步支持 3.8.1 安装 3.8.2 在counterAct…

Java 零工市场小程序 | 灵活就业平台 | 智能匹配 | 日结薪系统 | 用工一站式解决方案

在就业形势如此严峻的情况下&#xff0c;很多小伙伴都会选择零工的工作方式来赚取外快&#xff0c;很多用人单位也会因为职为短暂空缺或是暂时人手不够而选择招用兼职人员。 而Java 作为企业级开发的主流语言&#xff0c;以其卓越的性能和稳定性著称。把零工的需求&#xff08…

数据可视化——一图胜千言

第04篇&#xff1a;数据可视化——一图胜千言 写在前面&#xff1a;大家好&#xff0c;我是蓝皮怪&#xff01;前面几篇我们聊了统计学的基本概念、数据类型和描述性统计&#xff0c;这一篇我们要聊聊数据分析中最直观、最有趣的部分——数据可视化。你有没有发现&#xff0c;很…

1.1 Linux 编译FFmpeg 4.4.1

一、安装编译工具 sudo apt install -y autoconf automake build-essential cmake git pkg-config nasm yasm libtool zlib1g-dev说明&#xff1a; autoconf&#xff1a;生成 configure 脚本&#xff0c;用于自动配置源码。automake&#xff1a;与 autoconf 配合&#xff0c;…

【图片识别改名】如何批量识别大量图片的文字并重命名图片,基于WPF和京东OCR识别接口的实现方案

应用场景 在企业文档管理、数字图书馆、电商商品管理等场景中&#xff0c;经常需要处理大量图片中的文字信息。例如&#xff1a; 电商平台需要将商品图片中的型号、规格等信息提取出来作为文件名图书馆需要将扫描的图书页面识别为文字并整理归档企业需要将纸质文档电子化并按…

简历模板2——数据挖掘工程师5年经验

姓名 / Your Name 数据挖掘工程师 | 5年经验 | 推荐/风控/图模型 &#x1f4de; 138-XXXX-XXXX | ✉️ your.emailexample.com | &#x1f310; github.com/yourname | &#x1f4cd; 北京 &#x1f3af; 个人简介 / Summary 5年大厂数据挖掘经验&#xff0c;硕士学历。擅长推…

CSS3 渐变效果

1. 引言 CSS3 渐变能够在指定颜色之间创建平滑过渡效果。这种设计元素不仅能为网页增添丰富的视觉层次&#xff0c;更是现代网页设计的重要组成部分。CSS3 提供两种主要的渐变类型&#xff1a;线性渐变(Linear Gradient) - 沿直线方向进行颜色过渡&#xff1b;径向渐变(Radial…

A Survey on 3D Gaussian Splatting——3D高斯领域综述

原文链接&#xff1a;[2401.03890] A Survey on 3D Gaussian Splatting 动态更新的GitHub仓库&#xff08;包含性能对比与最新文献追踪&#xff09;&#xff1a; https://github.com/guikunchen/3DGS-Benchmarks https://github.com/guikunchen/Awesome3DGS 摘要&#xff1…

计算机网络 期末实训 eNSP 校园网

eNSP 综合实训 小型校园网 计算机网络期末实训 01 搭建拓扑 1.设计任务 构建一个小型校园网络,涵盖以下设备与区域: 学生宿舍区:50台计算机办公楼区:30台计算机(细分为财务部门、人事部门及其他科室)图书馆:10台计算机教学楼:30台计算机服务器集群:2台服务器,分别用…

Smart Form Adobe form 强制更改内表:TNAPR

强制更改内表:TNAPR se16-> Smart Form总览 Smart form 变量格式说明: &symbol& (括号中,小写字母为变量) &symbol& 屏蔽从第一位开始的N位 &symbol (n)& 只显示前N位 &symbol (S)& 忽略正负号 &symbol (<)& 符号在…

页面配置文件pages.json和小程序配置

页面配置文件pages.json和小程序配置 pages.jsonpagesstyle-navigationBarBackgroundColorstyle-navigationBarTitleTextstyle-navigationStylestyle-enablePullDownRefresh注意事项不同平台区分配置新建页面 globalStyletabBar代码 manifest.json授权web配置代理 pages.json …

Linux网络配置工具ifconfig与ip命令的全面对比

在Linux网络管理中&#xff0c;ifconfig和 ip命令是最常用的两个工具。随着时间的推移&#xff0c;ip命令逐渐取代了 ifconfig&#xff0c;成为更强大和灵活的网络配置工具。本文将对这两个工具进行全面对比&#xff0c;帮助您理解它们的区别和各自的优势。 一、ifconfig命令 …

STM32 实现解析自定义协议

一、环形队列设计与实现&#xff08;核心缓冲机制&#xff09; 数据结构设计&#xff1a; #define BUFFER_SIZE 512 #define BUFFER_MASK (BUFFER_SIZE - 1) typedef struct {volatile uint8_t buffer[BUFFER_SIZE]; // 环形缓冲区&#xff08;大小可配置&#xff09;volati…