集群状态报错

1、k8s集群中,有pod出现了 Pending ,通过 kubectl describe pod 命令,发现了如下报错
0/4 nodes are available: 1 node(s) had taint {node.kubernetes.io/disk-pressure: }, that the pod didn’t tolerate, 3 node(s) didn’t match node selector.

取消所有节点的 node.kubernetes.io/disk-pressure

kubectl taint nodes --all node.kubernetes.io/disk-pressure-

查看指定窗口日志

error: a container name must be specified for pod *, choose one of: [] or one of the init containers: []
一个pod中启用了多个容器,从此查看日志时需要指定查看该pod的哪个容器,可通过命令 -c <container_name> 指定

kubectl logs $podname -c containerName --tail 100

Node 存储空间不足

sudo docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v /etc:/etc:ro spotify/docker-gc

执行下面的命令来查看占用空间最多的镜像(按镜像大小由大到小排序):
sudo docker images --format '{{.Size}}\t{{.Repository}}:{{.Tag}}\t{{.ID}}' | sort -h -r | column -t

/sys/fs/cgroup 空间不足

很多发行版默认的 fs.inotify.max_user_watches 太小,只有 8192,可以通过增大该配置解决。比如

$ sudo sysctl fs.inotify.max_user_watches=52428

Pod 异常排错

一般来说,无论 Pod 处于什么异常状态,都可以执行以下命令来查看 Pod 的状态

kubectl get pod <pod-name> -o yaml 查看 Pod 的配置是否正确
kubectl describe pod <pod-name> 查看 Pod 的事件
kubectl logs <pod-name> [-c <container-name>] 查看容器日志

这些事件和日志通常都会有助于排查 Pod 发生的问题。

Pod 一直处于 Pending 状态

Warning FailedScheduling 12s (x6 over 27s) default-scheduler 0/4 nodes are available: 2 Insufficient cpu.
可能的原因包括

  • 资源不足,集群内所有的 Node 都不满足该 Pod 请求的 CPU、内存、GPU 或者临时存储空间等资源。解决方法是删除集群内不用的 Pod 或者增加新的 Node。
  • HostPort 端口已被占用,通常推荐使用 Service 对外开放服务端口

Pod 一直处于 Waiting 或 ContainerCreating 状态

首先还是通过 kubectl describe pod <pod-name> 命令查看到当前 Pod 的事件

$ kubectl -n kube-system describe pod nginx-pod
Events:
  Type     Reason                 Age               From               Message
  ----     ------                 ----              ----               -------
  Normal   Scheduled              1m                default-scheduler  Successfully assigned nginx-pod to node1
  Normal   SuccessfulMountVolume  1m                kubelet, gpu13     MountVolume.SetUp succeeded for volume "config-volume"
  Normal   SuccessfulMountVolume  1m                kubelet, gpu13     MountVolume.SetUp succeeded for volume "coredns-token-sxdmc"
  Warning  FailedSync             2s (x4 over 46s)  kubelet, gpu13     Error syncing pod
  Normal   SandboxChanged         1s (x4 over 46s)  kubelet, gpu13     Pod sandbox changed, it will be killed and re-created.

可以发现,该 Pod 的 Sandbox 容器无法正常启动,具体原因需要查看 Kubelet 日志:

$ journalctl -u kubelet
...
Mar 14 04:22:04 node1 kubelet[29801]: E0314 04:22:04.649912   29801 cni.go:294] Error adding network: failed to set bridge addr: "cni0" already has an IP address different from 10.244.4.1/24
Mar 14 04:22:04 node1 kubelet[29801]: E0314 04:22:04.649941   29801 cni.go:243] Error while adding to cni network: failed to set bridge addr: "cni0" already has an IP address different from 10.244.4.1/24
Mar 14 04:22:04 node1 kubelet[29801]: W0314 04:22:04.891337   29801 cni.go:258] CNI failed to retrieve network namespace path: Cannot find network namespace for the terminated container "c4fd616cde0e7052c240173541b8543f746e75c17744872aa04fe06f52b5141c"
Mar 14 04:22:05 node1 kubelet[29801]: E0314 04:22:05.965801   29801 remote_runtime.go:91] RunPodSandbox from runtime service failed: rpc error: code = 2 desc = NetworkPlugin cni failed to set up pod "nginx-pod" network: failed to set bridge addr: "cni0" already has an IP address different from 10.244.4.1/24

发现是 cni0 网桥配置了一个不同网段的 IP 地址导致,删除该网桥(网络插件会自动重新创建)即可修复

$ ip link set cni0 down
$ brctl delbr cni0
镜像拉取失败,比如
配置了错误的镜像
Kubelet 无法访问镜像(国内环境访问 gcr.io 需要特殊处理)
私有镜像的密钥配置错误
镜像太大,拉取超时(可以适当调整 kubelet 的 --image-pull-progress-deadline 和 --runtime-request-timeout 选项)
CNI 网络错误,一般需要检查 CNI 网络插件的配置,比如
无法配置 Pod 网络
无法分配 IP 地址
容器无法启动,需要检查是否打包了正确的镜像或者是否配置了正确的容器参数

Pod 处于 ImagePullBackOff 状态

这通常是镜像名称配置错误或者私有镜像的密钥配置错误导致。这种情况可以使用 docker pull <image> 来验证镜像是否可以正常拉取。

如果是私有镜像,需要首先创建一个 docker-registry 类型的 Secret

kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL

然后在容器中引用这个 Secret

spec:
  containers:
  - name: private-reg-container
    image: <your-private-image>
  imagePullSecrets:
  - name: my-secret

Pod 一直处于 CrashLoopBackOff 状态

CrashLoopBackOff 状态说明容器曾经启动了,但又异常退出了。此时 Pod 的 RestartCounts 通常是大于 0 的,可以先查看一下容器的日志

kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl logs --previous <pod-name>

这里可以发现一些容器退出的原因,比如

  • 容器进程退出
  • 健康检查失败退出
  • OOMKilled

Pod 处于 Error 状态

通常处于 Error 状态说明 Pod 启动过程中发生了错误。常见的原因包括

  • 依赖的 ConfigMap、Secret 或者 PV 等不存在
  • 请求的资源超过了管理员设置的限制,比如超过了 LimitRange 等
  • 违反集群的安全策略,比如违反了 PodSecurityPolicy 等
  • 容器无权操作集群内的资源,比如开启 RBAC 后,需要为 ServiceAccount 配置角色绑定

Pod 处于 Terminating 或 Unknown 状态

从 v1.5 开始,Kubernetes 不会因为 Node 失联而删除其上正在运行的 Pod,而是将其标记为 Terminating 或 Unknown 状态。想要删除这些状态的 Pod 有三种方法:

-   从集群中删除该 Node。使用公有云时,kube-controller-manager 会在 VM 删除后自动删除对应的 Node。而在物理机部署的集群中,需要管理员手动删除 Node(如 `kubectl delete node <node-name>`。
-   Node 恢复正常。Kubelet 会重新跟 kube-apiserver 通信确认这些 Pod 的期待状态,进而再决定删除或者继续运行这些 Pod。
-   用户强制删除。用户可以执行 `kubectl delete pods <pod> --grace-period=0 --force` 强制删除 Pod。除非明确知道 Pod 的确处于停止状态(比如 Node 所在 VM 或物理机已经关机),否则不建议使用该方法。特别是 StatefulSet 管理的 Pod,强制删除容易导致脑裂或者数据丢失等问题。

处于 `Terminating` 状态的 Pod 在 Kubelet 恢复正常运行后一般会自动删除。但有时也会出现无法删除的情况,并且通过 `kubectl delete pods <pod> --grace-period=0 --force` 也无法强制删除。此时一般是由于 `finalizers` 导致的,通过 `kubectl edit` 将 finalizers 删除即可解决。
"finalizers": [
  "foregroundDeletion"
]

Namespace 一直处于 terminating 状态

Namespace 一直处于 terminating 状态,一般有两种原因:

  • Namespace 中还有资源正在删除中
  • Namespace 的 Finalizer 未正常清理

对第一个问题,可以执行下面的命令来查询所有的资源

kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --ignore-not-found -n $NAMESPACE

而第二个问题则需要手动清理 Namespace 的 Finalizer 列表:

kubectl get namespaces $NAMESPACE -o json | jq '.spec.finalizers=[]' > /tmp/ns.json
kubectl proxy &
curl -k -H "Content-Type: application/json" -X PUT --data-binary @/tmp/ns.json http://127.0.0.1:8001/api/v1/namespaces/$NAMESPACE/finalize

排错图解

b0862c5c0f1e7a6db8145f7970dd9601.png

网络异常排错

说到 Kubernetes 的网络,其实无非就是以下三种情况之一

  • Pod 访问容器外部网络
  • 从容器外部访问 Pod 网络
  • Pod 之间相互访问

Flannel Pods 一直处于 Init:CrashLoopBackOff 状态

Flannel 网络插件非常容易部署,只要一条命令即可

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

kubelet启动失败

是kubelet cgroup驱动程序“ cgroupfs”与docker cgroup驱动程序不同

docker info|grep Driver #查看docker cgroup驱动

修改/etc/docker/daemon.json文件

{
  "exec-opts": ["native.cgroupdriver=systemd"]
}


systemctl daemon-reload
systemctl restart docker

标签: none

添加新评论