背景
节点磁盘是一种单调递减资源,虽然节点有监控,但是也只是个监控没法清理。所以需要一个定时任务来执行清理磁盘。crontab 可以实现,只适合于本地脚本和命令的定时执行。
在k8s中 CronJob 也可以实现,并且提供了内置的失败处理和重试机制,也可以配置失败后重试的次数。同时可以通过 Prometheus 来监控任务的执行状态。而且 Job 只需要临时地占用一些节点资源,任务执行完毕后会自动释放。
但 CronJob 也有一些限制:
- 默认的调度规则是随机的,一个节点上可能创建多个 Pod,造成重复作业的问题;
- 无法自适应集群节点的规模,当集群中添加/删除一个节点时,需要手动调整 Job 的配置。
OpenKruise BroadcastJob 则很好地克服了原生 Job 在节点运维场景中的不足之处。它允许用户以类似 DaemonSet 调度的方式来编排 Pod,当用户创建 BroadcastJob 后,它会默认在集群的每一个 worker 节点创建一个 Pod,执行完成之后会自动对 Pod 进行清理。同时,搭配 Advanced CronJob,可以将 BroadcastJob 进行定时发下,从而实现定时清理节点磁盘的能力。
环境
当前磁盘空间情况如下:
查看镜像有很多升级版本遗留的镜像。
构建镜像
cat Dockerfile
FROM registry.cn-hangzhou.aliyuncs.com/wgh9626/debian:latest
COPY crictl /bin/
COPY clean.sh /bin/
RUN chmod +x /bin/clean.sh && chmod +x /bin/crictl
CMD ["sh", "/bin/clean.sh"]
docker build -t registry.cn-hangzhou.aliyuncs.com/wgh9626/clean:latest .
docker push registry.cn-hangzhou.aliyuncs.com/wgh9626/clean:latest
注意这里不能用alpine镜像,因为alpine镜像中没有bash命令。容器会报这个错:Error: failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "bash": executable file not found in $PATH: unknown
这样构建镜像pod启动后仍然会报这个错,因为下面的脚本中使用了[ $? -eq 0 ]
,这个需要bash。所以这里有两种方案,一种是使用其他镜像比如debian,ubuntu等,第二种是安装bash。
RUN apk add --no-cache bash
。我这使用debian了。
清理脚本
cat clean.sh
#!/bin/sh
echo "container runtime endpoint:" $CONTAINER_RUNTIME_ENDPOINT
# 检查是否有启动的容器
crictl ps > /dev/null
if [ $? -eq 0 ]
then
crictl ps | awk '{if(NR>1){print $2}}' > used-images.txt
crictl images | grep registry.aliyuncs.com | awk '{print $3}' > target-images.txt
# # 删除带有registry.aliyuncs.com的未使用的镜像。
sort target-images.txt used-images.txt used-images.txt | uniq -u | xargs -r crictl rmi
else
echo "crictl does not exist"
fi
exit 0
创建Advanced CronJob
apiVersion: apps.kruise.io/v1alpha1
kind: AdvancedCronJob
metadata:
name: acj-test
spec:
schedule: "*/1 * * * *"
startingDeadlineSeconds: 60
template:
broadcastJobTemplate:
spec:
template:
spec:
containers:
- name: node-cleaner
image: registry.cn-hangzhou.aliyuncs.com/wgh9626/clean:latest
imagePullPolicy: IfNotPresent
env:
- name: CONTAINER_RUNTIME_ENDPOINT
value: unix:///var/run/containerd/containerd.sock
volumeMounts:
- name: containerd
mountPath: /var/run/containerd
terminationMessagePath: /tmp/termination-log
terminationMessagePolicy: File
volumes:
- name: containerd
hostPath:
path: /var/run/containerd
restartPolicy: OnFailure
dnsPolicy: ClusterFirst
completionPolicy:
type: Always
ttlSecondsAfterFinished: 90
failurePolicy:
type: Continue
restartLimit: 3
以hostPath的方式将该 containerd.sock
挂载到容器中以执行crictl命令。CronJob 定义成每隔1分钟执行一次清除动作方便测试,真实的场景中,我们可以每隔几天甚至几周清理一次。
k apply -f job.yaml
job执行成功。
查看kruise-controller-manager
的日志可以看到job下次执行时间。
k logs -n kruise-system kruise-controller-manager-555d7f7959-ngb6w --tail 1000 | grep "No upcoming scheduled times"
删除了几个镜像后,磁盘空间也释放了一点。