如何用脚本自动清理Kubernetes资源?——从手动焦虑到自动化运维
目录导读
- 为什么要自动清理Kubernetes资源?
- 资源泄漏的常见场景
- 手动清理的痛点与风险
- 核心思路:脚本要“看见”什么?
- 需要清理的典型资源类型
- 如何安全地定义清理条件
- 实战脚本:从零搭建自动清理工具
- 基础Shell脚本:按名字空间/标签清理
- Python版本:支持复杂过滤与日志记录
- 结合CronJob实现定期执行
- 关键问题与问答环节
- 如何避免误删运行中的Pod?
- 清理完成后如何通知团队?
- 进阶:用Operator实现智能清理
- 对比脚本与Operator的适用场景
- 推荐开源工具(如Kuberhealthy、Kubelet清理插件)
为什么要自动清理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.phase为Succeeded或Failed;或Evicted;或Terminating超过24小时 |
不要误删Running状态的Pod,除非有特殊标签 |
| Job | status.succeeded > 0且创建超过7天 |
避免删除还在运行中的Job |
| ConfigMap/Secret | 未被任何Pod挂载,且创建超过30天 | 先扫描Pod的挂载引用 |
| Namespace | 标记为终止中(Terminating)超过72小时 | 检查依赖资源(如CRD、Endpoints) |
| PV/PVC | 状态为Released或Lost,且未被动态回收 |
需要确认底层存储插件是否支持自动删除 |
如何安全地定义清理条件?
- 标签驱动:为资源添加
auto-clean: enabled标签,脚本只清理带此标签的对象。 - 时间窗口:设置
creationTimestamp过滤,例如清理7天前的调度失败的Pod。 - 状态联合:状态为Completed且最后更新时间超过24小时”。
- 黑名单机制:在脚本中配置免清理的名字空间(如
kube-system、istio-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.phase为Succeeded、Failed、Evicted的对象,可以增加干跑模式(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,你需要根据集群规模和资源生命周期选择合适方案,记住三个原则:安全优先(认准状态)、逐批执行、留痕可溯。
动手写一个适合你集群的清理脚本,让“资源消亡”也自动化。