节后恢复发布前,我做了一次镜像预检记录。
场景是一个普通后端服务,CI 负责测试和构建镜像,部署到云上 Kubernetes。流水线第一次跑没有进入测试阶段,日志停在:
Pulling docker image node:20-alpine ...
failed to pull image: context deadline exceeded
这类问题容易被误判成构建失败,但实际还在镜像阶段。
runner 侧先测
先把 CI 会用到的镜像列出来:
| 来源位置 | 镜像 |
|---|---|
.gitlab-ci.yml |
node:20-alpine |
| service | redis:7-alpine、postgres:16-alpine |
| Dockerfile | nginx:stable-alpine |
| 发布工具 | your-org/release-helper |
| K8s 基础组件 | pause:3.10 |
在 runner 所在网络里逐个验证:
docker pull docker.1ms.run/node:20-alpine
docker pull docker.1ms.run/redis:7-alpine
docker pull docker.1ms.run/postgres:16-alpine
docker pull docker.1ms.run/nginx:stable-alpine
docker pull ghcr.1ms.run/your-org/release-helper:2026.05.05
docker pull k8s.1ms.run/pause:3.10
这里主要确认 CI 的构建容器、service 容器和发布工具镜像能不能正常拉取。
节点侧再测
云上 Kubernetes 节点走的是 containerd,不能只拿 runner 的 Docker 结果当结论。
在目标节点上继续验证:
crictl pull docker.1ms.run/nginx:stable-alpine
crictl pull k8s.1ms.run/pause:3.10
crictl images | grep -E "nginx|pause"
如果 runner 能拉、节点不能拉,通常要看这些点:
- 节点 DNS 是否和 runner 不同。
- containerd 是否有对应镜像入口配置。
- 节点是否缺少私有仓库凭证。
- VPC、NAT、代理策略是否影响出网。
- 节点磁盘空间是否不足。
放进发布前检查
后面我把这组命令放进发布前检查:
#!/usr/bin/env bash
set -euo pipefail
images=(
"docker.1ms.run/node:20-alpine"
"docker.1ms.run/redis:7-alpine"
"docker.1ms.run/postgres:16-alpine"
"docker.1ms.run/nginx:stable-alpine"
"ghcr.1ms.run/your-org/release-helper:2026.05.05"
"k8s.1ms.run/pause:3.10"
)
for image in "${images[@]}"; do
echo "pull ${image}"
docker pull "${image}"
done
这一步不解决业务问题,只是把镜像链路提前验证掉。镜像阶段通过以后,再看测试失败、构建失败或 Kubernetes 部署失败,边界会更清楚。
小结
云上发布前,runner 和 K8s 节点最好分开测。
CI 侧看 Docker 能不能拉,节点侧看 containerd 能不能拉。两边都通过,再进入测试、构建和部署,节后第一轮发布会少一些低价值排查。