Kubernetes 节点 Docker 镜像清理自动化方案 - 使用 CronJob 定时清理

Kubernetes 节点 Docker 镜像清理 CronJob

前置条件

  • Kubernetes 版本:v1.20+(因为使用了 kubectl debug 功能)
  • 容器运行时:节点使用 Docker 作为容器运行时(不是 containerd 或 CRI-O)
  • 权限要求:需要有创建 ClusterRole 和 ClusterRoleBinding 的权限
  • 网络要求:节点能够拉取 docker:28.0.1bitnami/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

清理策略

  1. 镜像清理
    • 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
  • 历史记录数量

故障排除

常见问题

  1. 权限不足

    # 验证创建 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
    
  2. 镜像拉取失败

    • 检查网络连接
    • 考虑使用内网镜像仓库
  3. 节点清理失败

    • 检查节点状态
    • 查看详细错误日志

调试命令

# 手动执行清理脚本(测试用)
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
"

最佳实践

  1. 测试环境验证:先在测试环境验证清理脚本
  2. 备份重要镜像:确保重要镜像有备份
  3. 监控告警:设置磁盘空间告警
  4. 定期审查:定期审查清理策略和效果
  5. 文档更新:根据实际使用情况更新文档

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 初始版本 -

参考文档

posted @ 2026-02-25 22:26  怀恋小时候  阅读(44)  评论(0)    收藏  举报