简介:cri-containerd-1.7.23 是面向云原生运维与 Kubernetes 集群部署人员的 containerd 容器运行时离线包,按 Linux AMD64 平台整理,解压到系统目录即可完成运行时环境的安装与 systemd 服务注册,省去逐个下载二进制文件和配置文件的麻烦。压缩包共 19 个文件、约 101.22MB,主体是 containerd、ctr、crictl、runc 及各版本 shim 等可执行程序,另含 yaml 配置、systemd service 与 template 单元、env 环境变量脚本和 version 版本标识,并用一份 txt 说明交代 cri-containerd 已弃用及相关迁移信息,基本覆盖安装部署、注册服务、验证运行时的完整链路,可帮助读者快速搭起本地 CRI 实验环境、对照排查运行时故障与版本兼容问题。目前已有 265 人学习下载,适合需要复现 Kubernetes 容器运行时环境或整理离线安装素材的读者参考使用。
1. 用 tar 包手动部署 cri-containerd 比想象中更容易出问题
离线机房里最容易被低估的一件事,是运行时版本。之前给一批机器装 Kubernetes,图省事用了发行版仓库里的 containerd,结果它比 kubelet 期望的落后两个小版本,CRI 接口对不上,Pod 建到一半就卡在 ContainerCreating,日志里只有一行语焉不详的 sandbox 报错。折腾到后半夜,换成 cri-containerd-1.7.23-linux-amd64.tar 手动解包、手工写配置,把版本固定住才通。这套装法适合三类人:机器不能连外网、需要多台机器跑完全一致的运行时、以及被“仓库里是什么版本就用什么版本”坑过一次的人。下面按我实际操作的顺序走一遍。
2. 版本与环境先钉死:cri-containerd 1.7.23 能装在哪类机器上
装 tar 包和 apt install 最大的区别在于:包管理器会替你处理依赖和版本约束,tar 包什么都不管。所以动手解包之前,得先确认这台机器的内核、cgroup 版本、runc 版本跟 1.7.23 是同一代的东西,否则二进制放进去也起不来。这一章的五条检查和两个依赖,是我每次装之前必过的清单,漏一条后面就要多花一小时看日志。
2.1 把 1.7.23 这个版本号拆开看
1.7.23 拆成三段看:主版本 1 表示这还是 containerd 的 1.x 体系,配置格式、插件路径、socket 位置都沿用老规矩;次版本 7 是 LTS 分支,长期维护,补丁只做修复不加新特性;补丁号 23 说明它已经在 1.7 这条线上滚了很久,前面积累的一堆小问题都修进去了。这个组合对运维来说是最舒服的——接口不会突然变,但坑已经被别人踩完了。
它跟 Kubernetes 的对应关系也有个大致范围。1.7 这条线放到 1.25 到 1.29 的集群里都比较省心,再新的集群就得留意 pause 镜像版本和 CRI 字段有没有变动。我的习惯是让 containerd 和 kubelet 处在同一个大版本节奏上,跨代搭配不是不能跑,但一旦出问题,排查时你永远会怀疑是不是版本不匹配,这个念头本身就够折磨人。
| 关注点 | 1.7.23 的表现 | 落地时怎么办 |
|---|---|---|
| 配置格式 | containerd config default 直接生成 version = 2 | 别手写 v1,字段名对不上会静默忽略 |
| CRI 插件 | 编译进主二进制,不需要额外装 cri 插件包 | 检查 disabled_plugins 里没有 "cri" |
| 仓库配置 | 支持 config_path + hosts.toml | 内网仓库走 /etc/containerd/certs.d |
| cgroup v2 | 依赖 runc 1.1 以上才能完整工作 | 别用发行版自带的 1.0.x |
| 快照器 | 默认 overlayfs | 根分区不是 overlay 能用的文件系统就换 native |
还有一点值得提前说清楚:这个包里到底有什么,别靠猜。不同来源的 cri-containerd 打包结构不一样,有的把二进制放在 bin/ 下,有的放在 usr/local/bin/ 下,还有的把 CNI 插件、runc、crictl 一起塞进去了。解包前先 tar -tf 看一眼,比解完发现路径全错要省事。
2.2 内核、cgroup 与模块:装之前先过一遍这五条命令
先确认内核支持 overlay 文件系统,这是容器镜像分层的基础,没有它 containerd 起来之后所有镜像都解不开。再确认 cgroup 是 v1 还是 v2,这两种模式在配置里的写法完全不同,装完再改要重启运行时。模块和内核参数属于“设了之后一直生效”的东西,一次性写好,后面换机器直接抄文件。
# 1. 内核版本,4.x 以上基本都行,5.x 更省心
uname -r
# 2. 确认 overlay 文件系统被内核支持
grep -w overlay /proc/filesystems
# 3. 判断 cgroup 版本:cgroup2fs 表示 v2,tmpfs 表示 v1
stat -fc %T /sys/fs/cgroup
# 4. 加载必需的模块并写入开机自启
modprobe overlay
modprobe br_netfilter
cat >/etc/modules-load.d/containerd.conf <<'EOF'
overlay
br_netfilter
EOF
# 5. 打开网桥转发,Pod 跨节点通信靠这三个参数
cat >/etc/sysctl.d/99-cri.conf <<'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
第 5 段那三个参数看着跟容器运行时没关系,但只要集群里有跨节点 Pod 通信,缺了 ip_forward 就会出现“本机容器能通、跨节点不通”的经典现象,而且 containerd 自己的日志里一个字都不会提,全靠你去猜。 sysctl --system 执行完记得回读一次,确认值真的写进去了,有些镜像里 /etc/sysctl.d 下的文件会被更高优先级的配置覆盖。
swap 也要关掉。kubelet 在 swap 开启的环境下行为不可预期,containerd 本身虽然不强制,但装完之后反正要关,不如现在就做干净: swapoff -a ,然后把 /etc/fstab 里对应的行注释掉,否则重启之后又回来了。
2.3 runc 与目录规划:两个最容易漏的依赖
containerd 自己不负责创建容器进程,真正干活的是 runc,通过 containerd-shim-runc-v2 这个垫片进程转一手。所以 runc 的版本必须单独确认,尤其是 cgroup v2 环境下,runc 1.0.x 会在创建容器时给你一堆看不懂的 cgroup 报错。
# runc 要在 PATH 里,1.1.x 是 1.7 系列的好搭档
runc --version
# 确认 shim 也能被找到,containerd 是去 PATH 里搜它的
which containerd-shim-runc-v2
which 这条命令看着无聊,但它是最常见的翻车点之一:二进制文件明明就在 /usr/local/bin 下,可 systemd 启动的 containerd 继承的 PATH 里偏偏没有这一项,于是容器一启动就报 no such file or directory ,而报错里根本不提是 shim 找不到。要么把 /usr/local/bin 加进 unit 文件的 Environment=PATH= 里,要么老老实实把二进制放到 /usr/bin 。
目录规划我一般按这个表来,装之前先想好,装完了再挪要停机:
| 路径 | 用途 | 备注 |
|---|---|---|
/usr/local/bin/ | containerd、ctr、shim 等二进制 | 必须在 PATH 中 |
/etc/containerd/config.toml | 主配置 | 改之前先备份一份 |
/var/lib/containerd | root 目录,镜像和快照数据 | 建议单独挂盘 |
/run/containerd | state 目录,socket 和临时状态 | 重启即丢,别放持久数据 |
/etc/crictl.yaml | crictl 的客户端配置 | 不写就得每次带 -r 参数 |
根目录单独挂盘这件事,吃过一次亏之后就再也不敢省。镜像层全堆在系统盘上,跑上几个月系统盘满了,机器直接躺平,而且 containerd 在磁盘写满时的表现相当不体面——不是优雅报错,是一堆奇怪的 I/O 失败。
3. 解包与落地:把 cri-containerd-1.7.23-linux-amd64.tar 变成 systemd 服务
前面检查全部通过,就可以动包了。这一步的目标很明确:解包、校验二进制、生成配置、写 unit、起服务,五个动作做完, systemctl status containerd 必须是 active。中间任何一步偷懒,后面都要用双倍时间还。
3.1 解包前先看清单,再决定 -C 到哪里
同一个版本号,不同打包方式的内容结构可能差很远。先看清单,再决定 -C 指向根目录还是 /usr/local ,这一步花十秒,能省掉后面所有的路径纠缠。
# 先看包里是什么结构,前 40 行足够判断
tar -tf cri-containerd-1.7.23-linux-amd64.tar | head -40
# 结构以 bin/ 开头时,落到 /usr/local,二进制会进 /usr/local/bin
tar -C /usr/local -xf cri-containerd-1.7.23-linux-amd64.tar
# 结构以 usr/local/ 或 etc/ 开头时,直接落到根,保持原路径
tar -C / -xf cri-containerd-1.7.23-linux-amd64.tar
解完立刻验证三件事:主二进制能打印版本、shim 在位、 ctr 能执行。 containerd --version 的输出里应该能看到 v1.7.23 这个完整版本串,如果打出来是别的数字,说明机器上还有一份旧的 containerd 在 PATH 里更靠前的位置,这种“装了两份”的情况在手工装过的机器上特别常见。
/usr/local/bin/containerd --version
/usr/local/bin/ctr --version
ls -l /usr/local/bin/containerd-shim-runc-v2
如果解包出来的目录里还带了 CNI 插件和 crictl,别急着全铺到系统里。我的做法是先把 containerd 相关的二进制放好,CNI 插件单独放到 /opt/cni/bin ,crictl 放 /usr/local/bin 并在 /etc/crictl.yaml 里指定 endpoint,这样后面调试的时候每个组件的位置都是明确的。
3.2 生成一份能直接跑的 config.toml
不要手写配置。1.7 的配置项有几百个字段,手写的结局通常是漏掉某个必填段,然后 containerd 启动时报一句完全不知所云的插件加载失败。正确做法是让它自己生成一份默认配置,再在上面改。
mkdir -p /etc/containerd
/usr/local/bin/containerd config default > /etc/containerd/config.toml
cp /etc/containerd/config.toml /etc/containerd/config.toml.bak
config default 会输出当前二进制版本对应的完整配置,字段名、层级、默认值全都是对的。生成完第一件事是备份,第二件事才是改。要改的地方不多,下面这段是我在 1.7.23 上实际用的关键片段:
version = 2
root = "/var/lib/containerd"
state = "/run/containerd"
[grpc]
address = "/run/containerd/containerd.sock"
[plugins."io.containerd.grpc.v1.cri"]
# sandbox 镜像,版本必须和 kubelet 那一代对齐
sandbox_image = "registry.k8s.io/pause:3.9"
[plugins."io.containerd.grpc.v1.cri".containerd]
snapshotter = "overlayfs"
default_runtime_name = "runc"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
# 用 systemd 管理 cgroup,必须和 kubelet 保持一致
SystemdCgroup = true
[plugins."io.containerd.grpc.v1.cri".registry]
# 内网仓库的 hosts.toml 都放这个目录下
config_path = "/etc/containerd/certs.d"
root 和 state 是两个完全不同的东西,前者放镜像、快照这些持久数据,后者放 socket 和运行时状态,重启就没了。把 state 放到 tmpfs 上是常规做法,但如果你的 /run 空间很小,容器一多可能被撑爆。
runtime_type = "io.containerd.runc.v2" 这一行是 v2 运行时,和老的 v1 区别在于 shim 的生命周期管理方式,1.7 上默认就该用 v2。 SystemdCgroup 这个布尔值看似不起眼,但它和 kubelet 的 cgroupDriver 必须一字不差地对上,错一个字就会出现“容器能起但资源限制不生效”或者“Pod 反复重启”这类玄学现象。
config_path 指向的目录不存在也没关系,containerd 会忽略它,但一旦你把某个仓库的 hosts.toml 放进去,它就会按文件里的规则走。这个目录名必须和仓库地址完全一致,包括端口号。
3.3 写 systemd unit 并让它开机自启
tar 包装完之后是没有 service 文件的,得自己写。1.7.23 官方仓库里那份 unit 拿来改一下就能用,重点是 ExecStart 的路径和几个资源限制。
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
# 每次启动前确保 overlay 模块在位
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=1048576
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
Delegate=yes 是必须的,它让 containerd 能自己管理容器进程的 cgroup 子树,不加这个参数,容器多了之后 systemd 会把整个 cgroup 当成自己的东西回收掉,表现出来就是容器莫名其妙消失。 KillMode=process 保证 systemctl restart 时不会把正在跑的容器一起杀掉。 LimitNOFILE 给到 1048576 是因为容器一多,文件描述符消耗得非常快,默认的 1024 撑不了多久。
systemctl daemon-reload
systemctl enable --now containerd
# 起来之后先看状态,再看最近 50 行日志
systemctl status containerd --no-pager
journalctl -u containerd -n 50 --no-pager
状态是 active (running) 并且日志里没有 level=error 才算这一步过了。如果看到 failed to load plugin 之类的字样,八成是 config.toml 里有语法错误或者字段名拼错,往下看排查那一章。
3.4 让 CRI 插件真正被加载
服务起来不等于 CRI 能用。1.7 的 CRI 插件是内置的,但配置里有 disabled_plugins 这个字段,如果它包含 "cri" ,插件就不会加载,此时 ctr 一切正常, crictl 却连不上——这个现象我第一次遇到时还以为是 socket 路径写错了。
# 确认 cri 没被禁用,输出应该是空列表
grep -n 'disabled_plugins' /etc/containerd/config.toml
# socket 必须在位
ls -l /run/containerd/containerd.sock
# 用显式 endpoint 试一次
crictl --runtime-endpoint unix:///run/containerd/containerd.sock info
每次都带 --runtime-endpoint 太麻烦,写进客户端配置文件里: /etc/crictl.yaml 里三行就够, runtime-endpoint 和 image-endpoint 都指向同一个 socket, timeout 给 10 秒。写完之后 crictl info 直接能出 JSON,说明 CRI 这层通了。
4. 关键参数取舍:sandbox_image、SystemdCgroup 与内网仓库
配置项有几百个,真正会让人返工的就那么几个。这一章挑四个最容易出问题的地方展开:sandbox 镜像、cgroup 驱动、仓库配置、数据目录。每个都说清楚“为什么这么填”和“填错了会怎样”。
4.1 sandbox_image:pause 镜像版本必须跟 kubelet 同代
Pod 启动时,containerd 会先拉一个极小的 pause 镜像建 sandbox,所有业务容器共享它的网络命名空间。这个镜像的版本跟 kubelet 那一代是有对应关系的,随手写个 latest 或者写过老的版本,症状是 Pod 卡在 ContainerCreating , crictl inspectp 里能看到 sandbox 创建失败。
| Kubernetes 版本 | 对应 pause |
|---|---|
| 1.24 | 3.7 |
| 1.25 ~ 1.26 | 3.8 |
| 1.27 ~ 1.29 | 3.9 |
| 1.30 及以上 | 3.10 |
先确认集群版本,再改 sandbox_image 。离线环境更要注意,这个镜像得提前推进内网仓库,并且路径要和配置里写的完全一致,带不带端口、带不带命名空间前缀,都必须逐字符对上。
# 改之前先看集群版本
kubelet --version
# 改完从 CRI 侧验证镜像能不能拉到
crictl pull registry.test.local:5000/pause:3.9
crictl images | grep pause
4.2 SystemdCgroup:和 kubelet 的 cgroupDriver 必须一字不差
这是所有配置项里最容易出问题的一个。 SystemdCgroup = true 意味着 containerd 把 cgroup 的创建交给 systemd 管,对应的 kubelet 配置必须是 cgroupDriver: systemd ;两边不一致时,容器能起来,但 CPU、内存限制可能不生效,或者 kubelet 在统计资源用量时看到的数字是错的。
# /var/lib/kubelet/config.yaml 里必须有这一行
cgroupDriver: systemd
# 确认 kubelet 侧的实际取值
grep -n 'cgroupDriver' /var/lib/kubelet/config.yaml
# 确认 containerd 侧
grep -n 'SystemdCgroup' /etc/containerd/config.toml
两边都确认完之后重启一遍 containerd 和 kubelet,顺序是先 containerd 后 kubelet,反过来的话 kubelet 会因为连不上 CRI 而反复重试,日志刷得飞快。cgroup v2 环境下这一项更加不能错,因为 v2 只有统一的层级结构,没有 cgroupfs 那种“各管各的”的余地。
4.3 内网仓库:config_path 与 hosts.toml 的写法
1.7 已经不推荐在老式的 [registry.mirrors] 段里写仓库了,标准做法是 config_path 配合每个仓库一个 hosts.toml 。目录名必须是仓库的 host 加端口,一个字符都不能差, registry.test.local:5000 和 registry.test.local 是两个不同的目录。
mkdir -p /etc/containerd/certs.d/registry.test.local:5000
cat >/etc/containerd/certs.d/registry.test.local:5000/hosts.toml <<'EOF'
server = "https://registry.test.local:5000"
[host."https://registry.test.local:5000"]
capabilities = ["pull", "resolve"]
skip_verify = false
ca = ["/etc/containerd/certs.d/registry.test.local:5000/ca.crt"]
EOF
capabilities 里的 pull 和 resolve 表示这个 host 既能拉镜像也能解析 tag,如果你只想要只读镜像站的行为,就保留这两个。 skip_verify 我一般坚持设成 false,宁可把自签 CA 放到目录里,也不关校验——关了之后一旦 DNS 被污染或者仓库地址写错,拉下来的东西是什么就完全不可控了。 ca 指定证书路径,这个路径是 containerd 进程读的,权限得给够。
写完 hosts.toml 要重启 containerd 才生效,因为 config_path 下的文件是在启动时扫描的。改完用 crictl pull 拉一个镜像验证,报证书错误就去看 /etc/containerd/certs.d 下的路径和权限。
4.4 数据目录与日志级别:两个后期很难改的选项
root 一旦落下数据再想改,就得停机、迁移、改配置、重启,中间还容易把镜像层迁坏。所以装的时候就把根目录指到单独的数据盘上, /var/lib/containerd 只是个默认值,改成一个挂载点更实在的路径更稳妥。
日志级别用默认的 info 就行, debug 打开之后日志量能翻十几倍,磁盘不好的机器上能把自己写卡。真需要排查的时候临时改,排查完改回来,别长期开着。
root = "/data/containerd"
state = "/run/containerd"
[debug]
level = "info"
改 root 之后记得把老目录里的数据搬过去,或者干脆重来一遍——如果还没跑业务容器,重来比搬数据快得多。
5. 避坑与排查:cri-containerd 起不来、Pod 卡住时按层往下砍
排查这件事,最怕的是没有层次感,看到什么报错就搜什么,搜到一半又跳去另一条线索。我的习惯是按启动层、CRI 层、运行时层、镜像层四层往下砍,每一层都有明确的判断依据,哪一层断了就在哪一层停住。下面这几条都是真实踩过的。
5.1 启动层:进程反复重启
现象 : systemctl start containerd 之后几秒钟就变成 inactive (dead) , journalctl 里最后一行是 failed to load plugin io.containerd.grpc.v1.cri 。
原因 :config.toml 里 TOML 语法有问题,或者用了 1.7 已经不认的老字段名。TOML 对缩进不敏感但对引号极敏感, [plugins."io.containerd.grpc.v1.cri"] 少一个引号整份配置就废了,而报错信息只会告诉你插件加载失败。
解决 :用 containerd config dump 让它自己解析一遍,语法错误会直接指到行号。定位不到就退回备份的那份原始配置,逐段往里加,加一段重启一次,比盯着几百行配置猜快得多。
5.2 启动层:容器一创建就报 no such file or directory
现象 : ctr run 或 crictl run 时报 failed to create containerd task: ... no such file or directory: unknown ,但 containerd 进程本身好好的。
原因 : containerd-shim-runc-v2 不在 containerd 进程的 PATH 里。systemd 启动的服务继承的 PATH 很短,通常只有 /usr/bin:/usr/sbin ,而你解包到了 /usr/local/bin 。
解决 :要么在 unit 文件里加 Environment=PATH=/usr/local/bin:/usr/bin:/bin ,要么把二进制挪到 /usr/bin 。改完 daemon-reload 再重启,别只重启服务。
5.3 CRI 层:crictl 连不上 socket
现象 : crictl 直接报 connect: no such file or directory ,但 ls /run/containerd/containerd.sock 明明存在。
原因 :crictl 的默认 endpoint 在有的版本里指向 /var/run/dockershim.sock ,或者干脆没配。它不会自动去找 containerd 的 socket。
解决 :写 /etc/crictl.yaml , runtime-endpoint 和 image-endpoint 都填 unix:///run/containerd/containerd.sock , timeout 给 10。写完不用重启任何服务,客户端配置是每次执行时读的。
5.4 运行时层:Pod 卡在 ContainerCreating
现象 :Pod 一直 ContainerCreating , crictl inspectp <id> 里能看到 sandbox 创建失败,事件里写着拉 pause 镜像失败或者 pull access denied 。
原因 :两种可能。一是 sandbox_image 指向公网地址,而机器根本出不去;二是内网仓库里的 pause 镜像路径和配置里写的不一致,差一个端口号都算不一致。
解决 :先把镜像手动拉下来验证 crictl pull <配置里的完整地址> ,拉不到就是仓库配置问题,回到 4.3 节检查 hosts.toml 和证书。拉得到但 Pod 还是卡,就去看 kubelet 的日志,这时候问题往往已经不在 containerd 这层了。
5.5 镜像层:ctr 看不到镜像
现象 : ctr images ls 输出是空的,但 crictl images 里明明有一堆镜像。
原因 :命名空间不同。 ctr 默认在 default 命名空间,CRI 插件用的是 k8s.io ,同一个 containerd 里两套命名空间的数据是隔离的。
解决 : ctr -n k8s.io images ls 。这个坑特别容易让人误判成“镜像没拉下来”,然后重复拉一遍,浪费时间和带宽。用 ctr 调试 CRI 相关的东西, -n k8s.io 基本是必备参数。
6. 装完怎么验证:三层验证法,从 ctr 到 crictl 再到一个真容器
服务 active 不等于能用。我见过太多次“状态正常、日志干净、但就是跑不了容器”的情况,所以最后这一步验证必须分三层做,每层都有明确的通过标准,任何一层不通就停下来,别往下走。
| 验证层 | 命令 | 通过标准 |
|---|---|---|
| 二进制 | containerd --version | 输出里有 v1.7.23 |
| 进程 | systemctl is-active containerd | 输出 active |
| CRI 接口 | crictl info | 输出 JSON, runtimeName 是 runc |
| 真实容器 | ctr -n k8s.io run --rm ... | 容器能执行命令并正常退出 |
# 第一层:二进制和进程
containerd --version
systemctl is-active containerd
# 第二层:CRI 接口真的活得通
crictl version
crictl info | head -20
# 第三层:不依赖 kubelet,直接用 containerd 跑一个容器
# 镜像换成你环境里能拉到的任意一个
ctr -n k8s.io run --rm -t --net-host \
registry.test.local:5000/library/busybox:1.36 \
smoke-check uname -a
# 顺手确认镜像确实落在了 k8s.io 命名空间
ctr -n k8s.io images ls | head
第三层的 ctr run 是最有价值的一步。它绕过了 kubelet、绕过了 CRI 的调度逻辑,直接考验 containerd + runc + shim 这条链路能不能把进程真的创建出来。这条能过,说明运行时本体是好的,后面集群里再出问题,基本可以锁定在网络、镜像仓库或者 kubelet 配置上,排查范围一下缩小一大半。 --net-host 是为了避开 CNI 依赖,验证阶段不需要网络插件介入。
如果这一步报 cgroup 相关错误,回头检查 SystemdCgroup 和 runc 版本;报镜像相关错误,检查 hosts.toml ;报 shim 找不到,回到 5.2 节。三层都过了,再交给 kubelet 接管, systemctl restart kubelet 之后看节点是不是 Ready,就水到渠成了。
从那以后我每次装完运行时,不管多晚、不管多相信自己刚敲的命令,都强制把这三层验证走一遍,尤其是 ctr -n k8s.io run 那一条。血泪经验是:跳过验证直接上集群,出的问题永远比多花两分钟验证要贵。希望帮到你。
本文详细讲解在离线环境中手动部署cri-containerd 1.7.23的完整流程,涵盖环境检查(内核、cgroup v1/v2、runc版本)、解包与目录规划、config.toml生成、systemd服务配置、关键参数配置(sandbox_image、SystemdCgroup、内网仓库hosts.toml)、常见启动与CRI连接故障排查,以及ctr→crictl→真实容器的三层验证方法,确保Kubernetes CRI运行时稳定可靠。
439

被折叠的 条评论
为什么被折叠?



