k8s worker 节点关机 sts 管理的 pod 无法迁移

背景

1.28.2 版本 k8s 中的一台 worker 节点内存异常,需要关机换内存,正好可以测试一下 pod 的迁移。

发现

deployment 管理的 pod 是能够重新创建飘到其他节点上的,但是 statefulset 管理的 pod 一直处于 Terminating 状态无法迁移,pod 就一直无法提供服务。官方文档中解释如下:

当某节点关闭但 kubelet 的节点关闭管理器未检测到这一事件时, 在那个已关闭节点上、属于 StatefulSet 的 Pod 将停滞于终止状态,并且不能移动到新的运行节点上。 这是因为已关闭节点上的 kubelet 已不存在,亦无法删除 Pod, 因此 StatefulSet 无法创建同名的新 Pod。 如果 Pod 使用了卷,则 VolumeAttachments 不会从原来的已关闭节点上删除, 因此这些 Pod 所使用的卷也无法挂接到新的运行节点上。 所以,那些以 StatefulSet 形式运行的应用无法正常工作。 如果原来的已关闭节点被恢复,kubelet 将删除 Pod,新的 Pod 将被在不同的运行节点上创建。 如果原来的已关闭节点没有被恢复,那些在已关闭节点上的 Pod 将永远滞留在终止状态

解决办法

官方提供的解决办法是给该节点添加一个 NoExecute 的污点。尝试发现并不行,而且 node 长期处于 NotReady,node control 会给该节点自动添加 NOExecute 的污点。

有尝试过升级 k8s 版本到 1.31.1,发现也并不行。

后续搜索发现可以强制删除节点上的 pod,原理是强制删除不需要等待该节点上的 kubelet 的响应。

bash 复制代码
kubectl delete pod "pod_name" -n "namespace" --grace-period=0 --force

我们可以创建 deployment 来定时查找长期处于 Terminating 状态的 pod,或者说是 cronJob。

编写查询并删除 pod 的脚本 configmap:

bash 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: delete-terminating-pods-script
  namespace: ops  
data:
  delete_terminating_pods.sh: |
    #!/bin/bash

    temp_file="/tmp/terminating_pods.txt"
    > "$temp_file"
    while true; do
        kubectl get pod -A | grep Terminating | awk '{print $1,$2}' > "$temp_file"
        sleep 60

        kubectl get pod -A | grep Terminating | awk '{print $1,$2}'| while read namespace pod_name; do
            if grep -q "$namespace $pod_name" "$temp_file"; then  #避免删除优雅退出的 pod
                kubectl delete pod "$pod_name" -n "$namespace" --grace-period=0 --force
            fi
        done

        > "$temp_file"
        sleep 60
    done

创建一个 ServiceAccount 并给予权限

bash 复制代码
apiVersion: v1
kind: ServiceAccount
metadata:
  name: delete-terminating-pods-sa
  namespace: ops
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-deleter
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: delete-terminating-pods-crb
subjects:
- kind: ServiceAccount
  name: delete-terminating-pods-sa
  namespace: ops
roleRef:
  kind: ClusterRole
  name: pod-deleter
  apiGroup: rbac.authorization.k8s.io

编写一个 deployment,kubectl 的版本与自己集群版本相同即可

bash 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubectl
  namespace: ops
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kubectl
  template:
    metadata:
      labels:
        app: kubectl
    spec:
      serviceAccountName: delete-terminating-pods-sa
      containers:
        - name: kubectl-container
          image: bitnami/kubectl:1.31.1
          command: ["/bin/bash", "/scripts/delete_terminating_pods.sh"]
          volumeMounts:
          - name: script-volume
            mountPath: /scripts
      volumes:
      - name: script-volume
        configMap:
          name: delete-terminating-pods-script

到此就可以自动发现并删除 节点意外情况 sts 管理的 pod 了,有更好的办法评论区可以留言。

相关推荐
工业一体机老司机4 小时前
Docker部署工控机采集服务 Compose编排与开机自启
运维·docker·容器
miaobinfei10 小时前
docker拉取dify镜像,执行docker compose up -d 报错
运维·docker·容器
kobe_OKOK_11 小时前
docker compose命名卷 映射到宿主机的路径
运维·docker·容器
无言听风雨丶12 小时前
Linux 容器本质探秘:Cgroup 与 Namespace 深度解析与实战
linux·运维·服务器·kubernetes
晨陌y16 小时前
Flare自托管导航页教程:Docker部署、多用户、API与公网访问
运维·docker·容器
无言听风雨丶16 小时前
Kubernetes GitOps 持续交付实战:用 Argo CD 让 Git 成为集群事实源
git·elasticsearch·kubernetes
梅孔立18 小时前
Docker 容器网络不通:Tomcat 无法解析 MySQL、Nginx 无法反代 Tomcat 的生产级排查与治理
网络·docker·tomcat
无言听风雨丶1 天前
Kubernetes 控制平面深度剖析:从 kubectl apply 到 etcd 写入的全链路
平面·kubernetes·etcd
openFuyao1 天前
openFuyao x 复旦大学软件工程实验室 Panel 回顾:Agentic时代,集群调度技术体系将如何演进?
kubernetes·openfuyao
螺蛳粉 螺蛳粉1 天前
第 05 篇:etcd 深入:Raft 共识、watch 机制与快照备份恢复实战(底座认知 05)
docker·云原生·容器·kubernetes·etcd·分布式存储·kube-apiserver