Kubernetes 排错指南之云平台异常

网友投稿 937 2022-11-01

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

Kubernetes 排错指南之云平台异常

本文介绍在公有云中运行 Kubernetes 时可能会碰到的问题以及解决方法。

在公有云平台上运行 Kubernetes,一般可以使用云平台提供的托管 Kubernetes 服务(比如 Google 的 GKE、微软 Azure 的 AKS 或者 AWS 的 Amazon EKS 等)。当然,为了更自由的灵活性,也可以直接在这些公有云平台的虚拟机中部署 Kubernetes。无论哪种方法,一般都需要给 Kubernetes 配置 Cloud Provider 选项,以方便直接利用云平台提供的高级网络、持久化存储以及安全控制等功能。

而在云平台中运行 Kubernetes 的常见问题有

认证授权问题:比如 Kubernetes Cloud Provider 中配置的认证方式无权操作虚拟机所在的网络或持久化存储。这一般从 kube-controller-manager 的日志中很容易发现。网络路由配置失败:正常情况下,Cloud Provider 会为每个 Node 配置一条 PodCIDR 至 NodeIP 的路由规则,如果这些规则有问题就会导致多主机 Pod 相互访问的问题。公网 IP 分配失败:比如 LoadBalancer 类型的 Service 无法分配公网 IP 或者指定的公网 IP 无法使用。这一版也是配置错误导致的。安全组配置失败:比如无法为 Service 创建安全组(如超出配额等)或与已有的安全组冲突等。持久化存储分配或者挂载问题:比如分配 PV 失败(如超出配额、配置错误等)或挂载到虚拟机失败(比如 PV 正被其他异常 Pod 引用而导致无法从旧的虚拟机中卸载)。网络插件使用不当:比如网络插件使用了云平台不支持的网络协议等。

下面以 Azure 为例介绍云平台相关异常的排错方法。

Node 未注册到集群中

通常,在 Kubelet 启动时会自动将自己注册到 kubernetes 集群  中,然后通过 kubectl get nodes 就可以查询到该节点。 如果新的 Node 没有自动注册到 Kubernetes 集群中,那说明这个注册过程有错误发生,需要检查 kubelet 和 kube-controller-manager 的日志,进而再根据日志查找具体的错误原因。

Kubelet 日志

查看 Kubelet 日志需要首先 SSH 登录到 Node 上,然后运行 journalctl命令查看 kubelet 的日志:

journalctl -l -u kubelet

kube-controller-manager 日志

kube-controller-manager 会自动在云平台中给 Node 创建路由,如果路由创建创建失败也有可能导致 Node 注册失败。

PODNAME=$(kubectl -n kube-system get pod -l component=kube-controller-manager -o jsonpath='{.items[0].metadata.name}')kubectl -n kube-system logs $PODNAME --tail 100

LoadBalancer Service 一直处于 pending 状态

查看 Service kubectl describe service  没有错误信息,但 EXTERNAL-IP 一直是 ,说明 Azure Cloud Provider 在创建 LB/NSG/PublicIP 过程中出错。一般按照前面的步骤查看 kube-controller-manager 可以查到具体失败的原因,可能的因素包括

clientId、clientSecret、tenandId 或 subscriptionId 配置错误导致 Azure API 认证失败:更新所有节点的 /etc/kubernetes/azure.json,修复错误的配置即可恢复服务配置的客户端无权管理 LB/NSG/PublicIP/VM:可以为使用的 clientId 增加授权或创建新的 az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions//resourceGroups/"Kuberentes v1.8.X 中还有可能出现 Security rule must specify SourceAddressPrefixes, SourceAddressPrefix, or SourceApplicationSecurityGroups 的错误,这是由于 Azure Go SDK 的问题导致的,可以通过升级集群到 v1.9.X/v1.10.X 或者将 SourceAddressPrefixes 替换为多条 SourceAddressPrefix 规则来解决

负载均衡公网 IP 无法访问

Azure Cloud Provider 会为负载均衡器创建探测器,只有探测正常的服务才可以响应用户的请求。负载均衡公网 IP 无法访问一般是探测失败导致的,可能原因有:

后端 VM 本身不正常(可以重启 VM 恢复)后端容器未监听在设置的端口上(可通过配置正确的端口解决)防火墙或网络安全组阻止了要访问的端口(可通过增加安全规则解决)当使用内网负载均衡时,从同一个 ILB 的后端 VM 上访问 ILB VIP 时也会失败,这是 Azure 的预期行为(此时可以访问 service 的 clusterIP)后端容器不响应(部分或者全部)外部请求时也会导致负载均衡 IP 无法访问。注意这里包含部分容器不响应的场景,这是由于 Azure 探测器与 Kubernetes 服务发现机制共同导致的结果:(1)Azure 探测器定期去访问 service 的端口(即 NodeIP:NodePort)(2)Kubernetes 将其负载均衡到后端容器中(3)当负载均衡到异常容器时,访问失败会导致探测失败,进而 Azure 可能会将 VM 移出负载均衡该问题的解决方法是使用健康探针,保证异常容器自动从服务的后端(endpoints)中删除。

内网负载均衡 BackendPool 为空

Kubernetes 1.9.0-1.9.3 中会有这个问题(kubernetes#59746kubernetes#60060 acs-engine#2151),这是由于一个查找负载均衡所属 AvaibilitySet 的缺陷导致的。

该问题的修复(kubernetes#59747 kubernetes#59083)将包含到 v1.9.4 和 v1.10 中。

外网负载均衡均衡 BackendPool 为空

在使用不支持 Cloud Provider 的工具(如 kubeadm)部署的集群中,如果未给 Kubelet 配置 --cloud-provider=azure --cloud-config=/etc/kubernetes/cloud-config,那么 Kubelet 会以 hostname 将其注册到集群中。此时,查看该 Node 的信息(kubectl get node -o yaml),可以发现其 externalID 与 hostname 相同。此时,kube-controller-manager 也无法将其加入到负载均衡的后端中。

一个简单的确认方式是查看 Node 的 externalID 和 name 是否不同:

$ kubectl get node -o jsonpath='{.items[*].metadata.name}'k8s-agentpool1-27347916-0$ kubectl get node -o jsonpath='{.items[*].spec.externalID}'/subscriptions//resourceGroups//providers/Microsoft.Compute/virtualMachines/k8s-agentpool1-27347916-0

该问题的解决方法是先删除 Node kubectl delete node ,为 Kubelet 配置 --cloud-provider=azure --cloud-config=/etc/kubernetes/cloud-config,最后再重启 Kubelet。

Service 删除后 Azure 公网 IP 未自动删除

Kubernetes 1.9.0-1.9.3 中会有这个问题(kubernetes#59255):当创建超过 10 个 LoadBalancer Service 后有可能会碰到由于超过 FrontendIPConfiguations Quota(默认为 10)导致负载均衡无法创建的错误。此时虽然负载均衡无法创建,但公网 IP 已经创建成功了,由于 Cloud Provider 的缺陷导致删除 Service 后公网 IP 却未删除。

另外,超过 FrontendIPConfiguations Quota 的问题可以参考 Azure subscription and service limits, quotas, and constraints 增加 Quota 来解决。

Azure API 调用请求过多

有时 kube-controller-manager 或者 kubelet 会因请求调用过多而导致 Azure API 调用失败的情况,比如

"OperationNotAllowed",\r\n    "message": "The server rejected the request because too many requests have been received for this subscription.

特别是在 Kubernetes 集群创建或者批量增加 Nodes 的时候。从 v1.9.2 和 v1.10 开始, Azure cloud provider 为一些列的 Azure 资源(如 VM、VMSS、安全组和路由表等)增加了缓存,大大缓解了这个问题。

一般来说,如果该问题重复出现可以考虑

使用 Azure instance metadata,即为所有 Node 的 /etc/kubernetes/azure.json 设置 "useInstanceMetadata": true 并重启 kubelet为 kube-controller-manager 增大 --route-reconciliation-period(默认为 10s),比如在 /etc/kubernetes/manifests/kube-controller-manager.yaml 中设置 --route-reconciliation-period=1m 后 kubelet 会自动重新创建 kube-controller-manager Pod。

AKS kubectl logs connection timed out

kubectl logs 命令报 getsockopt: connection timed out 的错误(AKS#232):

$ kubectl --v=8 logs xI0308 10:32:21.539580   26486 round_trippers.go:417] curl -k -v -XGET  -H "Accept: application/json, */*" -H "User-Agent: kubectl/v1.8.1 (linux/amd64) kubernetes/f38e43b" -H "Authorization: Bearer x" https://x:443/api/v1/namespaces/default/pods/x/log?container=xI0308 10:34:32.790295   26486 round_trippers.go:436] GET https://X:443/api/v1/namespaces/default/pods/x/log?container=x 500 Internal Server Error in 131250 millisecondsI0308 10:34:32.790356   26486 round_trippers.go:442] Response Headers:I0308 10:34:32.790376   26486 round_trippers.go:445]     Content-Type: application/jsonI0308 10:34:32.790390   26486 round_trippers.go:445]     Content-Length: 275I0308 10:34:32.790414   26486 round_trippers.go:445]     Date: Thu, 08 Mar 2018 09:34:32 GMTI0308 10:34:32.790504   26486 request.go:836] Response Body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Get https://aks-nodepool1-53392281-1:10250/containerLogs/default/x: dial tcp 10.240.0.6:10250: getsockopt: connection timed out","code":500}I0308 10:34:32.790999   26486 helpers.go:207] server response object: [{  "metadata": {},  "status": "Failure",  "message": "Get https://aks-nodepool1-53392281-1:10250/containerLogs/default/x/x: dial tcp 10.240.0.6:10250: getsockopt: connection timed out",  "code": 500}]F0308 10:34:32.791043   26486 helpers.go:120] Error from server: Get https://aks-nodepool1-53392281-1:10250/containerLogs/default/x/x: dial tcp 10.240.0.6:10250: getsockopt: connection timed out

在 AKS 中,kubectl logs, exec, and attach 等命令需要 Master 与 Nodes 节点之间建立隧道连接。在 kube-system namespace 中可以看到 tunnelfront 和 kube-svc-redirect Pod:

$ kubectl -n kube-system get po -l component=tunnelNAME                           READY     STATUS    RESTARTS   AGEtunnelfront-7644cd56b7-l5jmc   1/1       Running   0          2d$ kubectl -n kube-system get po -l component=kube-svc-redirectNAME                      READY     STATUS    RESTARTS   AGEkube-svc-redirect-pq6kf   1/1       Running   0          2dkube-svc-redirect-x6sq5   1/1       Running   0          2dkube-svc-redirect-zjl7x   1/1       Running   1          2d

如果它们不是处于 Running 状态或者 Exec/Logs/PortForward 等命令报 net/http: TLS handshake timeout 错误,删除 tunnelfront Pod,稍等一会就会自动创建新的出来,如:

$ kubectl -n kube-system delete po -l component=tunnelpod "tunnelfront-7644cd56b7-l5jmc" deleted

使用 Virtual Kubelet 后 LoadBalancer Service 无法分配公网 IP

使用 Virtual Kubelet 后,LoadBalancer Service 可能会一直处于 pending 状态,无法分配 IP 地址。查看该服务的事件(如 kubectl describe svc)会发现错误 CreatingLoadBalancerFailed 4m (x15 over 45m) service-controller Error creating load balancer (will retry): failed to ensure load balancer for service default/nginx: ensure(default/nginx): lb(kubernetes) - failed to ensure host in pool: "instance not found"。这是由于 Virtual Kubelet 创建的虚拟 Node 并不存在于 Azure 云平台中,因而无法将其加入到 Azure Load Balancer 的后端中。

解决方法是开启 ServiceNodeExclusion 特性,即设置 kube-controller-manager --feature-gates=ServiceNodeExclusion=true。开启后,所有带有 alpha.service-controller.kubernetes.io/exclude-balancer 标签的 Node 都不会加入到云平台负载均衡的后端中。

注意该特性仅适用于 Kubernetes 1.9 及以上版本。

上一篇:【中培课堂】浅论HTML5对移动互联网领域的影响
下一篇:【中培课堂】详解软件功能测试的相关流程
相关文章

 发表评论

暂时没有评论,来抢沙发吧~