后端服务恰好在负载平衡器的运行状况检查路径上返回状态404。当我浏览到负载均衡器的域名时,我会得到"错误:服务器错误/服务器遇到临时错误",日志显示
"type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
statusDetails: "failed_to_pick_backend"
,这是有意义的。
当我浏览到负载均衡器的静态IP时,我的浏览器会显示底层Kubernetes Pod返回的404错误消息,换句话说,尽管健康检查失败,负载均衡器还是传递了请求。
为什么这两种不同的行为?
[编辑]
以下是创建负载均衡器的Ingress的yaml:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress1
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: myservice
servicePort: 80
我对此进行了"深入研究",并设法在我的GKE集群上重现了这种情况,所以现在我可以看出这里有一些东西。
后端服务恰好在负载平衡器的运行状况检查路径上返回状态404。
可能有两个选项(从您提供的描述中不清楚)。
- 类似于:">错误:服务器错误服务器遇到临时错误,无法完成您的请求。请在30秒内重试。">
这是您从LoadBalancer获得的,以防pod的HealthCheck失败。GKE Ingress对象的官方文件显示
通过Ingress公开的服务必须响应负载平衡器的运行状况检查。
任何作为负载平衡流量最终目的地的容器都必须执行以下操作之一以表明其健康:
为
/
路径上的GET请求提供HTTP 200状态的响应。配置HTTP就绪探测。为就绪探测指定的
path
上的GET请求提供HTTP 200状态的响应。通过Ingress暴露的服务必须指向启用就绪探测的同一容器端口。
需要修复HealthCheck处理。您可以访问GCP控制台-网络服务-负载平衡来检查负载平衡器的详细信息。
- ">404未找到--nginx/1.17.6">
这一点很清楚。这是端点myservice
向其发送请求时返回的响应。看起来有什么配置错误。我的猜测是pod只是不能正确地满足这个请求。可能是nginx网络服务器问题等。请检查配置,找出pod无法满足请求的原因。
在玩设置的时候,我发现了一个图像,可以让你检查请求是否已经到达pod和请求头。
因此可以创建一个类似的吊舱
apiVersion: v1
kind: Pod
metadata:
annotations:
run: fake-web
name: fake-default-knp
# namespace: kube-system
spec:
containers:
- image: mendhak/http-https-echo
imagePullPolicy: IfNotPresent
name: fake-web
ports:
- containerPort: 8080
protocol: TCP
以便能够查看传入请求中的所有标头(kubectl logs -f fake-default-knp
)。
当我浏览到负载均衡器的静态IP时,我的浏览器会显示底层Kubernetes Pod返回的404错误消息。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress1
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: myservice
servicePort: 80
创建这样一个Ingress对象后,GKE集群中将至少有2个后端。-创建Ingress时指定的后端(myservice
一个)-默认的一个(在创建集群时创建)。
kubectl get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP
l7-default-backend-xyz 1/1 Running 0 20d 10.52.0.7
请注意,myservice
仅为将Host
标头设置为example.com
的请求提供服务。其余的请求被发送到"默认后端"。这就是您在浏览LoadBalancer的IP地址时收到"默认后端-404"错误消息的原因。
从技术上讲,存在将l7-default-backend-xyz
作为端点的default-http-backend
服务。
kubectl get svc -n kube-system -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
default-http-backend NodePort 10.0.6.134 <none> 80:31806/TCP 20d k8s-app=glbc
kubectl get ep -n kube-system
NAME ENDPOINTS AGE
default-http-backend 10.52.0.7:8080 20d
同样,对于"Host"标头不等于您在Ingress中指定的标头的请求,这是返回"默认后端-404"错误的"对象"。
希望它能阐明这个问题:)
编辑:
myservice只为主机头设置为example.com的请求提供服务。"所以你的意思是,只有当有主机头时,请求才会进入LB?
不完全是。LB接收所有请求,并根据"Host"头值传递请求。具有example.com
主机标头的请求将在myservice
后端提供服务。
简单地说,逻辑如下:
- 请求到达
- 系统检查主机头(以确定用户的后端)
- 如果有合适的用户后端(根据Ingress配置)并且该后端正常,则会发出请求,否则">错误:服务器错误服务器遇到临时错误,无法完成您的请求。请在30秒内重试。"如果后端处于非正常状态,则会引发
- 如果请求的
Host
标头与Ingress规范中的任何主机都不匹配,则将请求发送到l7-default-backend-xyz
后端(不是Ingress配置中提到的那个)。该后端回复为:"defaultbackend-404"错误
希望这能说明问题。