如何用脚本自动清理Kubernetes资源?

wen 实用脚本 5

如何用脚本自动清理Kubernetes资源?——从手动焦虑到自动化运维

目录导读

  1. 为什么要自动清理Kubernetes资源?
    • 资源泄漏的常见场景
    • 手动清理的痛点与风险
  2. 核心思路:脚本要“看见”什么?
    • 需要清理的典型资源类型
    • 如何安全地定义清理条件
  3. 实战脚本:从零搭建自动清理工具
    • 基础Shell脚本:按名字空间/标签清理
    • Python版本:支持复杂过滤与日志记录
    • 结合CronJob实现定期执行
  4. 关键问题与问答环节
    • 如何避免误删运行中的Pod?
    • 清理完成后如何通知团队?
  5. 进阶:用Operator实现智能清理
    • 对比脚本与Operator的适用场景
    • 推荐开源工具(如Kuberhealthy、Kubelet清理插件)

为什么要自动清理Kubernetes资源?

资源泄漏的常见场景

在Kubernetes集群中,资源泄漏是运维人员的“隐形杀手”。

如何用脚本自动清理Kubernetes资源?

  • 开发环境测试服务:开发人员忘记删除临时创建的Deployment、Service或ConfigMap,长期占用资源。
  • Job/CronJob过期:完成任务的Job或CronJob创建的Pod在Completed后仍保留,导致节点磁盘不足(尤其是日志和镜像层)。
  • Evicted Pod:因节点压力被驱逐的Pod未自动删除,堆积后影响kubectl get pods的查询效率。
  • 未清理的Helm Release:卸载Helm Chart时未清理残留的CRD或Namespace。

手动清理的痛点

  • 效率低:一个拥有100+名字空间的集群,手动执行kubectl delete pod --field-selector=status.phase==Succeeded需要反复切换上下文。
  • 误删风险:人工删除时可能误删关键资源(如生产环境的Running Pod)。
  • 无审计日志:谁删了、何时删、删了哪些资源,手动操作无法留痕。

一句话总结:脚本自动清理不是“偷懒”,而是为了安全、可控、可追溯地管理集群资源。


核心思路:脚本要“看见”什么?

需要自动清理的资源类型

资源类型 清理条件 注意事项
Pod status.phaseSucceededFailed;或Evicted;或Terminating超过24小时 不要误删Running状态的Pod,除非有特殊标签
Job status.succeeded > 0且创建超过7天 避免删除还在运行中的Job
ConfigMap/Secret 未被任何Pod挂载,且创建超过30天 先扫描Pod的挂载引用
Namespace 标记为终止中(Terminating)超过72小时 检查依赖资源(如CRD、Endpoints)
PV/PVC 状态为ReleasedLost,且未被动态回收 需要确认底层存储插件是否支持自动删除

如何安全地定义清理条件?

  • 标签驱动:为资源添加auto-clean: enabled标签,脚本只清理带此标签的对象。
  • 时间窗口:设置creationTimestamp过滤,例如清理7天前的调度失败的Pod。
  • 状态联合:状态为Completed且最后更新时间超过24小时”。
  • 黑名单机制:在脚本中配置免清理的名字空间(如kube-systemistio-system)。

实战脚本:从零搭建自动清理工具

基础Shell脚本:按名字空间/标签清理

#!/bin/bash
# clean-k8s-resources.sh
# 目标:清理所有名字空间中状态为Succeeded/Failed的Pod,以及完成7天的Job
NAMESPACES=$(kubectl get ns -o jsonpath='{.items[*].metadata.name}')
for ns in $NAMESPACES; do
  # 1. 清理Succeeded/Failed Pod
  kubectl delete pod -n $ns --field-selector=status.phase==Succeeded --grace-period=0 2>/dev/null
  kubectl delete pod -n $ns --field-selector=status.phase==Failed --grace-period=0 2>/dev/null
  # 2. 清理状态为Completed且创建超过7天的Job
  kubectl get job -n $ns -o json | jq -r '.items[] | select(.status.succeeded > 0 and .metadata.creationTimestamp < (now - 7*24*3600 | strftime)) | .metadata.name' | while read job; do
    kubectl delete job -n $ns "$job" --grace-period=0
  done
done

运行chmod +x clean-k8s-resources.sh && ./clean-k8s-resources.sh

Python版本:支持复杂过滤与日志记录(推荐)

Python脚本更适合生产环境,因为它可以处理数组、异常和日志,示例如下:

# clean_k8s.py
import os
import json
import datetime
from kubernetes import client, config, watch
config.load_kube_config()  # 或从集群内加载
v1 = client.CoreV1Api()
batch_v1 = client.BatchV1Api()
def clean_expired_pods(age_hours=48):
    now = datetime.datetime.utcnow()
    pods = v1.list_pod_for_all_namespaces(watch=False)
    deleted = []
    for pod in pods.items:
        if pod.status.phase in ("Succeeded", "Failed") and \
           (now - pod.metadata.creation_timestamp).total_seconds() > age_hours * 3600:
            if pod.metadata.namespace not in ["kube-system", "logging"]:  # 黑名单
                v1.delete_namespaced_pod(pod.metadata.name, pod.metadata.namespace, grace_period_seconds=0)
                deleted.append(f"{pod.metadata.namespace}/{pod.metadata.name}")
    return deleted
def log_cleanup(deleted_items):
    with open("/var/log/k8s-cleanup.log", "a") as f:
        f.write(f"[{datetime.datetime.now()}] Deleted: {json.dumps(deleted_items)}\n")

结合CronJob实现定期执行

在Kubernetes集群内部署清理脚本作为CronJob:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: auto-clean-pods
spec:
  schedule: "0 2 * * *"  # 每天凌晨2点
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: cleanup-sa  # 需要创建RBAC权限
          containers:
          - name: cleaner
            image: bitnami/kubectl:latest
            command: ["/bin/bash", "-c", "/scripts/clean.sh"]
            volumeMounts:
            - name: script-volume
              mountPath: /scripts
          volumes:
          - name: script-volume
            configMap:
              name: clean-script  # 提前将脚本存入ConfigMap

RBAC权限示例(需要创建ServiceAccount和ClusterRole):

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: pod-cleaner
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "delete"]

关键问题与问答环节

Q:如何避免误删运行中的Pod?

A:核心是严格区分状态,脚本只删除status.phaseSucceededFailedEvicted的对象,可以增加干跑模式(Dry-run)
kubectl delete ... --dry-run=client,先输出将要删除的资源列表,确认无误后移除--dry-run

Q:清理完成后如何通知团队?

A:推荐集成通知渠道:

  • Slack/RocketChat:脚本执行后通过Webhook发送消息:curl -X POST -H "Content-Type: application/json" -d '{"text":"清理完成,删除了X个Pod"}' your-slack-webhook-url
  • Email:使用mail命令或Python的smtplib发送报告。
  • 存储为Prometheus指标:通过prometheus_client暴露清理数量,供Grafana监控。

Q:脚本执行失败(如API限流)怎么办?

A:加入重试机制和超时处理,Python版本可设置max_retries=3,并在每次删除后添加time.sleep(0.2)避免请求过快。


进阶:用Operator实现智能清理

脚本 vs Operator

对比维度 Shell/Python脚本 自定义Operator
部署复杂度 简单,单文件即可 需要编写CRD、Controller
动态响应 定时执行,无实时性 监听资源事件,实时响应
可扩展性 适合批量清理 可以处理更复杂的逻辑(如级联删除)
推荐场景 清理过期Job、Pod 自动回收动态创建的CRD资源

推荐开源工具

  • Kubecost:不仅能清理资源,还能提供成本分析,自动删除未挂载的卷。
  • K8s-Common-Labs/clean-operator:一个轻量级Operator,支持按标签和时间窗口自动清理。
  • Velero(仅备份):虽然主要用于备份,但其背景清理功能也能删除过期的备份资源。

脚本自动清理Kubernetes资源不是“锦上添花”,而是生产级集群的必备能力,从简单的Shell脚本到集成了RBAC、CronJob和日志的Python版本,再到高级的Operator,你需要根据集群规模和资源生命周期选择合适方案,记住三个原则:安全优先(认准状态)、逐批执行、留痕可溯

动手写一个适合你集群的清理脚本,让“资源消亡”也自动化。

抱歉,评论功能暂时关闭!