ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RancherOS 中的 libcontainer 容器规范解读:SPEC v1 的命名空间、cgroups、文件系统与安全模型全解析

RancherOS 中的 libcontainer 容器规范解读:SPEC v1 的命名空间、cgroups、文件系统与安全模型全解析 操作系统云原生容器运行时【免费下载链接】osTiny Linux distro that runs the entire OS as Docker containers项目地址https://gitcode.com/gh_mirrors/os/os点击查看免费下载导读本文以当前仓库中随 RancherOS 一起 vendored 的 libcontainer SPEC v1 规范 为主线系统讲解 v1 容器的标准配置命名空间、标准文件系统布局、默认 Linux capabilities、cgroup 资源预留以及容器创建后可执行的管理与检视动作。读完本文你将理解一个符合 v1 规范的容器从内核隔离到资源控制、从安全加固到进程管理的完整技术骨架并能对照 RancherOS 源码如 pkg/init/switchroot/switchroot.go、pkg/init/env/env.go与 libcontainer README 中的 Go API 示例掌握在实际项目中构造与运维这类容器所需的核心知识。libcontainer 提供了创建容器的原生 Go 实现——涉及命名空间、cgroups、capabilities 和文件系统访问控制并允许在容器创建后执行生命周期管理操作。v1 配置档案profile的设计目标是在强安全配置下承载绝大多数应用程序。一、v1 规范概述Container Specification v1 是一份标准的容器配置规范涵盖以下核心维度命名空间Namespaces进程级隔离标准文件系统Filesystemrootfs 布局与必需挂载默认 Linux capability 集合安全与灵活性的平衡资源预留Resource reservations通过 cgroups 实现的 CPU、内存、设备访问控制进程运行环境Environment容器内进程被注入的环境设置。除了描述容器如何创建该规范还定义了容器创建后可用于管理和检视容器内进程的标准动作集Actions。规范原文位于 vendor/github.com/opencontainers/runc/libcontainer/SPEC.md属于 opencontainers/runc 项目中 libcontainer 子库的官方文档被 RancherOS 项目以 vendor 方式引入与项目的核心架构“整个 OS 以 Docker 容器方式运行”直接相关。二、系统要求与兼容性System Requirements and Compatibility运行 v1 规范容器的最低系统要求如下内核版本推荐 3.10最低 2.6.2x需携带反向移植补丁 backported patchescgroups 挂载每个子系统subsystem必须挂载在**独立的层级hierarchy**中。这一要求意味着宿主机内核必须提供完整的命名空间与 cgroup 支持是运行本规范所描述容器类型的先决条件。三、命名空间Namespacesv1 容器默认启用以下六个命名空间均通过clone系统调用创建FlagEnabledCLONE_NEWPID1CLONE_NEWUTS1CLONE_NEWIPC1CLONE_NEWNET1CLONE_NEWNS1CLONE_NEWUSER1CLONE_NEWPIDPID 命名空间容器内进程拥有独立的 PID 视图PID 1 为容器 initCLONE_NEWUTSUTS 命名空间隔离主机名与域名/etc/hostname相关CLONE_NEWIPCIPC 命名空间隔离 System V IPC 与 POSIX 消息队列CLONE_NEWNET网络命名空间隔离网络栈、接口、路由与防火墙规则CLONE_NEWNS挂载命名空间隔离挂载点视图CLONE_NEWUSER用户命名空间配合 uid/gid 映射实现非特权容器。在 libcontainer README 的 Go 配置示例中这六个命名空间对应configs.Namespaces数组Namespaces: configs.Namespaces([]configs.Namespace{ {Type: configs.NEWNS}, {Type: configs.NEWUTS}, {Type: configs.NEWIPC}, {Type: configs.NEWPID}, {Type: configs.NEWUSER}, {Type: configs.NEWNET}, }),与 RancherOS 的联系RancherOS 的系统服务system service通过net: host、pid: host、uts: host、ipc: host等配置选择共享宿主机的某些命名空间可见于 os-config.tpl.yml 中的console、network、docker等服务定义。这正是 v1 规范“命名空间可裁剪”特性在真实操作系统场景中的典型运用系统级服务需要宿主机网络与 PID 视图而用户容器则获得完整隔离。四、文件系统Filesystem4.1 rootfs 与隔离容器必须被提供一个根文件系统rootfs用于“关押”jail并派生容器内进程容器依赖的二进制与系统库都位于该目录内。任何要执行的二进制都必须位于 rootfs 之内。一个重要的自动清理机制容器内发生的挂载mount在容器退出时会自动被清理——因为挂载命名空间被销毁时内核会卸载该命名空间内建立的所有挂载。4.2 运行时必需的挂载为了让容器正确执行运行时必须在 rootfs 内挂载以下文件系统PathTypeFlagsData/procprocMS_NOEXEC, MS_NOSUID, MS_NODEV/devtmpfsMS_NOEXEC, MS_STRICTATIMEmode755/dev/shmtmpfsMS_NOEXEC, MS_NOSUID, MS_NODEVmode1777, size65536k/dev/mqueuemqueueMS_NOEXEC, MS_NOSUID, MS_NODEV/dev/ptsdevptsMS_NOEXEC, MS_NOSUIDnewinstance, ptmxmode0666, mode620, gid5/syssysfsMS_NOEXEC, MS_NOSUID, MS_NODEV, MS_RDONLY各挂载标志含义MS_NOEXEC禁止在该文件系统上执行二进制MS_NOSUID忽略该文件系统上二进制文件的 setuid/setgid 位MS_NODEV禁止在该文件系统上访问设备节点MS_RDONLY只读挂载MS_STRICTATIME始终更新 atimestrict atime。上述配置在 libcontainer README 中对应configs.Mount数组defaultMountFlags : syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV与规范表格逐一对应如/dev使用MS_NOSUID | MS_STRICTATIME且Data: mode755/dev/pts使用Data: newinstance,ptmxmode0666,mode0620,gid5。4.3 /dev 设备节点在新建挂载命名空间内挂载完文件系统后需要向/dev填充一组设备节点。规范明确rootfs 内不需要预先指定任何/dev设备节点容器运行时会按需创建执行进程所需的正确设备PathModeAccess/dev/null0666rwm/dev/zero0666rwm/dev/full0666rwm/dev/tty0666rwm/dev/random0666rwm/dev/urandom0666rwm/dev/fuse0666rwm4.4 ptmx 与伪终端PTY/dev/ptmx必须是容器内指向宿主机/dev/ptmx的符号链接伪 TTY 在容器内是可选的容器应同时支持有无 PTY 两种情形若为容器提供伪终端则/dev/console需要在/dev填充并挂载于 tmpfs 之后将控制台绑定bind进来SourceDestinationUID GIDModeType*pty host path*/dev/console0 00600bind4.5 标准 I/O 与符号链接设置好/dev/null后运行时需检查容器 I/OSTDIN、STDOUT、STDERR与外部/dev/null之间是否存在链接若容器的 I/O 指向容器外的/dev/null则关闭它并将容器 rootfs 内本地的/dev/null通过dup2复制到对应 fd。/proc挂载完成后需在/dev内为 I/O 建立标准符号链接SourceDestination/proc/self/fd/dev/fd/proc/self/fd/0/dev/stdin/proc/self/fd/1/dev/stdout/proc/self/fd/2/dev/stderr4.6 pivot_root 与 ramfs 特殊情况pivot_root被用于改变进程的根从而将进程有效地“关押”在 rootfs 内put_old mkdir(...); pivot_root(rootfs, put_old); chdir(/); unmount(put_old, MS_DETACH); rmdir(put_old);关键限制若容器的 rootfs 位于ramfs中则pivot_root不被支持必须改用MS_MOVE加chroot的组合mount(rootfs, /, NULL, MS_MOVE, NULL); chroot(.); chdir(/);这一“ramfs 备选方案”在 RancherOS 中有真实的对应实现当从内存文件系统initrd启动时pkg/init/env/env.go 会设置DOCKER_RAMDISKtrue注释明确写道 “Magic setting to tell Docker to do switch_root and not pivot_root”而 pkg/init/switchroot/switchroot.go 在切换根时执行的正是syscall.Mount(rootfs, /, , syscall.MS_MOVE, )→syscall.Chroot(.)→syscall.Chdir(/)这一与规范完全一致的序列并在成功后os.Unsetenv(DOCKER_RAMDISK)。这说明规范中的“备选路径”不是纸面设计而是被实际操作系统引导流程采用的成熟方案。文件系统设置完成后umask被恢复为0022。五、资源Resourcescgroups 子系统cgroups 负责容器的资源分配涵盖系统资源如 CPU、内存与设备访问。v1 规范启用的子系统如下SubsystemEnableddevices1memory1cpu1cpuacct1cpuset1blkio1perf_event1freezer1hugetlb1pids1所有 cgroup 子系统都被加入joined以便从每个子系统收集统计信息。其中freezer不暴露任何统计信息但它被加入的原因是为了支持容器的**暂停pause与恢复resume**操作。时序上的关键保证容器 init 的父进程必须在初始化开始前将 init PID 放入正确的 cgroups——这样任何进程或线程都无法逃逸出 cgroups。这一同步通过一条管道pipe完成详见下文“运行时与 init 进程”小节容器 init 进程会阻塞等待父进程完成 cgroup 设置。六、安全Security6.1 默认 Linux Capabilities容器内设置的标准 Linux capabilities 集合为应用程序提供了兼顾安全与灵活性的良好默认值。默认启用的 capabilitiesCapabilityEnabledCAP_NET_RAW1CAP_NET_BIND_SERVICE1CAP_AUDIT_READ1CAP_AUDIT_WRITE1CAP_DAC_OVERRIDE1CAP_SETFCAP1CAP_SETPCAP1CAP_SETGID1CAP_SETUID1CAP_MKNOD1CAP_CHOWN1CAP_FOWNER1CAP_FSETID1CAP_KILL1CAP_SYS_CHROOT1默认禁用的 capabilities共 22 项CapabilityEnabledCAP_NET_BROADCAST0CAP_SYS_MODULE0CAP_SYS_RAWIO0CAP_SYS_PACCT0CAP_SYS_ADMIN0CAP_SYS_NICE0CAP_SYS_RESOURCE0CAP_SYS_TIME0CAP_SYS_TTY_CONFIG0CAP_AUDIT_CONTROL0CAP_MAC_OVERRIDE0CAP_MAC_ADMIN0CAP_NET_ADMIN0CAP_SYSLOG0CAP_DAC_READ_SEARCH0CAP_LINUX_IMMUTABLE0CAP_IPC_LOCK0CAP_IPC_OWNER0CAP_SYS_PTRACE0CAP_SYS_BOOT0CAP_LEASE0CAP_WAKE_ALARM0CAP_BLOCK_SUSPEND0安全要点解读保留的是网络收发、文件属主、进程信号、chroot 等常规应用必需的能力禁用项集中在**内核模块加载CAP_SYS_MODULE、直接 I/OCAP_SYS_RAWIO、系统管理CAP_SYS_ADMIN、ptraceCAP_SYS_PTRACE、时间与时钟修改、网络管理CAP_NET_ADMIN**等高风险面这正是“v1 档案以强安全配置承载大多数应用”的关键所在在 libcontainer README 的 Go 示例中Capabilities: []string{...}清单与本规范表格完全一致14 项启用项。6.2 AppArmor 与 SELinux容器还可叠加AppArmor与SELinux两层额外的安全机制。配置中若提供了 apparmor profile 或 selinux 进程/挂载标签process and mount labels容器应予以支持。规范给出的标准 AppArmor profile#include tunables/global profile profile_name flags(attach_disconnected,mediate_deleted) { #include abstractions/base network, capability, file, umount, deny {PROC}/sys/fs/** wklx, deny {PROC}/sysrq-trigger rwklx, deny {PROC}/mem rwklx, deny {PROC}/kmem rwklx, deny {PROC}/sys/kernel/[^s][^h][^m]* wklx, deny {PROC}/sys/kernel/*/** wklx, deny mount, deny /sys/[^f]*/** wklx, deny /sys/f[^s]*/** wklx, deny /sys/fs/[^c]*/** wklx, deny /sys/fs/c[^g]*/** wklx, deny /sys/fs/cg[^r]*/** wklx, deny /sys/firmware/efi/efivars/** rwklx, deny /sys/kernel/security/** rwklx, }该 profile 的策略要点默认放行网络、capability、文件与 umount但严格拒绝对/proc内核参数与内存/proc/mem、/proc/kmem、/sys下除 cgroup 之外的控制文件含 EFI 变量、内核安全接口的读写访问并拒绝mount——这层“默认拒绝”为容器提供了纵深防御。RancherOS 在 SELinux 侧的实际配置可见 assets/selinux/configSELINUXpermissive、SELINUXTYPEros以及 cmd/control/selinux.go 与 pkg/selinux/selinux_linux.go 中的相关实现配合 pkg/init/selinux/selinux.go 在启动阶段的加载体现了规范“SELinux 可作为附加安全层”的设计在真实发行版中的落地。规范同时标注了一项 TODOseccomp 的默认配置仍在研究中“seccomp work is being done to find a good default config”即 v1 规范当时尚未给出默认 seccomp 过滤器。七、运行时与 Init 进程Runtime and Init Process7.1 管道同步机制容器创建期间父进程需要与容器 init 进程通信并完成同步。实现方式是创建一条传递给容器 init 的管道init 进程首次派生spawn时会阻塞在管道自己的那一端直到父进程关闭其管道端init 才继续运行这为父进程留出时间把新进程放入 cgroup 层级以及/或者写入用户命名空间所需的 uid/gid 映射管道通过 FD 3 传递给 init 进程。这一机制正是前文“没有任何进程或线程能逃逸 cgroups”的时序保证。7.2 静态编译与无长驻 init消费 libcontainer 的应用程序应静态编译libcontainer不定义任何 init 进程传入的参数直接用于在应用内部exec目标进程容器规范中不应存在长期运行的 init“There should be no long running init within the container spec”。与之对应的启动模式来自 libcontainer README容器以两步过程派生调用方可复用当前二进制/proc/self/exe作为容器 init并以init参数进入“bootstrap”入口例如func init() { if len(os.Args) 1 os.Args[1] init { runtime.GOMAXPROCS(1) runtime.LockOSThread() factory, _ : libcontainer.New() if err : factory.StartInitialization(); err ! nil { logrus.Fatal(err) } panic(--this line should have never been executed, congratulations--) } }随后通过libcontainer.New(...)创建工厂、factory.Create(...)创建容器、container.Start(process)启动初始进程。7.3 伪终端与控制台若为容器提供伪终端pseudo tty运行时将打开控制台并dup2作为容器的 STDIN、STDOUT、STDERR同时把控制台挂载为/dev/console。7.4 额外运行时文件容器会获得一组额外的挂载/文件用于处理 rootfs 中“不可移植”的文件——这些文件通常由运行时创建并填充容器特定信息以避免对宿主产生副作用/etc/hosts/etc/resolv.conf/etc/hostname/etc/localtime这一设计在 RancherOS 的 os-config.tpl.yml 中同样可见system-volumes服务将/etc/hosts、/etc/resolv.conf等以卷方式注入系统容器保证容器内网络与主机名信息的正确性。7.5 默认值Defaults以下默认值可由用户覆盖但省略时对容器内进程生效TypeValueParent Death SignalSIGKILLUID0GID0GROUPS0, NULLCWD/$HOME当前用户的 home 目录或 /Readonly rootfsfalsePseudo TTYfalseParent Death Signal SIGKILL父进程死亡时内核以 SIGKILL 终止容器进程防止孤儿进程游离UID/GID 0容器内默认以 root 运行再通过 capabilities 收敛权限Readonly rootfs false默认 rootfs 可写Pseudo TTY false默认不分配伪终端。八、容器动作Actions标准管理 API容器创建完成后存在一组标准动作作为容器的公共 APIActionDescriptionGet processes返回容器内所有运行进程的 PIDGet Stats返回容器整体的资源统计Wait等待容器的 init 进程PID 1Wait Process等待容器内任一进程返回其退出状态Destroy杀死容器 init 进程并移除所有文件系统状态Signal向容器 init 进程发送信号Signal Process向容器内任一进程发送信号Pause暂停容器内所有进程Resume恢复所有被暂停的容器进程Exec在容器内执行新进程需要 setnsSet容器创建后设置其配置在 libcontainer README 中这些动作对应的 Go 调用为// 返回容器内所有进程的 pids processes, err : container.Processes() // 获取容器及其进程的详细 cpu、memory、io、network 统计 stats, err : container.Stats() // 暂停容器内所有进程 container.Pause() // 恢复所有被暂停的进程 container.Resume() // 向容器 init 进程发送信号 container.Signal(signal)九、在运行中的容器内执行新进程Exec用户可以在运行中的容器内执行新进程其语义要点如下二进制可达性任何要执行的二进制必须位于容器 rootfs 内与文件系统一节的原则一致持久性新进程在容器 rootfs 内运行其对容器文件系统所做的任何修改在进程结束后依然保留命名空间共享新进程将加入容器现有的全部命名空间暂停联动容器被暂停时新进程也随之暂停容器恢复时进程恢复生命周期约束新进程仅在容器主进程PID 1运行期间执行容器重启时它不会被自动重启。已规划的新增能力Planned additions规范同时预告了 Exec 的后续增强方向新进程将拥有嵌套在容器 cgroups 内部的独立 cgroups用于进程追踪与可选资源分配其中freezer cgroup 为必需其余 cgroups 可选进程执行器必须在启动进程前把 PID 放入正确的 cgroups确保任何子进程或线程都无法逃逸出 cgroups进程停止时执行器会以 best-effort 方式尝试停止其所有子进程并移除子 cgroups。结语通过 libcontainer SPEC v1我们可以看到一套完整、自洽的容器标准六个命名空间定义隔离边界rootfs 加六类必需挂载定义执行环境十个 cgroup 子系统定义资源边界15 项启用 / 22 项禁用的 capabilities 加 AppArmor、SELinux 定义安全边界管道同步 无长驻 init 定义进程模型十二种标准动作定义运维接口。而这些规范中的每一项都能在 RancherOS 的源码与配置中找到对应实现——从 pkg/init/switchroot/switchroot.go 的MS_MOVE chroot到 pkg/init/env/env.go 的DOCKER_RAMDISK再到 os-config.tpl.yml 中系统容器对命名空间的灵活取舍。对任何希望深入理解容器运行时内部机制、或基于 libcontainer 构建自有运行时的人来说这份 v1 规范都是最值得精读的第一手材料。赞分享操作系统云原生容器运行时【免费下载链接】osTiny Linux distro that runs the entire OS as Docker containers项目地址https://gitcode.com/gh_mirrors/os/os点击查看免费下载相关推荐Flynn 中的 libcontainer 容器规范 v1 全解析命名空间、cgroups、Intel RDT 与安全配置Flynn 中的 libcontainer 容器规范 v1 全解析命名空间、cgroups、Intel RDT 与安全配置 本文以开源仓库 Flynn一个基云原生微服务容器编排运维runc/libcontainer v1 容器规范深度解析命名空间、根文件系统、cgroups、Intel RDT 与安全管理runc/libcontainer v1 容器规范深度解析命名空间、根文件系统、cgroups、Intel RDT 与安全管理 本文围绕开源仓库 runcl云原生容器运行时CLIDocker 底层容器引擎解析libcontainer 的 Go 原生命名空间、cgroups 与生命周期管理实战Docker 底层容器引擎解析libcontainer 的 Go 原生命名空间、cgroups 与生命周期管理实战 导读 libcontainer 是 Doc开发者工具上一篇突破GPU性能瓶颈tiny-gpu Warp Scheduler设计全解析下一篇3倍加速ChatTTS-ui GPU性能优化实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表