您的位置:首页 > 教育 > 培训 > 网络营销pdf_代理公司是干什么的_网站seo优化_营销方式都有哪些

网络营销pdf_代理公司是干什么的_网站seo优化_营销方式都有哪些

2025/4/21 19:43:02 来源:https://blog.csdn.net/LONG_Yi_1994/article/details/147360012  浏览:    关键词:网络营销pdf_代理公司是干什么的_网站seo优化_营销方式都有哪些
网络营销pdf_代理公司是干什么的_网站seo优化_营销方式都有哪些

、当你使用 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

    • 类型:devtmpfstmpfs(部分设备节点由 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)
  • 说明:/procsys/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 调用容器运行时(通常为 containerdrunc)创建容器,涉及以下子步骤:

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):

  1. 解压镜像层:镜像由多层 tar 归档组成,Docker 将其解压到容器的工作目录(如 /var/lib/docker/overlay2/<container_id>)。

  2. 挂载 rootfs:使用 overlayfs(或其他存储驱动)将镜像层和容器可写层合并,形成统一的根文件系统。

  3. 挂载特殊文件系统

    • 挂载 /procprocfs)以提供进程信息。
    • 挂载 /syssysfs)以提供设备和内核信息。
    • 挂载 /devdevtmpfs),并填充基本设备节点(如 /dev/null/dev/zero)。
    • 若使用 -it,挂载 /dev/tty 或伪终端设备。

    这就是为何 /dev/proc/sys 出现在容器中的原因

  4. 应用挂载选项

    • 如果指定了 --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)启动容器:

  1. 执行入口点
    • 根据镜像的 CMDdocker run 指定的命令,运行主进程(如 /bin/hello)。
    • 如果指定了 -it,为主进程分配伪终端。
  2. 设置网络
    • 默认使用桥接网络(bridge),为容器分配 IP。
    • 如果指定了 --network,应用自定义网络(如 hostnone)。
  3. 处理信号
    • Docker 捕获容器主进程的退出状态,决定是否停止容器。
    • 如果指定了 --rm,容器退出后自动删除。

2.5 运行后处理

  • 日志收集:Docker 将容器的标准输出和错误输出记录到日志(查看:docker logs <container_id>)。
  • 状态更新:更新容器状态(如 runningexited),可通过 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:验证挂载来源

  1. 运行容器:
    docker run -it my-hello sh
    
  2. 检查挂载:
    mount | grep -E 'proc|sys|dev'
    
  3. 宿主机验证:
    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 内核:学习 procfssysfsdevtmpfs 的实现。
  • 安全强化:探索 AppArmorSELinuxseccomp 的配置。

7. 总结

容器中出现的 /dev/proc/sys 是 Docker 在启动时自动挂载的虚拟文件系统,用于支持进程管理、设备访问和内核交互。这些挂载由 Linux 内核提供,通过命名空间隔离,确保容器只访问自身相关的信息。docker run 的执行过程包括解析参数、拉取镜像、创建容器(设置命名空间、文件系统、cgroups、安全选项)以及启动主进程。通过理解这一过程,你可以优化容器配置、调试问题并增强安全性。建议在测试环境多实践,结合 docker inspectmount 命令深入探索挂载行为。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com