为什么 Docker 容器中有额外的目录(如 `/dev`、`/proc`、`/sys`)?及 `docker run` 详细执行过程
、当你使用 docker run 启动一个基于极简镜像(如 scratch 或手动构建的镜像)的容器时,发现容器内出现了 /dev、/proc、/sys 等目录,即使你的镜像中并未包含这些目录。这是因为 Docker 在启动容器时,会自动挂载一些必要的文件系统,以确保容器能够正常运行。本文将详细解答这一现象的原因,并结合问题深入讲解 docker run 的执行过程,揭示 Docker 容器启动的底层机制,提供大量干货。
1. 为什么容器中有 /dev、/proc、/sys 等目录?
1.1 原因:Docker 自动挂载的默认文件系统
Docker 容器运行在宿主机的 Linux 内核之上,依赖内核提供的功能(如进程管理、设备访问)。为了让容器正常工作,Docker 在启动容器时会自动挂载一些特殊文件系统到容器的根文件系统(rootfs),即使你的镜像(如基于 scratch)不包含这些目录。这些文件系统包括:
-
/proc:- 类型:
procfs(虚拟文件系统)。 - 作用:提供进程信息、内核状态和系统配置。例如,
/proc/cpuinfo显示 CPU 信息,/proc/self显示当前进程信息。 - 为什么挂载:容器内的进程需要访问自身状态(如 PID、环境变量),或与内核交互。
- 类型:
-
/sys:- 类型:
sysfs(虚拟文件系统)。 - 作用:暴露内核的设备、驱动和硬件信息。例如,
/sys/devices显示设备树。 - 为什么挂载:容器可能需要访问硬件或内核参数(如网络设备状态)。
- 类型:
-
/dev:- 类型:
devtmpfs或tmpfs(部分设备节点由udev管理)。 - 作用:提供设备文件(如
/dev/null、/dev/zero、/dev/random),用于与硬件或内核交互。 - 为什么挂载:容器需要基本的设备访问,例如标准输入/输出(
/dev/stdin)或伪随机数生成(/dev/random)。
- 类型:
这些目录不是来自你的镜像,而是 Docker 在容器启动时通过 挂载(mount) 动态添加的。它们是 Linux 内核提供的虚拟文件系统,存在于内存中,不占用镜像的磁盘空间。
1.2 挂载的来源
这些文件系统通常来自宿主机的内核或特定的文件系统挂载点:
/proc和/sys:直接挂载宿主机的/proc和/sys,但通过 命名空间隔离(如 PID 和 Mount 命名空间)限制容器只能看到自己的进程和设备信息。/dev:Docker 创建一个tmpfs文件系统,并填充必要的设备节点(如/dev/null)。某些设备(如 GPU)可能通过--device选项从宿主机映射。
1.3 如何验证这些目录是挂载的?
在容器内运行以下命令,查看挂载点:
docker run -it my-hello sh
# 假设镜像包含 sh,运行:
mount
输出示例:
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
devtmpfs on /dev type devtmpfs (rw,nosuid,relatime,size=1024000k,nr_inodes=256000,mode=755)
- 说明:
/proc、sys和/dev是挂载的虚拟文件系统。
若镜像(如 scratch)不包含 sh,可通过宿主机检查:
# 获取容器 ID
docker ps
# 检查容器挂载
cat /proc/$(docker inspect <container_id> --format '{{.State.Pid}}')/mounts
1.4 如何避免这些目录?
如果你希望容器内不出现这些目录,可以通过以下方式控制,但需谨慎,因为这可能导致容器无法正常运行:
-
禁用默认挂载:使用
--mount或--volume自定义挂载,但 Docker 通常强制挂载/proc和/dev的子集。 -
使用
--read-only:将文件系统设为只读,限制动态修改:docker run --read-only my-hello但
/proc和/sys仍会挂载,因为它们是必需的。 -
自定义挂载命名空间:通过
unshare或自定义容器运行时(如runc)手动配置,但复杂且不推荐。
注意:完全禁用这些挂载可能导致程序无法运行(如无法访问 /dev/null 或进程信息)。
2. docker run 的执行过程详解
为了深入理解为何会出现 /dev、/proc、/sys,我们需要剖析 docker run 的完整执行过程。docker run 是 Docker 的核心命令,负责创建和启动容器。以下是其底层步骤,结合问题进行详细讲解:
2.1 解析命令参数
当你运行:
docker run --rm -it my-hello
Docker CLI 解析参数:
--rm:容器退出后自动删除。-it:分配交互式终端(-i保持标准输入,-t分配伪终端)。my-hello:指定镜像名称。
Docker CLI 将解析后的参数发送到 Docker Daemon(通过 /var/run/docker.sock)。
2.2 拉取镜像(若必要)
若本地不存在 my-hello 镜像,Docker 会从配置的镜像仓库(如 Docker Hub)拉取:
docker pull my-hello
对于本地构建的镜像(如上文基于 scratch 或手动导入),此步骤跳过。
2.3 创建容器
Docker Daemon 调用容器运行时(通常为 containerd 和 runc)创建容器,涉及以下子步骤:
2.3.1 初始化容器配置
- 从镜像的元数据(
config.json)读取配置,如:CMD:默认执行命令(如/bin/hello)。ENV:环境变量。EXPOSE:暴露的端口。
- 合并
docker run的参数(如--rm、-it)覆盖默认配置。
2.3.2 设置命名空间
Docker 使用 Linux 命名空间隔离容器环境:
- PID 命名空间:容器有独立的进程树,
/proc只显示容器内进程。 - Network 命名空间:隔离网络接口、IP 地址。
- Mount 命名空间:隔离文件系统挂载点。
- UTS 命名空间:隔离主机名和域名。
- IPC 命名空间:隔离进程间通信。
- User 命名空间(可选):映射用户和组 ID。
这些命名空间确保容器内的 /proc、/sys 只反映容器自己的状态,而非宿主机。
2.3.3 创建文件系统
Docker 准备容器的根文件系统(rootfs):
-
解压镜像层:镜像由多层 tar 归档组成,Docker 将其解压到容器的工作目录(如
/var/lib/docker/overlay2/<container_id>)。 -
挂载 rootfs:使用
overlayfs(或其他存储驱动)将镜像层和容器可写层合并,形成统一的根文件系统。 -
挂载特殊文件系统:
- 挂载
/proc(procfs)以提供进程信息。 - 挂载
/sys(sysfs)以提供设备和内核信息。 - 挂载
/dev(devtmpfs),并填充基本设备节点(如/dev/null、/dev/zero)。 - 若使用
-it,挂载/dev/tty或伪终端设备。
这就是为何
/dev、/proc、/sys出现在容器中的原因。 - 挂载
-
应用挂载选项:
- 如果指定了
--volume或--mount,挂载额外的卷。 - 如果使用了
--read-only,将 rootfs 设为只读(但/proc等仍为读写)。
- 如果指定了
2.3.4 配置 cgroups
Docker 使用 cgroups(控制组)限制容器资源:
- CPU:限制 CPU 使用(如
--cpus)。 - 内存:限制内存(如
--memory)。 - IO:限制磁盘 IO(如
--blkio-weight)。 - 进程数:限制最大进程数(如
--pids-limit)。
cgroups 信息可在宿主机的 /sys/fs/cgroup 中查看。
2.3.5 配置安全选项
- Capabilities:Docker 默认丢弃大部分 Linux 权限(如
CAP_SYS_ADMIN),仅保留必要权限(如CAP_NET_BIND_SERVICE用于绑定低端口)。 - Seccomp:应用默认的 seccomp 配置文件,限制系统调用。
- AppArmor/SELinux(若启用):应用额外的安全策略。
2.4 启动容器
容器创建完成后,Docker 调用运行时(如 runc)启动容器:
- 执行入口点:
- 根据镜像的
CMD或docker run指定的命令,运行主进程(如/bin/hello)。 - 如果指定了
-it,为主进程分配伪终端。
- 根据镜像的
- 设置网络:
- 默认使用桥接网络(
bridge),为容器分配 IP。 - 如果指定了
--network,应用自定义网络(如host或none)。
- 默认使用桥接网络(
- 处理信号:
- Docker 捕获容器主进程的退出状态,决定是否停止容器。
- 如果指定了
--rm,容器退出后自动删除。
2.5 运行后处理
- 日志收集:Docker 将容器的标准输出和错误输出记录到日志(查看:
docker logs <container_id>)。 - 状态更新:更新容器状态(如
running、exited),可通过docker ps查看。 - 端口映射:如果指定了
-p,Docker 配置 iptables 或其他网络规则,将宿主机端口映射到容器端口。
3. 深入剖析 /dev、/proc、/sys 的挂载
3.1 /proc 的挂载
- 挂载命令(内部执行):
mount -t proc proc /proc - 隔离机制:通过 PID 命名空间,容器只能看到自己的进程(如
/proc/1是容器主进程)。 - 禁用方法(不推荐):
使用--mount type=tmpfs,destination=/proc覆盖,但会导致进程无法访问自身信息,可能崩溃。
3.2 /sys 的挂载
- 挂载命令:
mount -t sysfs sysfs /sys - 隔离机制:Mount 命名空间限制容器只能访问相关设备信息。
- 禁用方法:类似
/proc,但禁用可能导致网络或硬件功能失效。
3.3 /dev 的挂载
- 挂载命令:
mount -t devtmpfs devtmpfs /dev - 设备节点:Docker 默认创建以下节点:
/dev/null、/dev/zero、/dev/random、/dev/urandom。/dev/stdin、/dev/stdout、/dev/stderr(符号链接)。- 如果使用
-it,创建/dev/tty或伪终端。
- 管理方式:Docker 使用
udev或静态设备节点填充/dev。 - 自定义设备:通过
--device添加宿主机设备:docker run --device=/dev/sda my-hello
3.4 为什么不能完全避免挂载?
这些文件系统是 Linux 内核与用户空间交互的桥梁,许多程序(即使是静态二进制)都会直接或间接依赖它们。例如:
- Go 程序可能读取
/proc/self/stat获取进程状态。 - HTTPS 请求需要
/dev/urandom生成随机数。 - 标准输出依赖
/dev/stdout。
完全禁用这些挂载需要自定义容器运行时(如 runc)并修改内核配置,但复杂且不实用。
4. 高级技巧与干货
4.1 控制挂载行为
-
最小化
/dev:使用--device-cgroup-rule限制设备访问:docker run --device-cgroup-rule='c 1:3 rwm' my-hello- 仅允许访问
/dev/null(字符设备,主设备号 1,次设备号 3)。
- 仅允许访问
-
覆盖挂载(实验性):
docker run --mount type=tmpfs,destination=/proc my-hello但可能导致程序崩溃。
4.2 调试挂载问题
-
查看容器挂载:
docker inspect <container_id> | grep -i mount或在宿主机:
cat /proc/$(docker inspect <container_id> --format '{{.State.Pid}}')/mounts -
进入容器检查:
如果镜像包含sh:docker run -it my-hello sh ls /proc /sys /dev -
导出镜像分析:
docker save my-hello -o my-hello.tar tar -tf my-hello.tar确认镜像本身不包含
/dev、/proc、/sys。
4.3 优化容器启动
-
禁用不必要的命名空间(实验性):
docker run --pid=host --network=host my-hello- 使用宿主机的 PID 和网络命名空间,减少隔离,但安全性降低。
-
最小化 cgroups:
docker run --memory=50m --cpus=0.5 my-hello
4.4 安全性增强
- 丢弃权限:
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE my-hello - 只读文件系统:
docker run --read-only my-hello - 自定义 seccomp:
创建自定义 seccomp 配置文件,限制系统调用:docker run --security-opt seccomp=custom.json my-hello
4.5 常见问题与解决
- 容器无法启动:
- 检查二进制是否静态编译:
ldd /bin/hello。 - 确保入口点正确:
docker run my-hello /bin/hello。
- 检查二进制是否静态编译:
- 意外挂载过多设备:
- 检查
docker run参数是否包含--privileged(会导致挂载宿主机的/dev)。 - 使用
--device精确控制设备。
- 检查
- 性能问题:
- 减少挂载:避免不必要的
--volume。 - 优化 cgroups:限制资源使用。
- 减少挂载:避免不必要的
5. 实战案例
案例 1:验证挂载来源
- 运行容器:
docker run -it my-hello sh - 检查挂载:
mount | grep -E 'proc|sys|dev' - 宿主机验证:
docker inspect <container_id> --format '{{.State.Pid}}' cat /proc/<pid>/mounts
案例 2:最小化 /dev 设备
运行容器,仅允许 /dev/null:
docker run --device-cgroup-rule='c 1:3 rwm' my-hello
检查:
docker run -it my-hello ls /dev
仅显示 /dev/null。
案例 3:禁用默认挂载(实验性)
尝试覆盖 /proc:
docker run --mount type=tmpfs,destination=/proc my-hello
注意:可能导致程序崩溃,仅用于实验。
6. 扩展学习
- OCI 规范:研究 OCI 运行时规范 理解容器启动。
- containerd 和 runc:深入学习 Docker 的底层运行时。
- Linux 内核:学习
procfs、sysfs和devtmpfs的实现。 - 安全强化:探索
AppArmor、SELinux和seccomp的配置。
7. 总结
容器中出现的 /dev、/proc、/sys 是 Docker 在启动时自动挂载的虚拟文件系统,用于支持进程管理、设备访问和内核交互。这些挂载由 Linux 内核提供,通过命名空间隔离,确保容器只访问自身相关的信息。docker run 的执行过程包括解析参数、拉取镜像、创建容器(设置命名空间、文件系统、cgroups、安全选项)以及启动主进程。通过理解这一过程,你可以优化容器配置、调试问题并增强安全性。建议在测试环境多实践,结合 docker inspect 和 mount 命令深入探索挂载行为。
相关文章:
为什么 Docker 容器中有额外的目录(如 `/dev`、`/proc`、`/sys`)?及 `docker run` 详细执行过程
、当你使用 docker run 启动一个基于极简镜像(如 scratch 或手动构建的镜像)的容器时,发现容器内出现了 /dev、/proc、/sys 等目录,即使你的镜像中并未包含这些目录。这是因为 Docker 在启动容器时,会自动挂载一些必要…...
Tailwind 武林奇谈:bg-blue-400 失效,如何重拾蓝衣神功?
前言 江湖有云,Tailwind CSS,乃前端武林中的轻功秘籍。习得此技,排版如行云流水,配色似御风随形,收放自如,随心所欲。 某日,小侠你奋笔敲码,正欲施展“蓝衣神功”(bg-blue-400),让按钮怒气冲冠、蓝光满面,怎料一招使出,画面竟一片白茫茫大地真干净,毫无半点杀气…...
【Docker 运维】Java 应用在 Docker 容器中启动报错:`unable to allocate file descriptor table`
文章目录 一、根本原因二、判断与排查方法三、解决方法1、限制 Docker 容器的文件描述符上限2、在执行脚本中动态设置ulimit的值3、升级至 Java 11 四、总结 容器内执行脚本时报错如下,Java 进程异常退出: library initialization failed - unable to a…...
开始放飞之先搞个VSCode
文章目录 开始放飞之先搞个VSCode重要提醒安装VSCode下载MinGW-w64回到VSCode中去VSCode原生调试键盘问题遗留问题参考文献 开始放飞之先搞个VSCode 突然发现自己的新台式机上面连个像样的编程环境都没有,全是游戏了!!!ÿ…...
基于SA模拟退火算法的车间调度优化matlab仿真,输出甘特图和优化收敛曲线
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于SA模拟退火算法的车间调度优化matlab仿真,输出甘特图和优化收敛曲线。输出指标包括最小平均流动时间,最大完工时间,最小间隙时间。 2…...
【仿Mudou库one thread per loop式并发服务器实现】SERVER服务器模块实现
SERVER服务器模块实现 1. Buffer模块2. Socket模块3. Channel模块4. Poller模块5. EventLoop模块5.1 TimerQueue模块5.2 TimeWheel整合到EventLoop5.1 EventLoop与线程结合5.2 EventLoop线程池 6. Connection模块7. Acceptor模块8. TcpServer模块 1. Buffer模块 Buffer模块&…...
基于Redis实现高并发抢券系统的数据同步方案详解
在高并发抢券系统中,我们通常会将用户的抢券结果优先写入 Redis,以保证系统响应速度和并发处理能力。但数据的最终一致性要求我们必须将这些结果最终同步到 MySQL 的持久化库中。本文将详细介绍一种基于线程池 Redis Hash 扫描的异步数据同步方案&#…...
SPL 量化 序言
序言 量化交易是通过数学模型、统计学方法和计算机技术,将市场行为转化为可执行的交易策略的自动化投资方式。其核心是通过大数据分析、机器学习和金融工程等技术,从历史数据中挖掘市场规律,预测价格趋势并生成交易信号。 量化交易的实现通…...
【LLM Prompt】CoT vs.ToT
CoT(Chain of Thought) Definition: CoT refers to the method of prompting a language model to generate responses in a step-by-step manner, explicitly showing the reasoning process leading to the final answer.定义: CoT 是一种提示语言模型…...
uniapp h5接入地图选点组件
uniapp h5接入地图选点组件 1、申请腾讯地图key2、代码接入2.1入口页面 (pages/map/map)templatescript 2.2选点页面(pages/map/mapselect/mapselect)templatescript 该内容只针对uniapp 打包h5接入地图选点组件做详细说明&#x…...
【Rust 精进之路之第13篇-生命周期·进阶】省略规则与静态生命周期 (`‘static`)
系列: Rust 精进之路:构建可靠、高效软件的底层逻辑 作者: 码觉客 发布日期: 2025年4月20日 引言:让编译器“读懂”你的意图——省略的艺术 在上一篇【生命周期入门】中,我们理解了生命周期的必要性——它是 Rust 编译器用来确保引用有效性、防止悬垂引用的关键机制。我…...
OSI模型和传输过程
OSI模型概述 OSI(Open Systems Interconnection)模型是由国际标准化组织(ISO)提出的一个概念性框架,用于标准化网络通信功能。它将网络通信分为七层,每一层负责特定的功能,并通过接口与相邻层交…...
MySQL-CASE WHEN条件语句
介绍 MySQL 中的一种流程控制语法结构,用于在 SQL 查询中实现条件逻辑。它允许你根据一个或多个条件的真假来返回不同的值。可以根据某些条件对数据进行分类或者转换。 使用方式 简单 CASE 表达式 CASE input_expressionWHEN when_expression THEN result_expre…...
【随缘更新,免积分下载】Selenium chromedriver驱动下载(最新版135.0.7049.42)
目录 一、chromedriver概述 二、chromedriver使用方式 三、chromedriver新版本下载🔥🔥🔥 四、Selenium与Chrome参数设置🔥🔥 五、Selenium直接操控已打开的Chrome浏览器🔥🔥🔥…...
jenkins批量复制Job项目的shell脚本实现
背景 现在需要将“测试” 目录中的所有job全部复制到 一个新目录中 test2。可以结合jenkins提供的apilinux shell 进行实现。 测试目录的实际文件夹名称是 test。 脚本运行效果如下: [qdevsom5f-dev-hhyl shekk]$ ./copy_jenkins_job.sh 创建文件夹 test2 获取源…...
iOS Google登录
iOS Google登录 SDK下载地址在 Firebase 有下载,要下载整个SDK文件,然后拿其中的Google 登录SDK来使用 Firebase 官方文档 github 下载链接...
嵌入式工程师( C / C++ )笔试面试题汇总
注:本文为 “嵌入式工程师笔试面试题” 相关文章合辑。 未整理去重。 如有内容异常,请看原文。 嵌入式必会 C 语言笔试题汇总 Z 沉浮 嵌入式之旅 2021 年 01 月 19 日 00:00 用预处理指令 #define 声明一个常数,用以表明 1 年中有多少秒&a…...
重构便携钢琴专业边界丨特伦斯便携钢琴V30Pro定义新一代便携电钢琴
在便携电钢琴领域,特伦斯推出的V30Pro折叠钢琴以"技术革新场景适配"的双重升级引发关注。这款产品不仅延续了品牌标志性的折叠结构,更通过声学系统重构与智能交互优化,重新定义了便携乐器的专业边界。 ▶ 核心特点:技术…...
DiffuRec: A Diffusion Model for Sequential Recommendation
DiffuRec: A Diffusion Model for Sequential Recommendation Background 序列推荐(Sequential Recommendation, SR)领域,主流方法是将用户与物品表示为fixed embedding。然而,这种静态向量表达方式难以全面刻画用户多样化的兴趣…...
多模态大语言模型arxiv论文略读(三十三)
Jailbreaking Attack against Multimodal Large Language Model ➡️ 论文标题:Jailbreaking Attack against Multimodal Large Language Model ➡️ 论文作者:Zhenxing Niu, Haodong Ren, Xinbo Gao, Gang Hua, Rong Jin ➡️ 研究机构: Xidian Univer…...
IntelliJ IDEA download JDK
IntelliJ IDEA download JDK 自动下载各个版本JDK,步骤 File - Project Structure (快捷键 Ctrl Shift Alt S) 如果下载失败,换个下载站点吧。一般选择Oracle版本,因为java被Oracle收购了 好了。 花里胡哨&#…...
计算机网络——常见的网络攻击手段
什么是XSS攻击,如何避免? XSS 攻击,全称跨站脚本攻击(Cross-Site Scripting),这会与层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,因此有人将跨站脚本攻击缩写为XSS。它指的是恶意攻击者往Web页面…...
Android动态化技术优化
Android动态化技术优化 一、WebView优化基础 1.1 WebView性能瓶颈 初始化耗时内存占用高页面加载慢白屏问题1.2 WebView基本配置 class OptimizedWebView : WebView {init {// 开启硬件加速setLayerType(LAYER_TYPE_HARDWARE, null...
面向对象设计中的类的分类:实体类、控制类和边界类
目录 前言1. 实体类(Entity Class)1.1 定义和作用1.2 实体类的特点1.3 实体类的示例 2. 控制类(Control Class)2.1 定义和作用2.2 控制类的特点2.3 控制类的示例 3. 边界类(Boundary Class)3.1 定义和作用3…...
鸿蒙ArkUI实战之TextArea组件、RichEditor组件、RichText组件、Search组件的使用
本文接上篇继续更新ArkUI中组件的使用,本文介绍的组件有TextArea组件、RichEditor组件、RichText组件、Search组件,这几个组件的使用对应特定场景,使用时更加需要注意根据需求去使用 TextArea组件 官方文档: TextArea-文本与输…...
初创企业机器学习训练:云服务器配置对效率、成本与可扩展性的影响
在当今的初创企业中,机器学习模型训练已成为驱动创新和智能产品的核心环节。然而,深度学习模型的训练通常需要大量的计算资源,如何高效利用云服务器的基础配置成为初创团队关注的重点。云服务器的基础配置通常包括 vCPU(虚拟CPU&a…...
【“星瑞” O6 评测】—NPU 部署 face parser 模型
前言 瑞莎星睿 O6 (Radxa Orion O6) 拥有高达 28.8TOPs NPU (Neural Processing Unit) 算力,支持 INT4 / INT8 / INT16 / FP16 / BF16 和 TF32 类型的加速。这里通过通过官方的工具链进行FaceParsingBiSeNet的部署 1. FaceParsingBiSeNet onnx 推理 首先从百度网盘…...
56、如何快速让⼀个盒⼦⽔平垂直居中
在网页开发中,有多种方式能让一个盒子实现水平垂直居中。下面为你介绍几种常见且快速的方法。 1. 使用 Flexbox 布局 Flexbox 是一种非常便捷的布局模型,能够轻松实现元素的水平和垂直居中。 html <!DOCTYPE html> <html lang"en"&…...
互联网大厂Java面试:Spring Cloud与微服务的奇妙之旅
互联网大厂Java面试:Spring Cloud与微服务的奇妙之旅 在一家知名的互联网公司,一位严肃且专业的面试官正准备对求职者进行技术考察。而这次的应聘者,是自称拥有丰富经验但实际上却是个搞笑的水货程序员——马飞机。接下来,我们将…...
BDO分厂积极开展“五个一”安全活动
BDO分厂为规范化学习“五个一”活动主题,按照“上下联动、分头准备 、差异管理、资源共享”的原则,全面激活班组安全活动管理新模式,正在积极开展班组安全活动,以单元班组形式对每个班组每周组织一次“五个一”安全活动。 丁二醇单…...
