深入解析:Docker 容器如何实现文件系统与资源的多维隔离?

目录

    • 一、RootFs
      • 1. Docker 镜像与文件系统层
      • 2. RootFs 与容器隔离的意义
    • 二、Linux Namespace
      • 1. 进程命名空间
        • 1.1 `lsns` 命令说明
        • 1.2 查看“祖先进程”命名空间
        • 1.3 查看当前用户进程命名空间
      • 2. 容器进程命名空间
        • 2.1 查看容器进程命名空间列表
        • 2.2 容器进程命名空间的具体体现
    • 三、cgroups
      • 1. cpu 子系统
        • 1.1 CFS (Completely Fair Scheduler)
        • 1.2 RT (Real-time Scheduler)
        • 1.3 示例
      • 2. cpuset 子系统
      • 3. cpuacct 子系统
      • 4. memory 子系统
        • 示例
      • 5. blkio 子系统
      • 6. devices 子系统
      • 7. freezer 子系统
      • 8. net_cls 子系统
      • 9. net_prio 子系统
      • 10. perf_event
      • 11. hugetlb
    • 总结

一、RootFs

在传统的 Linux 系统中,rootfs(根文件系统)就是系统的“根”目录,一般位于 /,其下包含 /bin/dev/etc 等常见目录结构。
在容器中,则通过镜像(Image)+**容器层(Container Layer)**的组合来提供容器自身的根文件系统,这个容器的根文件系统就是rootfs,与宿主机的 rootfs 相对隔离。

1. Docker 镜像与文件系统层

  • **镜像(Image)**由多层只读层(read-only layers)构成,利用了 Union FS 或 OverlayFS 等联合文件系统技术。
  • **容器层(Container Layer)**是该镜像之上的可写层(read-write layer)。容器运行时,对文件的修改都会写入到这个容器层中,不会影响只读层的内容。

2. RootFs 与容器隔离的意义

  • 当启动一个容器时,容器看到的“根文件系统”并非与宿主机相同,而是来自镜像 + 容器层组合形成的 rootfs。
  • 对于容器内部的进程来说,/ 就是容器自身的根目录,与宿主机的 / 相互独立(尽管底层还是同一个内核)。
  • 这种文件系统级别的隔离为容器提供了和宿主机隔离的外观,不同容器之间也不会直接污染彼此的文件系统。

二、Linux Namespace

Linux Namespace 是容器隔离的核心机制之一。Namespace 的主要作用是将系统资源进行“分名字空间”隔离,如进程(PID)、网络(NET)、文件系统挂载(MOUNT)、用户(USER)、IPC 等,从而让容器“以为”它拥有自己独立的环境。
在这里插入图片描述

1. 进程命名空间

1.1 lsns 命令说明
  • lsns 是 Linux 提供的一个查看系统中命名空间信息的命令。可以用 lsns 查看当前系统里所有命名空间,如 lsns -t pid 可以查看 PID 命名空间,lsns -t net 查看网络命名空间等。
  • 常见列示信息包含:
    • NS TYPE: 命名空间类型(如 pidnetmntutsipcuser 等)。
    • NSID: 命名空间 ID,一般可以在 /proc/pid/ns 路径中看到相应符号链接。
    • PID: 对应的进程号。
    • Command: 该命名空间对应进程的启动命令。
1.2 查看“祖先进程”命名空间

在 Linux 中,每个进程都有对应的命名空间引用(指针)。如果想要查看某个进程(比如 PID=1 或者宿主机上的某个 PID)的命名空间,可以通过:
列出系统所有命名空间

sudo lsns --output0all

在这里插入图片描述

ls -l /proc/<PID>/ns

这会展示对应的符号链接,比如:

lrwxrwxrwx 1 root root 0 Jan  1 00:00 /proc/1/ns/pid -> pid:[4026531836]

这样就能看到 pid:[4026531836] 对应的命名空间 ID。通常 PID=1(系统的 init 或 systemd)会在宿主机的最初始 namespace 中。

1.3 查看当前用户进程命名空间

直接对你当前 shell 的 PID 进行查看:

echo $$
# 假设输出为 12345
ls -l /proc/12345/ns

就能看到你当前 shell 进程所使用的 namespace。

2. 容器进程命名空间

容器之所以能够让其内部进程彼此隔离,主要原因之一是 Docker(或其他容器运行时)在启动容器进程时,会为该进程创建或加入单独的命名空间(PID/NET/IPC/UTS 等)。

2.1 查看容器进程命名空间列表

假设我们有一个正在运行的容器,可以先找到容器对应的“容器进程”:

docker ps
docker inspect <container_id> | grep "Pid"

然后拿到对应的 PID,比如是 23456。接着:

ls -l /proc/23456/ns

就能看到容器进程使用的所有 namespace 绑定信息。

2.2 容器进程命名空间的具体体现
  • PID Namespace
    容器内部查看到的进程号(PID)从 1 开始,而在宿主机上,这个容器的进程是一个完全不同的 PID 值。容器内部的“PID=1”通常是容器内的 init 进程。
  • Network Namespace
    容器有自己单独的网卡配置(如 eth0),与宿主机是隔离的。通过容器的 network namespace,可以将容器网络与宿主机网络解耦(或进行端口映射)。
  • Mount Namespace
    容器有自己挂载的文件系统视图,比如 / 是容器自己的 rootfs。与宿主机的挂载点不同。
  • IPC Namespace
    容器之间的共享内存、消息队列等 IPC 机制互不影响。
  • UTS Namespace
    容器可以有自己独立的 hostname。容器内 hostname 与宿主机可以不同。

借助这些命名空间,容器可以呈现一个与宿主机几乎隔离的操作系统视图。


三、cgroups

cgroups (control groups) 是 Linux 提供的另一项关键特性,用于对系统资源进行“配额、限制、监控、隔离”。Docker 容器通过将容器进程加入到相应的 cgroup,来限制其对 CPU、内存、IO 等资源的使用或进行统计。

cgroups 是一个可插拔的框架,常见的子系统包括:

  • cpu
  • cpuset
  • cpuacct
  • memory
  • blkio
  • devices
  • freezer
  • net_cls
  • net_prio
  • perf_event
  • hugetlb
    等。

下面分别简要介绍这些子系统在容器隔离中的作用或使用示例。

1. cpu 子系统

cpu 子系统主要用于限制或分配 CPU 时间片给某个 cgroup 内进程。让我们来看看常见的调度器和示例。

1.1 CFS (Completely Fair Scheduler)
  • Linux 默认的 CPU 调度器。可通过 cpu.sharescpu.cfs_period_uscpu.cfs_quota_us 等文件对 CPU 使用进行相对或绝对限额设置。
  • 例如要限制某个 cgroup 的进程只能使用“相当于一个 CPU 核心”的计算量,可以在 cpu.cfs_period_us = 100000(默认100ms)和 cpu.cfs_quota_us = 100000 之间做设置,这样就大致等价于 1 core。
1.2 RT (Real-time Scheduler)
  • RT 调度针对实时任务,可以用来做实时优先级的资源控制。不过容器中常见应用较少直接动用 RT 调度。
1.3 示例

在手动配置 cgroup 时,可能会:

  1. 创建目录:mkdir /sys/fs/cgroup/cpu/test_cgroup
  2. 写入一些限制:
    echo 200000 > /sys/fs/cgroup/cpu/test_cgroup/cpu.cfs_quota_us
    echo 100000 > /sys/fs/cgroup/cpu/test_cgroup/cpu.cfs_period_us
    
    表示此 cgroup 一次调度周期内(100ms),只能用 200ms CPU 时间,相当于可以使用 2 核的 CPU 时间。
  3. 把某个进程写入 tasks:
    echo <pid> > /sys/fs/cgroup/cpu/test_cgroup/tasks
    
    该进程的 CPU 使用就受限于此组的规则。

Docker 在启动容器时会自动做这些事情,如 --cpus--cpuset-cpus 等参数。

2. cpuset 子系统

  • cpuset 子系统允许指定某些 CPU 核、某些内存节点给特定的 cgroup。
  • 比如可以指定容器只能在 CPU 0 和 1 上运行,或者只能从 NUMA 节点0分配内存。
  • Docker 对应的参数是 --cpuset-cpus="0-1" 之类。

3. cpuacct 子系统

  • cpuacct 用于统计某个 cgroup 内进程的 CPU 使用情况(用户态、内核态占用总时长),只做统计不做限制。
  • Docker 可以通过这个子系统查看容器的 CPU 使用状态。

4. memory 子系统

memory 子系统用于限制和统计进程的内存使用,包括物理内存和 swap。

  • 常见的控制文件:
    • memory.limit_in_bytes:该 cgroup 最大物理内存限制。
    • memory.memsw.limit_in_bytes:物理内存 + swap 限制(如果启用 swap 记账)。
  • 通过设置这些值,可防止某些进程用光系统所有内存。
示例
  1. 创建 cgroup:mkdir /sys/fs/cgroup/memory/test_mem
  2. 设置限制:
    echo 524288000 > /sys/fs/cgroup/memory/test_mem/memory.limit_in_bytes  # 500MB
    
  3. 将进程加入:
    echo <pid> > /sys/fs/cgroup/memory/test_mem/tasks
    
    这样该进程占用内存在超过 500MB 时可能会触发 OOM(Out Of Memory)动作。

5. blkio 子系统

  • blkio (Block IO) 用于限制进程的块设备 IO 速率,比如磁盘读写速度。
  • 可以设置读取速率、写入速率的限制。对需要在容器层面做 IO QoS 的场景很有帮助。

6. devices 子系统

  • devices 子系统可以控制某个 cgroup 中的进程可以访问哪些设备、只能读或写、或完全禁止访问等。
  • 容器通常为了安全,会只允许访问少数必要设备(比如 /dev/null/dev/random 等)。

7. freezer 子系统

  • freezer 子系统提供了把 cgroup 内进程“冻结/解冻”的功能。
  • 可以把某个 cgroup 的状态设置为 FROZEN,则该组内所有进程都挂起,等到切回 THAWED 才继续运行。

8. net_cls 子系统

  • net_cls 可以为网络数据包打上一个分类标识(classid),配合 tc(traffic control)做网络流量整形或带宽控制。

9. net_prio 子系统

  • net_prio 子系统可以为 cgroup 中的进程设置网络优先级(priority),从而在同一台宿主机上的容器间做网络流量优先级区分。

10. perf_event

  • perf_event 子系统方便对一组进程进行性能计数器(performance counter)的监控,比如 CPU cycle、cache miss 等。

11. hugetlb

  • hugetlb 用于管理大页内存(Huge Pages)。可以限制某个 cgroup 使用多少大页内存。

总结

通过 RootFsLinux Namespacecgroups 的巧妙组合,Docker 容器能够在同一个 Linux 内核上运行,却拥有与宿主机和其他容器相对独立的文件系统、进程空间、网络环境、IPC、以及严格的资源配额/限制。这为容器提供了接近虚拟机的隔离性,同时也保留了“共享同一个内核”的优势(启动速度快、资源开销小等)。

  1. RootFs:让容器拥有独立的文件系统视图,与宿主机的根目录区分开来。
  2. Linux Namespace
    • PID Namespace 让容器内部进程有各自的 PID 视图。
    • Network Namespace 让容器拥有独立的虚拟网卡、网络栈。
    • Mount Namespace 让容器控制自己的挂载点。
    • UTS、IPC、User Namespace 等也实现其他层面的隔离。
  3. cgroups
    • 对 CPU、内存、IO 等进行资源限制和监控。
    • 通过 Docker 参数可很方便地指定容器的资源上限、优先级。

这些机制共同构成了 Docker 容器环境下的核心隔离限制手段,使得容器能够安全、稳定地在生产环境中运行各种应用。


参考:
0voice · GitHub

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解锁Java中的国密算法:安全保障的密钥

一、引言 在数字化浪潮席卷全球的当下&#xff0c;信息安全已然成为国家、企业乃至个人无法忽视的重要议题。国密算法&#xff0c;作为我国自主研发的密码算法体系&#xff0c;宛如坚固的盾牌&#xff0c;为国家信息安全筑起了一道坚不可摧的防线。它的诞生&#xff0c;不仅承载…

proxysql读写分离的部署

关闭防火墙和selinux systemctl stop firewalld systemctl disable firewalld setenforce 0设置主机名称 hostnamectl set-hostname zhangyijia-host71.database.com && bash hostnamectl set-hostname zhangyijia-host72.database.com && bash两台主机安装m…

Android各个版本存储权限适配

一、Android6.0-9.0 1、动态权限申请&#xff1a; private static String[] arrPermissions {android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE,android.Manifest.permission.ACCESS_FINE_LOCATION,android.Manifest.…

【xcode 16.2】升级xcode后mac端flutter版的sentry报错

sentry_flutter 7.11.0 报错 3 errors in SentryCrashMonitor_CPPException with the errors No type named terminate_handler in namespace std (line 60) and No member named set_terminate in namespace std 替换sentry_flutter版本为&#xff1a; 8.3.0 从而保证oc的…

ASP.NET Core 6.0 如何处理丢失的 Startup.cs 文件

介绍 .NET 6.0 已经发布&#xff0c;ASP.NET Core 6.0 也已发布。其中有不少变化让很多人感到困惑。例如&#xff0c;“谁动了我的奶酪”&#xff0c;它在哪里Startup.cs&#xff1f;在这篇文章中&#xff0c;我将深入研究这个问题&#xff0c;看看它移动到了哪里以及其他变化。…

idea plugin插件开发——入门级教程(IntelliJ IDEA Plugin)

手打不易&#xff0c;如果转摘&#xff0c;请注明出处&#xff01; 注明原文&#xff1a;idea plugin插件开发——入门级教程&#xff08;IntelliJ IDEA Plugin&#xff09;-CSDN博客 目录 前言 官方 官方文档 代码示例 开发前必读 Intellij、Gradle、JDK 版本关系 plu…

概率密度函数(PDF)分布函数(CDF)——直方图累积直方图——直方图规定化的数学基础

对于连续型随机变量&#xff0c;分布函数&#xff08;Cumulative Distribution Function, CDF&#xff09;是概率密度函数&#xff08;Probability Density Function, PDF&#xff09;的变上限积分&#xff0c;概率密度函数是分布函数的导函数。 如果我们有一个连续型随机变量…

三分钟简单了解一些HTML的标签和语法_02

1.a标签演示 点击然后跳转 代码加入title 2.图片链接 3.锚点链接 点击就会跳转的当前位置 4.a标签小知识补充 该实例会跳转到顶,锚点链接则会跳转到相应的锚点 5. 结果:直接跳转到该页面的锚点处 6. 在 HTML 中&#xff0c;<tr>标签表示表格中的行&#xff08;TableRow&…

mysql 学习3 SQL语句--整体概述。SQL通用语法;DDL创建数据库,查看数据库,删除数据库,使用数据库;

SQL通用语法 SQL语句分类 DDL data definition language : 用来创建数据库&#xff0c;创建表&#xff0c;创建表中的字段&#xff0c;创建索引。因此成为 数据定义语言 DML data manipulation language 有了数据库和表以及字段后&#xff0c;那么我们就需要给这个表中 添加数…

基于ollama,langchain,springboot从零搭建知识库三【解析文档并存储到向量数据库】

安装环境 安装pgvector&#xff0c;先设置docker镜像源&#xff1a; vim /etc/docker/daemon.json {"registry-mirrors": ["https://05f073ad3c0010ea0f4bc00b7105ec20.mirror.swr.myhuaweicloud.com","https://mirror.ccs.tencentyun.com",&…

C# OpenCV机器视觉:红外体温检测

在一个骄阳似火的夏日&#xff0c;全球却被一场突如其来的疫情阴霾笼罩。阿强所在的小镇&#xff0c;平日里熙熙攘攘的街道变得冷冷清清&#xff0c;人们戴着口罩&#xff0c;行色匆匆&#xff0c;眼神中满是对病毒的恐惧。阿强作为镇上小有名气的科技达人&#xff0c;看着这一…

计算机视觉算法实战——无人机检测

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​ 1. 引言✨✨ 随着无人机技术的快速发展&#xff0c;无人机在农业、物流、监控等领域的应用越来越广泛。然而&#xff0c;无人机的滥用也带…

日志收集Day004

1.filebeat安装 基于二进制安装filebeat (1)下载filebeat软件包 (2)解压软件包 tar xf filebeat-7.17.5-linux-x86_64.tar.gz -C /app/softwares/ (3)验证filebeat安装是否成功 cd /app/softwares/filebeat-7.17.5-linux-x86_64/ ln -svf pwd/filebeat /usr/local/sbin/ f…

Vue入门(Vue基本语法、axios、组件、事件分发)

Vue入门 Vue概述 Vue (读音/vju/&#xff0c;类似于view)是一套用于构建用户界面的渐进式框架&#xff0c;发布于2014年2月。与其它大型框架不同的是&#xff0c;Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三…

缓存商品、购物车(day07)

缓存菜品 问题说明 问题说明&#xff1a;用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大。 结果&#xff1a; 系统响应慢、用户体验差 实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询…

数据结构测试题2

一、单选题&#xff08;每题 2 分&#xff0c;共20分&#xff09; 1. 栈和队列的共同特点是( A )。 A.只允许在端点处插入和删除元素 B.都是先进后出 C.都是先进先出 D.没有共同点 2. 用链接方式存储的队列&#xff0c;在进行插入运算时( C ) A. 仅修改头指针 B. 头…

qml Settings详解

1、概述 QML中的Settings类提供了一种便捷的方式来保存和恢复应用程序的配置信息&#xff0c;如用户名、密码、窗口位置和大小等。它简化了配置数据的存储过程&#xff0c;无需使用像SQLite这样的数据库系统。通过使用Settings&#xff0c;开发者可以轻松实现应用程序设置的持…

认识Django项目模版文件——Django学习日志(二)

1.默认文件介绍 └── djangoproject1/├── djangoproject1/│ ├── urls.py [URL和函数的对应关系]【常用文件】│ ├── settings.py [项目配置文件]【常用文件】│ ├── _init_.py│ ├── wsgi.py [接受网络请求] 【不要动】│ └──…

Qt实践:一个简单的丝滑侧滑栏实现

Qt实践&#xff1a;一个简单的丝滑侧滑栏实现 笔者前段时间突然看到了侧滑栏&#xff0c;觉得这个抽屉式的侧滑栏非常的有趣&#xff0c;打算这里首先尝试实现一个简单的丝滑侧滑栏。 首先是上效果图 &#xff08;C&#xff0c;GIF帧率砍到毛都不剩了&#xff09; QProperty…

【Linux网络编程】传输层协议

目录 一&#xff0c;传输层的介绍 二&#xff0c;UDP协议 2-1&#xff0c;UDP的特点 2-2&#xff0c;UDP协议端格式 三&#xff0c;TCP协议 3-1&#xff0c;TCP报文格式 3-2&#xff0c;TCP三次握手 3-3&#xff0c;TCP四次挥手 3-4&#xff0c;滑动窗口 3-5&#xf…