【发布时间】:2021-01-10 01:45:12
【问题描述】:
这个问题是关于我无法使用 Istio 入口网关将 gRPC 客户端连接到托管在 Kubernetes (AWS EKS) 中的 gRPC 服务。
在 kubernetes 方面: 我有一个容器,其中有一个 Go 进程在端口 8081 上侦听 gRPC。端口暴露在容器级别。我定义了一个 kubernetes 服务并公开了 8081。我定义了一个 istio 网关,它选择 istio: ingressgateway 并为 gRPC 打开端口 8081。最后,我定义了一个 istio 虚拟服务,它为端口 8081 上的任何东西提供了一个路由。
在客户端:我有一个可以向服务发送 gRPC 请求的 Go 客户端。
- 当我
kubectl port-forward -n mynamespace service/myservice 8081:8081并通过client -url localhost:8081致电我的客户时,它工作正常。 - 当我关闭端口转发并使用
client -url [redacted]-[redacted].us-west-2.elb.amazonaws.com:8081调用时,我的客户端无法连接。 (该 url 是kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'的输出,并附加了:8081。
日志:
- 我查看了
istio-system/istio-ingressgateway服务日志。我没有看到尝试的连接。 - 我确实看到了我之前在查看 istio bookinfo 教程时建立的 bookinfo 连接。该教程有效,我能够打开浏览器并查看 bookinfo 产品页面,并且 ingressgateway 日志显示
"GET /productpage HTTP/1.1" 200。所以 Istio 入口网关可以工作,只是我不知道如何为新的 gRPC 端点配置它。
Istio 的入口网关
kubectl describe service -n istio-system istio-ingressgateway
输出以下内容,我怀疑这是问题所在,尽管我努力打开它,但端口 8081 并未列出。我对默认打开了多少端口感到困惑,我没有打开它们(欢迎 cmets 关于如何关闭我不使用的端口,但这不是这个 SO 问题的原因)
Name: istio-ingressgateway
Namespace: istio-system
Labels: [redacted]
Annotations: [redacted]
Selector: app=istio-ingressgateway,istio=ingressgateway
Type: LoadBalancer
IP: [redacted]
LoadBalancer Ingress: [redacted]
Port: status-port 15021/TCP
TargetPort: 15021/TCP
NodePort: status-port 31125/TCP
Endpoints: 192.168.101.136:15021
Port: http2 80/TCP
TargetPort: 8080/TCP
NodePort: http2 30717/TCP
Endpoints: 192.168.101.136:8080
Port: https 443/TCP
TargetPort: 8443/TCP
NodePort: https 31317/TCP
Endpoints: 192.168.101.136:8443
Port: tcp 31400/TCP
TargetPort: 31400/TCP
NodePort: tcp 31102/TCP
Endpoints: 192.168.101.136:31400
Port: tls 15443/TCP
TargetPort: 15443/TCP
NodePort: tls 30206/TCP
Endpoints: 192.168.101.136:15443
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
所以我认为我没有为 GRPC 正确打开端口 8081。我可以运行哪些其他日志或测试来帮助确定其来源?
这里是相关的yaml:
Kubernetes Istio 虚拟服务:其意图是将端口 8081 上的任何内容路由到 myservice
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myservice
namespace: mynamespace
spec:
hosts:
- "*"
gateways:
- myservice
http:
- match:
- port: 8081
route:
- destination:
host: myservice
Kubernetes Istio 网关:其目的是为 GRPC 开放 8081 端口
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: myservice
namespace: mynamespace
spec:
selector:
istio: ingressgateway
servers:
- name: myservice-plaintext
port:
number: 8081
name: grpc-svc-plaintext
protocol: GRPC
hosts:
- "*"
Kubernetes 服务:显示端口 8081 在服务级别暴露,我通过前面提到的端口转发测试确认了这一点
apiVersion: v1
kind: Service
metadata:
name: myservice
namespace: mynamespace
labels:
app: myservice
spec:
selector:
app: myservice
ports:
- protocol: TCP
port: 8081
targetPort: 8081
name: grpc-svc-plaintext
Kubernetes 部署:显示端口 8081 在容器级别暴露,我通过前面提到的端口转发测试确认了这一点
apiVersion: apps/v1
kind: Deployment
metadata:
name: myservice
namespace: mynamespace
labels:
app: myservice
spec:
replicas: 1
selector:
matchLabels:
app: myservice
template:
metadata:
labels:
app: myservice
spec:
containers:
- name: myservice
image: [redacted]
ports:
- containerPort: 8081
重新检查客户端上的 DNS 工作:
getent hosts [redacted]-[redacted].us-west-2.elb.amazonaws.com
输出 3 个 IP,我认为这很好。
[IP_1 redacted] [redacted]-[redacted].us-west-2.elb.amazonaws.com
[IP_2 redacted] [redacted]-[redacted].us-west-2.elb.amazonaws.com
[IP_3 redacted] [redacted]-[redacted].us-west-2.elb.amazonaws.com
检查 Istio Ingressgateway 的路由:
istioctl proxy-status istio-ingressgateway-[pod name]
istioctl proxy-config routes istio-ingressgateway-[pod name]
返回
Clusters Match
Listeners Match
Routes Match (RDS last loaded at Wed, 23 Sep 2020 13:59:41)
NOTE: This output only contains routes loaded via RDS.
NAME DOMAINS MATCH VIRTUAL SERVICE
http.8081 * /* myservice.mynamespace
* /healthz/ready*
* /stats/prometheus*
端口 8081 被路由到 myservice.mynamespace,对我来说似乎不错。
更新 1: 我开始明白我无法使用默认的 istio 入口网关打开端口 8081。该服务不公开该端口,我假设创建网关会“在后台”更新服务,但事实并非如此。 我可以选择的外部端口是:80、443、31400、15443、15021,我认为我的网关只需要依赖这些。我已经更新了我的网关和虚拟服务以使用端口 80,然后客户端就可以正常连接到服务器了。
这意味着我必须区分多个服务,而不是通过端口(显然不能从同一个端口路由到两个服务),而是通过 SNI,我猜我不清楚如何在 gRPC 中做到这一点我可以在 gRPC 标头中添加Host:[hostname]。不幸的是,如果这就是我可以路由的方式,则意味着需要在网关上读取标头,并且当我希望在 pod 处终止时,这要求在网关处终止 TLS。
【问题讨论】:
-
Laodbalancer 应该指向入口控制器,所有其他“服务”应该是“节点端口”类型
-
istio-ingressgateway服务是LoadBalancer类型,external-ip是AWS ELB定义的主机名,其他服务都是ClusterIP类型。
标签: kubernetes grpc kubernetes-ingress istio