我最近注意到状态为“关闭”的 Pod 大量堆积。我们自 2020 年 10 月以来一直在使用 Kubernetes。
生产和登台运行在相同的节点上,只是登台使用可抢占节点来降低成本。容器在暂存过程中也很稳定。 (故障很少发生,因为之前在测试中发现过)。
服务提供商 Google Cloud Kubernetes。
我熟悉了文档并尝试搜索,但我都不认识谷歌对这种特殊状态的帮助。日志中没有错误。
我没有遇到 pod 被停止的问题。理想情况下,我希望 K8s 自动删除这些关闭 Pod。如果我跑
kubectl delete po redis-7b86cdccf9-zl6k9
,它就会眨眼间消失。
kubectl get pods | grep Shutdown | awk '{print $1}' | xargs kubectl delete pod
是手动临时解决方法。
PS。在我的环境中,
k
是 kubectl
的别名。
我偶然发现了一些解释状态的相关问题 https://github.com/kubernetes/website/pull/28235 https://github.com/kubernetes/kubernetes/issues/102820
“当 Pod 在节点正常关闭期间被逐出时,它们会被标记为失败。运行
kubectl get pods
将显示被逐出 Pod 的状态为 Shutdown
。”
被驱逐的 Pod 不是故意删除的,正如 k8s 团队在这里所说的1,被驱逐的 Pod 也不是为了在驱逐后进行检查而被删除。
我相信最好的方法是创建一个 cronjob 2,正如已经提到的。
apiVersion: batch/v1
kind: CronJob
metadata:
name: del-shutdown-pods
spec:
schedule: "* 12 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- kubectl get pods | grep Shutdown | awk '{print $1}' | xargs kubectl delete pod
restartPolicy: OnFailure
您不需要任何 grep - 只需使用 kubectl 提供的选择器即可。而且,顺便说一句,您无法从 busybox 映像调用 kubectl,因为它根本没有 kubectl。我还创建了一个具有 pod 删除权限的服务帐户。
apiVersion: batch/v1
kind: CronJob
metadata:
name: del-shutdown-pods
spec:
schedule: "0 */2 * * *"
concurrencyPolicy: Replace
jobTemplate:
metadata:
name: shutdown-deleter
spec:
template:
spec:
serviceAccountName: deleter
containers:
- name: shutdown-deleter
image: bitnami/kubectl
imagePullPolicy: IfNotPresent
command:
- "/bin/sh"
args:
- "-c"
- "kubectl delete pods --field-selector status.phase=Failed -A --ignore-not-found=true"
restartPolicy: Never
首先,尝试使用以下命令强制删除 kubernetes pod:
$ kubectl 删除 pod
-n --grace-period 0 --force
您可以使用以下命令直接删除 Pod:
$ kubectl 删除 pod
然后,使用以下命令检查 pod 的状态:
$ kubectl 获取 pods
在这里,您将看到 Pod 已被删除。
您还可以使用 yaml 文件中的文档进行验证。
大多数程序在收到 SIGTERM 时都会正常关闭,但如果您使用第三方代码或正在管理您无法控制的系统,则 preStop 挂钩是在不修改应用程序的情况下触发正常关闭的好方法。 Kubernetes 将向 pod 中的容器发送 SIGTERM 信号。 此时,Kubernetes 会等待指定的时间,称为终止宽限期。
欲了解更多信息请参阅。
目前 Kubernetes 默认情况下不会删除已驱逐和关闭状态的 pod。我们在我们的环境中也遇到了类似的问题。
作为自动修复,您可以创建一个 Kubernetes cronjob,它可以删除处于已驱逐和关闭状态的 pod。 Kubernetes cronjob pod 可以使用 serviceaccount 和 RBAC 进行身份验证,您可以在其中限制实用程序的动词和命名空间。
您可以使用https://github.com/hjacobs/kube-janitor。这提供了各种可配置的清理选项
我对这个问题的看法看起来像这样(来自其他解决方案的灵感):
# Delete all shutdown pods. This is common problem on kubernetes using preemptible nodes on gke
# why awk, not failed pods: https://github.com/kubernetes/kubernetes/issues/54525#issuecomment-340035375
# due fact failed will delete evicted pods, that will complicate pod troubleshooting
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: del-shutdown-pods
namespace: kube-system
labels:
app: shutdown-pod-cleaner
spec:
schedule: "*/1 * * * *"
successfulJobsHistoryLimit: 1
jobTemplate:
spec:
template:
metadata:
labels:
app: shutdown-pod-cleaner
spec:
volumes:
- name: scripts
configMap:
name: shutdown-pods-scripts
defaultMode: 0777
serviceAccountName: shutdown-pod-sa
containers:
- name: zombie-killer
image: bitnami/kubectl
imagePullPolicy: IfNotPresent
command:
- "/bin/sh"
args:
- "-c"
- "/scripts/podCleaner.sh"
volumeMounts:
- name: scripts
mountPath: "/scripts"
readOnly: true
restartPolicy: OnFailure
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: shutdown-pod-cleaner
namespace: kube-system
labels:
app: shutdown-pod-cleaner
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["delete", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: shutdown-pod-cleaner-cluster
namespace: kube-system
subjects:
- kind: ServiceAccount
name: shutdown-pod-sa
namespace: kube-system
roleRef:
kind: ClusterRole
name: shutdown-pod-cleaner
apiGroup: ""
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: shutdown-pod-sa
namespace: kube-system
labels:
app: shutdown-pod-cleaner
---
apiVersion: v1
kind: ConfigMap
metadata:
name: shutdown-pods-scripts
namespace: kube-system
labels:
app: shutdown-pod-cleaner
data:
podCleaner.sh: |
#!/bin/sh
if [ $(kubectl get pods --all-namespaces --ignore-not-found=true | grep Shutdown | wc -l) -ge 1 ]
then
kubectl get pods -A | grep Shutdown | awk '{print $1,$2}' | xargs -n2 sh -c 'kubectl delete pod -n $0 $1 --ignore-not-found=true'
else
echo "no shutdown pods to clean"
fi
我刚刚设置了一个 cronjob 来清理失效的 GKE Pod。 完整的设置包括 RBAC 角色、角色绑定和服务帐户。
服务帐户和集群角色设置。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-accessor-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "delete", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pod-access
subjects:
- kind: ServiceAccount
name: cronjob-svc
namespace: kube-system
roleRef:
kind: ClusterRole
name: pod-accessor-role
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cronjob-svc
namespace: kube-system
用 Cronjob 来清理死掉的 pod。
apiVersion: batch/v1
kind: CronJob
metadata:
name: pod-cleaner-cron
namespace: kube-system
spec:
schedule: "0 */12 * * *"
successfulJobsHistoryLimit: 1
jobTemplate:
spec:
template:
metadata:
name: pod-cleaner-cron
namespace: kube-system
spec:
serviceAccountName: cronjob-svc
restartPolicy: Never
containers:
- name: pod-cleaner-cron
imagePullPolicy: IfNotPresent
image: bitnami/kubectl
command:
- "/bin/sh"
args:
- "-c"
- "kubectl delete pods --field-selector status.phase=Failed -A --ignore-not-found=true"
status: {}
受到此处讨论的启发,我在 GitHub 上创建了以下 kube-clean 存储库,并在artifacthub.io 上创建了相应的 kube-clean helm 图表,它为每个指定的命名空间生成了
CronJob
。
我就是这样做的。希望它能帮助某人。在一行中运行下面的代码,不带注释。取出不需要的东西或添加以帮助别人。
##Get the pods in the mmi-medic namespace in json format
kubectl get pods -n YOUR_NAMESPACE -o json
## get a certain JSON element in each of the pods
| jq '.items[].status.containerStatuses
##If the pod is standing in false ready status, sign of completed pod
| select(.[].ready == false)
##Only if the pod is in completed status
| select(.[].state.terminated.reason == "Completed")
##Only if pod was created by Kaniko Image builder, lets me know I am deleteing correct pods.
| select(.[].name | test("kaniko")?)
##Set a date that is 24 hours ago. 86400 is how many seconds in 24 hours
| (now - 86400) as $date
##Get the date element we will compare against.
| select((.[].state.terminated.finishedAt
##Get the first chars from value.
| .[:18] + "Z"
##If the finishedAt Date is longer than 24 hours then delete.
| fromdate) < $date)
##Get the name of the POD to send to xargs but raw sends it without the double quotes that jq leaves behind not part of value.
| .[].name ' --raw-output
##Finally if empty dont run xargs otherwise delete the pod by name.
| xargs --no-run-if-empty kubectl -n YOUR_NAMESPACE delete pod
我也在我的 K8s cronjob 模板中使用它作为我的图像
image: bitnami/kubectl