gVisor 与 Containerd 高级配置指南Shim 选项、调试日志、NVIDIA 运行时与共享卷 inotify【免费下载链接】gvisorApplication Kernel for Containers项目地址: https://gitcode.com/GitHub_Trending/gv/gvisor本文是 gVisorApplication Kernel for Containers在 containerd 环境下的进阶配置手册面向已经完成 Containerd Quick Start 基础接入、希望通过containerd-shim-runsc-v1深度定制 runsc 行为的开发者。读完本文你将掌握 shim 配置文件runsc.toml的完整选项、containerd 侧ConfigPath的传递机制、shim 与 gVisor 双层调试日志的开启方法、NVIDIA Container Runtime 的兼容改造以及多容器共享卷场景下 inotify 事件跨容器传递的注解配置。一、Shim 配置文件runsc.tomlcontainerd-shim-runsc-v1是 containerd 与 gVisor 之间的桥梁containerd 通过 CRI 调用该 shimshim 再以正确的参数调用 runsc 二进制run、boot、create等子命令。为了让 shim 与 runsc 的行为可控gVisor 为 shim 提供了一套独立的 TOML 配置文件默认路径为/etc/containerd/runsc.toml。cat EOF | sudo tee /etc/containerd/runsc.toml option value [runsc_config] flag value EOF配置文件由两层构成顶层选项作用于 shim 自身日志路径、日志级别、runsc 二进制路径、cgroup 等[runsc_config]段一个 key/value 映射用于向 runsc 透传任意命令行标志。flag value会被转换为--flagvalue追加到 runsc 的命令行参数中底层实现在 pkg/shim/v1/runsccmd/runsc.go#L716-L718 的args()函数里可以看到这一转换逻辑for k, v : range r.Config { args append(args, fmt.Sprintf(--%s%s, k, v)) }可用runsc flags命令查看 runsc 支持的全部标志。1.1 全部可用选项shim 支持的选项定义在 pkg/shim/v1/runsc/options.go#L57-L92 的Options结构体中TOML 键名与含义如下TOML 键类型说明shim_cgroupstringshim 自身应放置的 cgroupio_uiduint32I/O 管道文件的所有者 UIDio_giduint32I/O 管道文件的所属 GIDbinary_namestringrunsc 可执行文件的名称或路径rootstringrunsc 的 root 目录对应--root标志log_levelstringshim 日志级别debug、info、warning等仅在 shim 以服务方式运行时生效log_pathstringshim 日志目录路径中的%ID%会被替换为容器 IDgroupingbool是否启用 shim 分组多个容器共享一个 shimenable_hibernate_serverbool是否启动 hibernate serverrunsc_configmap[string]string透传给 runsc 的任意标志键值对1.2 shim 配置文件的查找机制从源码看shim 会按固定顺序探测配置文件pkg/shim/v1/runsc/options.go#L29-L46shimConfigPaths : []string{ /run/containerd/runsc/config.toml, /etc/containerd/runsc/config.toml, config.toml, }即依次尝试/run/containerd/runsc/config.toml、/etc/containerd/runsc/config.toml以及当前目录下的config.toml找到第一个存在的文件即解析若都找不到则返回空配置所有选项为默认值。仓库中 shim/runsc.toml 是一份带注释的示例文件可作为编写自定义配置的起点。二、让 containerd 把配置传给 shim仅仅写好/etc/containerd/runsc.toml还不够containerd 必须知道要去读取它。从 containerd 1.3 起CRI 插件支持在 runtime 配置中指定ConfigPath将 shim 配置文件路径随 runtime 一并下发。2.1 Containerd 1.3 的完整配置在/etc/containerd/config.toml中注册一个名为runsc的 runtimecat EOF | sudo tee /etc/containerd/config.toml version 2 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] runtime_type io.containerd.runc.v2 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runsc] runtime_type io.containerd.runsc.v1 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runsc.options] TypeUrl io.containerd.runsc.v1.options ConfigPath /etc/containerd/runsc.toml EOF关键点runtime_type io.containerd.runsc.v1告诉 containerd 调用containerd-shim-runsc-v1options.TypeUrl必须为io.containerd.runsc.v1.options这是 shim 识别运行时选项的消息类型常量定义见 pkg/shim/v1/runsc/options.go#L24options.ConfigPath指向第一节中的 shim 配置文件。修改完成后重启 containerd 使配置生效sudo systemctl restart containerd若使用 containerd 2.x可将配置文件头部改为version 3与基础接入文档中的建议一致。三、调试shim 与 gVisor 的双层日志调试 gVisor 沙箱时通常需要两层日志shim 自身的日志与 runsc内核态的调试日志。二者可以独立开启。3.1 通过 containerd 收集 shim 日志在/etc/containerd/config.toml中开启shim_debug后containerd 会把 shim 的输出转发到自己的日志中再配合[debug] level debug提升 containerd 全局日志级别即可通过sudo journalctl -u containerd查看cat EOF | sudo tee /etc/containerd/config.toml version 2 [debug] level debug [plugins.io.containerd.runtime.v1.linux] shim_debug true [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runc] runtime_type io.containerd.runc.v2 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runsc] runtime_type io.containerd.runsc.v1 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.runsc.options] TypeUrl io.containerd.runsc.v1.options ConfigPath /etc/containerd/runsc.toml EOF这种方式的缺点是 containerd 与 shim 的消息混在一起难以区分。3.2 独立的 shim 日志文件更干净的做法是在 shim 配置文件/etc/containerd/runsc.toml中设置log_path与log_levellog_pathshim 日志文件所在目录路径中的%ID%会被替换为容器 ID如果路径以/结尾则自动使用默认文件名runsc-shim-ID.log见 pkg/shim/v1/runsccmd/utils.go#L40-L49 的FormatShimLogPath实现log_levelshim 日志级别通常设为debug因为其他级别下 shim 几乎没有值得关注的输出。3.3 示例同时开启 shim 与 gVisor 调试日志gVisor 侧的调试日志由 runsc 的debug与debug-log标志控制。shim 会以%ID%替换容器 ID、以%COMMAND%替换 runsc 子命令名run、boot等填充到debug-log路径中cat EOF | sudo tee /etc/containerd/runsc.toml log_path /var/log/runsc/%ID%/shim.log log_level debug [runsc_config] debug true debug-log /var/log/runsc/%ID%/gvisor.%COMMAND%.log EOFdebug true经 pkg/shim/v1/runsccmd/runsc.go#L719-L721 转换为--debug参数debug-log经同文件 L722-L724 转换为--debug-logpath参数。更详细的调试手段如 syscall 跟踪、strace、profile 等参见 调试指南。四、与 NVIDIA Container Runtime 集成如果你希望借助nvidia-container-runtime在 gVisor 沙箱中使用 GPU需要让 containerd 中的nvidiaruntime 走 runsc shim。通常先用 NVIDIA 工具生成配置sudo nvidia-ctk runtime configure --runtimecontainerd该命令会在/etc/containerd/config.toml中新增一个名为nvidia的 runtime但它的默认配置与 runsc 并不兼容需要手工调整两点runtime_type默认指向 runcio.containerd.runc.v2必须改为io.containerd.runsc.v1containerd 才会调用containerd-shim-runsc-v1options默认试图设置BinaryName /usr/bin/nvidia-container-runtime而 runsc shim 是通过ConfigPath读取配置的因此需把options改为指定ConfigPath并把BinaryName移到 shim 配置文件runsc.toml中。改造后的/etc/containerd/config.toml应形如... [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.nvidia] runtime_type io.containerd.runsc.v1 [plugins.io.containerd.grpc.v1.cri.containerd.runtimes.nvidia.options] TypeUrl io.containerd.runsc.v1.options ConfigPath /etc/containerd/runsc.toml ...而/etc/containerd/runsc.toml需要包含binary_name与 GPU 透传标志log_path /var/log/runsc/%ID%/shim.log log_level debug binary_name /usr/bin/nvidia-container-runtime [runsc_config] debug true debug-log /var/log/runsc/%ID%/gvisor.%COMMAND%.log nvproxy true其中binary_name对应Options.BinaryName字段见 pkg/shim/v1/runsc/options.go#L68指定 shim 实际调用的 runsc 可执行文件nvproxy是 gVisor 的 NVIDIA GPU 代理标志用于把 GPU 设备访问转发给宿主机驱动。关于如何配置nvidia-container-runtime将 runsc 作为底层运行时参见 GPU 使用指南 的对应小节。五、为共享卷开启跨容器 inotify多容器共享同一卷时gVisor 默认把各容器的卷独立挂载整个 Pod 内部没有一个统一的卷视图因此一个容器对共享卷的修改对其他容器而言表现为外部更新按需访问时可能检测到但inotify 无法正确捕获这类跨容器变更除非提供额外的挂载提示mount hints元数据。GKE 的控制平面通常会自动注入这些提示但在 EKS 等其他 Kubernetes 发行版上必须手工配置。下面给出完整步骤。5.1 允许 Pod 注解透传给 gVisor首先在/etc/containerd/config.toml中配置 containerd把自定义的 gVisor 注解透传给 runsc[plugins.io.containerd.grpc.v1.cri.containerd.runtimes.gvisor] runtime_type io.containerd.runsc.v1 pod_annotations [ dev.gvisor.* ]5.2 添加 gVisor 卷挂载注解挂载提示以注解形式告诉 gVisor 如何处理每个卷注解键的通用格式为dev.gvisor.spec.mount.NAME.*其中NAME是卷名称。可用注解如下注解取值说明dev.gvisor.spec.mount.NAME.sharecontainer/pod/sharedcontainer卷仅被单个容器使用pod卷被 Pod 内多个容器共享shared卷与 Pod 外部共享需要频繁检查外部变更dev.gvisor.spec.mount.NAME.typetmpfs/bindtmpfs卷在沙箱内使用tmpfs对emptyDir卷可带来更好性能bind宿主机 bind 挂载dev.gvisor.spec.mount.NAME.options逗号分隔的挂载选项例如rw,rprivatedev.gvisor.spec.mount.NAME.directfsdefault/offdefault或不设置跟随全局--directfs设置off对该挂载禁用directfs适用于无法捐赠宿主机文件描述符的自定义 gofer 服务如虚拟或网络后端文件系统其余挂载仍可继续使用 directfsdev.gvisor.empty-dir.NAME.force-sharedtrue/false默认默认 gVisor 会把emptyDir优化为沙箱内部的tmpfs挂载设为true可让该emptyDir退出优化改为宿主机上的普通共享 bind 挂载适合需要与沙箱外进程如通过 UDS 通信的 CSI 驱动共享的emptyDir。该注解仅对emptyDir生效5.3 完整示例共享 emptyDir 的 Pod以下 Pod 定义了一个名为shared-folder的共享emptyDir通过注解开启跨容器 inotifyapiVersion: v1 kind: Pod metadata: name: shared-folder-test annotations: dev.gvisor.spec.mount.shared-folder.share: pod dev.gvisor.spec.mount.shared-folder.type: tmpfs dev.gvisor.spec.mount.shared-folder.options: rw,rprivate spec: runtimeClassName: gvisor containers: - name: container1 image: node:14 command: [node, watcher.js] volumeMounts: - name: shared-folder mountPath: /shared - name: container2 image: busybox command: [/bin/sh, -c, while true; do echo hello /shared/test.txt; sleep 2; done] volumeMounts: - name: shared-folder mountPath: /shared volumes: - name: shared-folder emptyDir: {}5.4 注解含义详解dev.gvisor.spec.mount.NAME.share pod声明该卷被同一沙箱内的多个容器共享。这会建立快速访问路径并允许 inotify 事件在容器之间传播。dev.gvisor.spec.mount.NAME.type tmpfsemptyDir卷通常建议设为tmpfs以获得沙箱内更高的读写性能。虽然被称为tmpfs但在配置允许时仍可由磁盘背书。dev.gvisor.spec.mount.NAME.options rw,rprivate共享读写卷的典型挂载选项。注解就位后只要 Pod 以gvisorruntime 调度inotify 即可正确检测到共享卷上的跨容器文件变更。5.5 故障排查如果 inotify 仍未生效按以下顺序核查containerd 配置中的pod_annotations片段是否就位是否允许dev.gvisor.*透传Pod 注解中的卷名如shared-folder是否与volumes中定义的卷名完全一致检查 gVisor 的调试日志中是否有相关警告或错误日志开启方法见本文第三节。完成上述配置后在 EKS或其他发行版上使用 gVisor 的多容器 Pod其共享卷行为应与 GKE 一致——即支持基于 inotify 的跨容器文件变更检测。【免费下载链接】gvisorApplication Kernel for Containers项目地址: https://gitcode.com/GitHub_Trending/gv/gvisor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考