network error怎么解决(K8S常见故障排查指南)

发布时间:2024-12-01 12:22:38

故障排查思维导图


当你在 Kubernetes 中部署应用程序时,通常会定义三个组件:

  • Deployment -- 这是创建应用程序副本的方法。
  • Service -- 将流量路由到 Pod 的内部负载均衡器
  • Ingress -- 流量应如何从集群外部流向您的服务的描述。


排除 Kubernetes 部署故障的 3 个步骤

在深入调试损坏的部署之前,必须对 Kubernetes 的工作原理有一个明确定义。

由于每个部署中都包含三个组件,因此我们应该从底部开始按顺序调试所有组件。

  1. 确保 Pod 正在运行;
  2. 专注于让Service将流量路由到Pod;
  3. 检查 Ingress 配置是否正确;

1. Pod 故障排除

大多数时候,问题出在 Pod 本身上。

我们应该确保Pod Running且Ready。

如何检查?

kubectl get pods
NAME                    READY STATUS            RESTARTS  AGE
app1                    0/1   ImagePullBackOff  0         47h
app2                    0/1   Error             0         47h
app3-76f9fcd46b-xbv4k   1/1   Running           1         47h

在上面的输出中,最后一个 Pod 处于Running且Ready 状态,但是,前两个 Pod 既未Running也未Ready。

如何调查出了什么问题?

有四个有用的命令可用于对 Pod 进行故障排除:

  1. kubectl logs <pod name> 有助于检索Pod容器的日志。
  2. kubectl describe pod <pod name> 对于检索与 Pod 关联的事件列表非常有用。
  3. kubectl get pod <pod name> 对于提取 Kubernetes 中存储的 Pod 的 YAML 定义非常有用。
  4. kubectl exec -ti <pod name> -- bash 对于在 Pod 的容器之内运行交互式命令非常有用。

那我们应该使用哪一个命令呢?

没有一种方法是放之四海而皆准的。

相反,我们应该使用它们的组合。

常见 Pod 错误

Pod 可能会出现启动和运行时错误。

启动错误包括:

  • ImagePullBackoff
  • ImageInspectError
  • ErrImagePull
  • ErrImageNeverPull
  • RegistryUnavailable
  • InvalidImageName

运行时错误包括:

  • CrashLoopBackOff
  • RunContainerError
  • KillContainerError
  • VerifyNonRootError
  • RunInitContainerError
  • CreatePodSandboxError
  • ConfigPodSandboxError
  • KillPodSandboxError
  • SetupNetworkError
  • TeardownNetworkError

有些错误比其他错误更常见。

以下是最常见错误的列表以及如何修复这些错误。

ImagePullBackOff

当 Kubernetes 无法检索Pod的image时,会出现此错误。

常见的原因有以下三个:

  1. image名称无效,例如,拼错了名称,或者image不存在。
  2. 为image指定了一个不存在的tag。
  3. 尝试检索的image属于私有镜像仓库,并且 Kubernetes 没有访问凭据。

前两种情况可以通过更正image名称和tag来解决。

最后,应该将私有镜像的凭据添加到Secret,并在Pod中引用它。

CrashLoopBackOff

如果容器无法启动,Kubernetes 会显示 CrashLoopBackOff作为状态。

通常,容器在以下情况下无法启动:

  1. 应用程序中存在错误,导致其无法启动。
  2. 容器配置错了。
  3. K8S LivenessProbe失败次数过多。

这时,我们应该尝试从该容器日志来检查失败的原因。

如果由于容器重新启动太快而看不到日志,可以使用以下命令,它打印前一个容器的错误消息。

kubectl logs <pod-name> --previous

RunContainerError

当容器无法启动时会出现该错误。

这甚至是在容器内的应用程序启动之前。

该问题通常是由于配置错误造成的,例如:

  • 挂载了不存在的卷,例如 ConfigMap 或 Secrets。
  • 将只读卷挂载为读写。

这时,应该用来kubectl describe pod <pod-name>检查和分析错误。

Pod 处于Pending状态

当创建 Pod 时,Pod 处于Pending状态。

假设调度程序组件运行良好,原因如下:

  1. 集群没有足够的资源(例如 CPU 和内存)来运行 Pod。
  2. 当前Namespace有一个ResourceQuota对象,创建Pod会使Namespace超出配额。
  3. Pod 绑定到Pending PersistentVolumeClaim。

最好的选择是通过以下检查命令,查看Pod事件。

kubectl describe pod <pod name>

对于由于 ResourceQuotas 创建的错误,还可以使用以下命令检查集群的日志:

kubectl get events --sort-by=.metadata.creationTimestamp

Pod 处于Pending状态

如果 Pod 正在Running但Pending中,则意味着ReadinessProbe失败。

ReadinessProbe失败时,Pod 不会加到Service,并且不会将任何流量转发到该实例。

失败的ReadinessProbe是特定于应用程序的错误,因此我们应该使用kubectl describe命令检查事件

2. Services故障排查

如果 Pod 正在Running并Ready,但仍然无法收到应用程序的响应,则应该检查Service是否配置正确。

Service旨在根据 Pod 的label将流量路由到 Pod。

因此,我们应该检查的第一件事是该Service映射了多少个 Pod。

可以通过检查Service的Endpoints来执行此操作:

kubectl describe service my-service
Name:                     my-service
Namespace:                default
Selector:                 app=my-app
IP:                       10.100.194.137
Port:                     <unset>  80/TCP
TargetPort:               8080/TCP
Endpoints:                172.17.0.5:8080

Endpoint是一对<ip address:port>,并且应该至少有一个,当服务以(至少)一个 Pod 为目标时。如果Endpoints为空,则有两种解释:

  1. 没有任何使用正确label运行的 Pod(提示:应该检查是否位于正确的命名空间中)。
  2. Selector中的Service label配置错误。

如果看到Endpoints列表,但仍然无法访问应用程序,那么Service targetPort可能配置错误。

无论Service type是什么,都可以使用以下方式kubectl port-forward访问到。

kubectl port-forward service/<service-name> 3000:80

备注:

  • <service-name>是服务的名称。
  • 3000是应用程序上监听的端口。
  • 80是Service开放的端口。

3. Ingress 故障排查

如果已检查到这部分,那么:

  • Pod 正在Running并Ready。
  • Service 将流量分配给Pod。

但仍然看不到应用程序的响应。

这意味着 Ingress 很可能配置错误。

由于 Ingress 控制器是集群中的第三方组件,因此根据 Ingress 控制器的类型有不同的调试方式。

但在深入了解 Ingress 检查工具之前,我们可以检查一些简单的内容。

Ingress 使用service.name和service.port访问到服务。

我们应该检查这些配置是否正确,还可以检查 Ingress 是否已正确配置:

kubectl describe ingress my-ingress
Name:             my-ingress
Namespace:        default
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /   my-service:80 (<error: endpoints "my-service" not found>)

如果Backend列为空,则配置中一定存在错误。

如果可以在Backend列中看到Endpoint,但仍然无法访问应用程序,则问题可能是:

  • 我们如何将 Ingress 暴露给互联网。
  • 我们如何将集群暴露给互联网。

首先,检查 Ingress 控制器的 Pod(可能位于不同的命名空间中):

kubectl get pods --all-namespaces
NAMESPACE   NAME                              READY STATUS
kube-system coredns-5644d7b6d9-jn7cq          1/1   Running
kube-system etcd-minikube                     1/1   Running
kube-system kube-apiserver-minikube           1/1   Running
kube-system kube-controller-manager-minikube  1/1   Running
kube-system kube-proxy-zvf2h                  1/1   Running
kube-system kube-scheduler-minikube           1/1   Running
kube-system nginx-ingress-controller-6fc5bcc  1/1   Running

通过describe pod检查端口:

kubectl describe pod nginx-ingress-controller-6fc5bcc
 --namespace kube-system \
 | grep Ports
    Ports:         80/TCP, 443/TCP, 8443/TCP
    Host Ports:    80/TCP, 443/TCP, 0/TCP

最后,访问到 Pod:

kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
Forwarding from 127.0.0.1:3000 -> 80
Forwarding from [::1]:3000 -> 80

此时,每次访问计算机上的 3000 端口时,请求都会转发到 Pod 上的 80 端口。

  • 如果是这样,问题就出在宿主机上,我们应该检查流量如何路由到集群。
  • 如果不起作用,则问题出在 Ingress 控制器中,我们应该调试 Ingress。

如果仍然无法让 Ingress 控制器工作,则应该开始调试它。

Ingress 控制器有许多不同版本。

流行的选项包括 Nginx、HAProxy、Traefik 等。

我们应该查阅 Ingress 控制器的文档以查找故障排查指南。

由于Ingress Nginx是最流行的 Ingress 控制器,因此我们在下面中提供了一些技巧。

调试 Ingress Nginx

Ingress-nginx 项目有一个Kubectl 的官方插件。

您可以用来kubectl ingress-nginx:

  • 检查日志、后端、证书等。
  • 访问到 Ingress。
  • 检查当前配置。

我们应该尝试的三个命令是:

  • kubectl ingress-nginx lint,检查nginx.conf.
  • kubectl ingress-nginx backend,检查后端(类似于kubectl describe ingress <ingress-name>)。
  • kubectl ingress-nginx logs,检查日志。

请注意,您可能需要使用 为 Ingress 控制器指定正确的命名空间--namespace <name>。

故障排查总结

如果我们不知道从哪里开始,在 Kubernetes 中进行故障排除可能是一项艰巨的任务。

我们应该始终记住自下而上地解决问题:从 Pod 开始,然后通过 Service 和 Ingress 向上排查。

在本文中学到的相同调试技术可以应用于其他对象,例如:

  • 异常的Jobs 和 CronJobs。
  • StatefulSet 和 DaemonSet。