K8s 镜像拉取难题:Containerd 代理配置完整指南
概述
在 K8s 集群中,Containerd 作为默认容器运行时,负责镜像拉取、容器启停等核心操作。但实际部署中常遇到 “镜像拉取超时”“无法连接海外仓库(如 Docker Hub、gcr.io)” 等问题,核心原因有两个:
- 网络访问限制:国内网络访问海外镜像仓库时,存在延迟高或连接阻断问题;
- 内网环境隔离:企业 / 机房内网需通过指定代理服务器才能访问外部网络。
Containerd 不会自动继承系统全局代理,需单独配置代理规则 —— 无论是 HTTP/HTTPS 代理,还是内网专属代理,都需通过修改 Containerd 的系统服务配置实现生效。本文详解两种主流配置方案(临时生效、永久生效),并重点说明 K8s 环境下的 NO_PROXY 特殊配置(避免集群内部通信异常)。
一、核心前提:明确代理类型与关键参数
配置前需确认两个关键信息,避免配置无效:
- 代理地址格式:
- HTTP 代理:http://代理 IP:端口(如 http://192.168.1.100:8080);
- HTTPS 代理:通常与 HTTP 代理地址一致(部分代理需单独指定,如 http://192.168.1.100:8443);
- 本地代理(如 Clash、V2Ray):地址多为 http://127.0.0.1:7890(需确认代理工具监听端口)。
- K8s 专属 NO_PROXY 配置:
NO_PROXY 用于指定 “无需走代理” 的地址(避免 K8s 内部组件通信被代理拦截),必须包含以下内容,需根据集群实际配置替换尖括号 <> 中的占位符:
必含项 | 说明 | 示例 |
---|---|---|
localhost,127.0.0.0/8 | 本地回环地址,确保 Containerd 本地通信正常 | 固定值,无需修改 |
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 | 常见私有网段(含 K8s 节点内网、Pod 网段) | 固定值,无需修改 |
.svc,.cluster.local | K8s 内部 Service 域名后缀(如 nginx.default.svc.cluster.local) | 固定值,无需修改(基于 K8s 规范) |
<nodeCIDR> | K8s 节点 IP 所在网段 | 如 192.168.56.0/24 |
<APIServerInternalURL> | K8s API Server 内网地址 | 如 https://192.168.56.10:6443 |
<serviceNetworkCIDRs> | K8s Service 网络网段(kubeadm 部署时 --service-cidr 指定) | 如 10.96.0.0/12 |
<clusterNetworkCIDRs> | K8s Pod 网络网段(如 Calico/Flannel 配置的网段) | 如 10.244.0.0/16 |
自定义域名 / IP | 内网镜像仓库、ETCD 集群地址等(如示例中的 .ewhisper.cn) | 根据实际环境补充 |
二、方案一:临时配置代理(systemctl 环境变量,适合测试)
通过 systemctl set-environment 为 Containerd 服务临时添加代理环境变量,重启 Containerd 后生效,服务器重启后失效,适合临时测试或短期使用。
操作步骤
1. 设置代理环境变量:
复制以下命令,替换 http://127.0.0.1:7890 为你的实际代理地址,NO_PROXY 替换为上述适配后的内容:
# 设置 HTTP 代理
sudo systemctl set-environment HTTP_PROXY=http://127.0.0.1:7890
# 设置 HTTPS 代理
sudo systemctl set-environment HTTPS_PROXY=http://127.0.0.1:7890
# 设置 NO_PROXY(关键:替换为你的 K8s 集群专属配置)
sudo systemctl set-environment NO_PROXY=localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.svc,.cluster.local,.ewhisper.cn,192.168.56.0/24,https://192.168.56.10:6443,10.96.0.0/12,10.244.0.0/16
2. 重启 Containerd 生效:
sudo systemctl restart containerd
3. 验证代理是否生效:
通过 systemctl show 查看 Containerd 服务的环境变量,确认代理配置已加载:
# 查看 Containerd 服务的环境变量,过滤代理相关字段
sudo systemctl show containerd --property=Environment | grep -i proxy
预期输出(示例):
Environment=HTTP_PROXY=http://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 NO_PROXY=localhost,127.0.0.0/8,...
4. 取消临时代理(如需):
若需移除临时代理,执行以下命令并重启 Containerd:
sudo systemctl unset-environment HTTP_PROXY HTTPS_PROXY NO_PROXY
sudo systemctl restart containerd
三、方案二:永久配置代理(服务配置文件,推荐生产环境)
通过在 /etc/systemd/system/containerd.service.d/ 目录下创建自定义配置文件,为 Containerd 服务添加永久代理配置 ——服务器重启后仍生效,适合生产环境长期使用。
操作步骤
1. 创建配置目录(若不存在):
Containerd 的自定义服务配置需放在 containerd.service.d 目录下(系统级配置,优先级高于默认配置),先确保目录存在:
sudo mkdir -p /etc/systemd/system/containerd.service.d
2. 创建代理配置文件:
新建 http-proxy.conf 文件,复制以下内容并替换代理地址和 NO_PROXY(关键:需适配你的 K8s 集群):
sudo vim /etc/systemd/system/containerd.service.d/http-proxy.conf
写入配置(替换示例中的代理地址和 NO_PROXY):
[Service]
# HTTP 代理:替换为你的实际代理地址
Environment="HTTP_PROXY=http://127.0.0.1:7890"
# HTTPS 代理:与 HTTP 代理一致或按实际填写
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
# NO_PROXY:替换为你的 K8s 集群专属配置(必改!)
Environment="NO_PROXY=localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.svc,.cluster.local,.ewhisper.cn,192.168.56.0/24,https://192.168.56.10:6443,10.96.0.0/12,10.244.0.0/16"
3. 重载系统服务配置并重启 Containerd:
修改 systemd 配置后,需重载配置才能识别新文件,再重启 Containerd 生效:
# 重载 systemd 配置(关键:让系统识别新的代理配置)
sudo systemctl daemon-reload
# 重启 Containerd 服务
sudo systemctl restart containerd
注意:原博文中 “重启 docker.service” 为笔误,Containerd 服务名为 containerd,无需操作 Docker 服务。
4. 验证代理配置生效:
除了通过 systemctl show 验证环境变量,还可通过 crictl 拉取一个海外镜像(如 nginx:alpine)测试实际效果:
# 用 crictl 拉取镜像(Containerd 官方客户端工具)
sudo crictl pull nginx:alpine
若输出 Successfully pulled image "nginx:alpine",表示代理配置正常,镜像拉取成功。
四、常见问题与解决方案(K8s 环境专属避坑)
问题现象 | 可能原因 | 解决方案 |
---|---|---|
配置代理后,Pod 无法通过 Service 通信 | NO_PROXY 未包含 .svc 或 cluster.local 后缀 | 补充 NO_PROXY 配置,确保包含 .svc,.cluster.local(K8s Service 域名后缀)。 |
镜像拉取成功,但 Kubelet 无法连接 Containerd | NO_PROXY 未包含节点内网网段(如 ]<nodeCIDR>) | 在 NO_PROXY 中添加节点 IP 所在网段(如 192.168.56.0/24)。 |
重启服务器后,代理配置失效 | 使用了 “临时配置方案”(systemctl set-environment) | 改用 “永久配置方案”(创建 http-proxy.conf 文件),确保配置持久化。 |
代理需要用户名密码验证 | 未在代理地址中包含认证信息 | 格式:http://用户名:密码@代理 IP:端口(如 http://user:123456@192.168.1.100:8080),密码含特殊字符(如 @)需 URL 编码(@ 编码为 %40)。 |
配置后 crictl pull 仍超时 | 1. 代理地址错误;2. 防火墙阻断 Containerd 访问代理 | 1. 用 curl -x http://代理地址 https://www.docker.com 测试代理是否可用; 2. 临时关闭防火墙(sudo ufw disable 或 sudo systemctl stop firewalld)排查,若恢复则需配置防火墙放行规则。 |
五、总结:两种方案的选择建议
配置方案 | 生效范围 | 优点 | 缺点 | 适合场景 |
---|---|---|---|---|
临时配置(systemctl) | 仅当前 Containerd 服务,重启服务器失效 | 操作简单,无需修改配置文件,适合测试 | 不持久,服务器重启后需重新配置 | 临时测试代理可用性、短期调试 |
永久配置(配置文件) | 系统级持久化,重启服务器仍生效 | 一劳永逸,适合长期稳定使用 | 需手动创建配置文件,需注意 NO_PROXY 适配 | 生产环境 K8s 集群、长期使用 Containerd 的场景 |
对于 K8s 集群,优先选择 “永久配置方案”—— 不仅能确保代理持久生效,还能通过统一的配置文件实现集群节点批量同步(如用 Ansible 分发 http-proxy.conf 到所有节点)。核心注意点是 NO_PROXY 必须适配 K8s 集群的网络规划,避免内部通信被代理拦截,导致 Pod 调度、Service 访问等异常。