Kubernetes 节点 Docker 镜像清理自动化方案 - 使用 CronJob 定时清理
Kubernetes 节点 Docker 镜像清理 CronJob
前置条件
- Kubernetes 版本:v1.20+(因为使用了
kubectl debug功能) - 容器运行时:节点使用 Docker 作为容器运行时(不是 containerd 或 CRI-O)
- 权限要求:需要有创建 ClusterRole 和 ClusterRoleBinding 的权限
- 网络要求:节点能够拉取
docker:28.0.1和bitnami/kubectl:latest镜像 - 版本匹配:建议使用与节点 Docker 版本匹配的
docker镜像版本
兼容性说明
容器运行时兼容性
| 运行时 | 是否支持 | 说明 |
|---|---|---|
| Docker | ✅ 支持 | 直接使用 docker 命令 |
| containerd | ❌ 不支持 | 需要修改为 crictl 命令 |
| CRI-O | ❌ 不支持 | 需要适配 |
Kubernetes 版本兼容性
| 版本 | 是否支持 | 说明 |
|---|---|---|
| v1.20+ | ✅ 支持 | kubectl debug 命令可用 |
| v1.15-v1.19 | ⚠️ 有限支持 | 需要使用 kubectl run 替代方案 |
| v1.15以下 | ❌ 不支持 | 建议升级集群 |
概述
本文档提供了一个 Kubernetes CronJob 配置,用于自动清理集群中所有节点上的 Docker 本地仓库中无用的镜像。该任务每天凌晨 3 点自动执行,可以有效管理节点磁盘空间。
功能特性
- 定时执行:每天凌晨 3 点自动运行
- 全节点清理:遍历集群中的所有节点
- 镜像策略:
- 清理 24 小时前的所有镜像
- 清理所有悬空镜像
- 超时保护:每个节点操作限制 120 秒
- 历史记录:保留 3 个成功任务和 1 个失败任务的历史记录
YAML 配置
# 创建daily-image-cleanup-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-image-cleanup
namespace: image-cleanup-system
spec:
schedule: "0 3 * * *"
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
ttlSecondsAfterFinished: 3600
template:
spec:
serviceAccountName: image-cleanup-sa
containers:
- name: cleaner
image: bitnami/kubectl:latest
command: ["/bin/bash"]
args:
- "-c"
- |
echo "开始清理所有K8s节点上的旧镜像..."
TIMEOUT=120
kubectl get nodes -o name | while read NODE; do
NODE_NAME=$(echo $NODE | cut -d'/' -f2)
echo "清理节点: $NODE_NAME"
timeout $TIMEOUT kubectl debug $NODE \
--image=docker:28.0.1 \
--quiet \
-- sh -c "
echo '在节点 ${NODE_NAME} 上执行清理...'
chroot /host docker image prune -a -f --filter 'until=24h' 2>/dev/null
chroot /host docker image prune -f 2>/dev/null
echo '节点 ${NODE_NAME} 清理完成.'
" 2>/dev/null || echo "节点 $NODE_NAME 清理超时或失败"
echo "$NODE_NAME 处理完成"
echo "---"
done
echo "所有节点镜像清理完成!"
restartPolicy: Never
部署说明
1. 创建专用命名空间
kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: image-cleanup-system
labels:
name: image-cleanup-system
EOF
2. 创建 RBAC 资源(如果不存在)
首先创建 ClusterRole 和 ClusterRoleBinding:
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: image-cleanup-role
rules:
- apiGroups: [""]
resources: ["nodes", "pods"]
verbs: ["get", "list", "watch", "create", "delete"]
EOF
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: image-cleanup-binding
subjects:
- kind: ServiceAccount
name: image-cleanup-sa
namespace: image-cleanup-system
roleRef:
kind: ClusterRole
name: image-cleanup-role
apiGroup: rbac.authorization.k8s.io
EOF
3. 创建 ServiceAccount
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: image-cleanup-sa
namespace: image-cleanup-system
EOF
4. 应用 CronJob 配置
kubectl apply -f daily-image-cleanup-cronjob.yaml
5. 验证部署
# 查看 CronJob 状态
kubectl get cronjob -n image-cleanup-system daily-image-cleanup
# 查看最近的 Job
kubectl get jobs -n image-cleanup-system
# 查看 Job 日志
kubectl logs -n image-cleanup-system job/daily-image-cleanup-xxxxx
配置详解
关键参数说明
| 参数 | 值 | 说明 |
|---|---|---|
schedule |
"0 3 * * *" |
Cron 表达式,每天凌晨 3 点执行 |
successfulJobsHistoryLimit |
3 |
保留 3 个成功的 Job 历史记录 |
failedJobsHistoryLimit |
1 |
保留 1 个失败的 Job 历史记录 |
ttlSecondsAfterFinished |
3600 |
Job 完成后 1 小时自动清理 |
TIMEOUT |
120 |
每个节点操作超时时间(秒) |
RBAC 权限说明
| 权限类型 | 资源 | 操作 | 用途 |
|---|---|---|---|
| 节点权限 | nodes | get, list, watch, create | 获取节点信息和创建调试 Pod |
| Pod 权限 | pods | get, list, watch, create, delete | 获取、创建和删除 Pod |
清理策略
- 镜像清理:
docker image prune -a -f --filter 'until=24h':清理 24 小时前的所有镜像docker image prune -f:清理所有悬空镜像
注意事项
1. RBAC 权限要求
确保已正确配置 RBAC 权限:
- ClusterRole:定义了对 nodes 和 pods 的操作权限
- ClusterRoleBinding:将权限绑定到 ServiceAccount
- ServiceAccount:用于身份认证
所需权限包括:
- 获取节点信息(get, list, watch nodes)
- 创建调试 Pod(create pods)
- 删除调试 Pod(delete pods)
2. 资源影响
- 清理操作可能会短暂影响节点性能
- 建议在低峰期执行
- 确保有足够的磁盘空间进行清理
3. 监控和日志
- 定期检查 Job 执行状态
- 查看清理日志确认操作成功
- 监控节点磁盘空间使用情况
4. 自定义配置
可根据实际需求调整:
- 执行时间(修改
schedule) - 超时时间(修改
TIMEOUT) - 镜像保留时间(修改
until=24h) - 历史记录数量
故障排除
常见问题
-
权限不足:
# 验证创建 pods 的权限 kubectl auth can-i create pods --as=system:serviceaccount:image-cleanup-system:image-cleanup-sa # 验证获取 nodes 的权限 kubectl auth can-i get nodes --as=system:serviceaccount:image-cleanup-system:image-cleanup-sa # 验证删除 pods 的权限 kubectl auth can-i delete pods --as=system:serviceaccount:image-cleanup-system:image-cleanup-sa -
镜像拉取失败:
- 检查网络连接
- 考虑使用内网镜像仓库
-
节点清理失败:
- 检查节点状态
- 查看详细错误日志
调试命令
# 手动执行清理脚本(测试用)
kubectl run -it --rm --restart=Never --image=bitnami/kubectl:latest -- bash -c "
kubectl get nodes -o name | while read NODE; do
NODE_NAME=\$(echo \$NODE | cut -d'/' -f2)
echo '清理节点: \$NODE_NAME'
timeout 120 kubectl debug \$NODE --image=docker:28.0.1 --quiet -- sh -c 'chroot /host docker image prune -a -f --filter \"until=24h\" 2>/dev/null; chroot /host docker image prune -f 2>/dev/null'
done
"
最佳实践
- 测试环境验证:先在测试环境验证清理脚本
- 备份重要镜像:确保重要镜像有备份
- 监控告警:设置磁盘空间告警
- 定期审查:定期审查清理策略和效果
- 文档更新:根据实际使用情况更新文档
Docker 版本匹配建议
重要提示:建议使用与节点 Docker 版本匹配的 docker 镜像版本,以确保兼容性:
如何查看节点 Docker 版本:
# 在任意节点上执行
docker --version
# 示例输出:Docker version 20.10.7, build f0df350
推荐的版本对应关系:
| 节点 Docker 版本 | 建议使用的镜像版本 | 说明 |
|---|---|---|
| 20.10.x | docker:20.10.x | 完全匹配 |
| 20.10.x | docker:20.10 | 主要版本匹配 |
| 19.03.x | docker:19.03.x | 完全匹配 |
| 18.09.x | docker:18.09.x | 完全匹配 |
| 未知版本 | docker:latest | 尽量避免,可能不兼容 |
修改配置示例:
如果节点使用 Docker 20.10.7,建议将 CronJob 中的镜像版本从:
--image=docker:28.0.1
修改为:
--image=docker:20.10.7
或者使用环境变量方式:
DOCKER_IMAGE_VERSION="20.10.7" # 根据实际情况调整
版本不匹配的风险:
- 功能不兼容:新版本镜像可能不支持旧版本 Docker 的命令
- API 差异:不同版本的 Docker 命令参数可能有所不同
- 性能问题:版本差异可能导致性能下降或不稳定
完整部署命令
一键部署所有资源:
#!/bin/bash
# 创建完整的镜像清理 CronJob 部署
# 创建专用命名空间
kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: image-cleanup-system
labels:
name: image-cleanup-system
EOF
# 创建 RBAC 资源
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: image-cleanup-role
rules:
- apiGroups: [""]
resources: ["nodes", "pods"]
verbs: ["get", "list", "watch", "create", "delete"]
EOF
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: image-cleanup-binding
subjects:
- kind: ServiceAccount
name: image-cleanup-sa
namespace: image-cleanup-system
roleRef:
kind: ClusterRole
name: image-cleanup-role
apiGroup: rbac.authorization.k8s.io
EOF
# 创建 ServiceAccount
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: image-cleanup-sa
namespace: image-cleanup-system
EOF
# 创建 CronJob
kubectl apply -f - <<EOF
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-image-cleanup
namespace: image-cleanup-system
spec:
schedule: "0 3 * * *"
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
ttlSecondsAfterFinished: 3600
template:
spec:
serviceAccountName: image-cleanup-sa
containers:
- name: cleaner
image: bitnami/kubectl:latest
command: ["/bin/bash"]
args:
- "-c"
- |
echo "开始清理所有K8s节点上的旧镜像..."
TIMEOUT=120
kubectl get nodes -o name | while read NODE; do
NODE_NAME=\$(echo \$NODE | cut -d'/' -f2)
echo "清理节点: \$NODE_NAME"
timeout \$TIMEOUT kubectl debug \$NODE \\
--image=docker:28.0.1 \\
--quiet \\
-- sh -c "
echo '在节点 \${NODE_NAME} 上执行清理...'
chroot /host docker image prune -a -f --filter 'until=24h' 2>/dev/null
chroot /host docker image prune -f 2>/dev/null
echo '节点 \${NODE_NAME} 清理完成.'
" 2>/dev/null || echo "节点 \$NODE_NAME 清理超时或失败"
echo "\$NODE_NAME 处理完成"
echo "---"
done
echo "所有节点镜像清理完成!"
restartPolicy: Never
EOF
echo "部署完成!验证状态:"
kubectl get cronjob -n image-cleanup-system daily-image-cleanup
kubectl get clusterrole image-cleanup-role
kubectl get clusterrolebinding image-cleanup-binding
kubectl get serviceaccount -n image-cleanup-system image-cleanup-sa
版本历史
| 版本 | 日期 | 变更内容 | 作者 |
|---|---|---|---|
| v1.0 | 2026-02-25 | 初始版本 | - |

浙公网安备 33010602011771号