这个问题是关于我无法使用Istio入口网关将gRPC客户端连接到Kubernetes(AWS EKS)中托管的gRPC服务。
在kubernetes端::我有一个带有Go进程的容器,该进程在端口8081上监听gRPC。该端口在容器级别暴露。我定义了一个kubernetes服务并公开了8081。我定义了一个istio网关,它选择istio:ingressgateway并为gRPC打开端口8081。最后,我定义了一个istio虚拟服务,该虚拟服务的端口8081上有一条路由。
在客户端上:我有一个Go客户端,可以将gRPC请求发送到该服务。
kubectl port-forward -n mynamespace service/myservice 8081:8081
并通过client -url localhost:8081
致电客户时,效果很好。client -url [redacted]-[redacted].us-west-2.elb.amazonaws.com:8081
呼叫时,客户端无法连接。 (该网址是kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
的输出,并附加了:8081
。日志:
istio-system/istio-ingressgateway
服务日志。我没有看到尝试的连接。"GET /productpage HTTP/1.1" 200
。因此Istio入口网关可以正常工作,只是我不知道如何为新的gRPC端点配置它。Istio的入口网关
kubectl describe service -n istio-system istio-ingressgateway
输出以下内容,我怀疑是问题所在,尽管我努力打开端口8081,但未列出该端口。我对默认情况下打开了多少个端口感到困惑,我没有打开它们(欢迎评论如何关闭不使用的端口,但这不是出现此问题的原因)
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。
答案 0 :(得分:1)
我开始理解我无法使用默认的istio入口网关打开端口8081。该服务不会公开该端口,我假设创建网关将“在后台”更新服务,但事实并非如此。我可以选择的外部端口是:80、443、31400、15443、15021,我认为我的网关仅需要依赖这些端口。我已经更新了网关和虚拟服务以使用端口80,然后客户端可以很好地连接到服务器。
我不确定您尝试如何为入口网关添加自定义端口,但是有可能。
就我检查here而言,可以通过3种方式进行,这是@ A_Suh,@ Ryota和@peppered提供的示例链接。
其他资源:
这意味着我必须区分多个服务,而不是通过端口(显然不能从同一端口路由到两个服务),而是通过SNI进行区分,我不清楚如何在gRPC中做到这一点我可以在gRPC标头中添加Host:[hostname]。不幸的是,如果这是我可以路由的方式,则意味着需要在网关上读取标头,并且当我希望在Pod处终止时,这要求在网关处终止TLS。
我看到您已经创建了新问题here,所以我们就移到那里。
答案 1 :(得分:0)
我已成功将端口添加到入口网关,但仍然无法让客户端连接到服务器。对我来说,端口转发也有效,但是当我尝试通过入口连接时出现错误。这里 istio ingressgateway 在 GKE 上,所以它使用全局 HTTPS 负载均衡器。
Jun 14, 2021 8:28:08 PM com.manning.mss.ch12.grpc.sample01.InventoryClient updateInventory
WARNING: RPC failed: Status{code=INTERNAL, description=http2 exception, cause=io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception: First received frame was not SETTINGS. Hex dump for first 5 bytes: 485454502f
at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception.connectionError(Http2Exception.java:85)
at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.verifyFirstFrameIsSettings(Http2ConnectionHandler.java:350)
at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.decode(Http2ConnectionHandler.java:251)
at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:450)
at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:502)
at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:441)
at io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:278)
at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:345)
at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:337)
at io.grpc.netty.shaded.io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408)
at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359)
at io.grpc.netty.shaded.io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:345)
at io.grpc.netty.shaded.io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.grpc.netty.shaded.io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:677)
at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:612)
at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:529)
at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:491)
at io.grpc.netty.shaded.io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905)
at io.grpc.netty.shaded.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)