Kubernetes 无法为gRPC打开Istio入口网关

Kubernetes 无法为gRPC打开Istio入口网关,kubernetes,grpc,kubernetes-ingress,istio,Kubernetes,Grpc,Kubernetes Ingress,Istio,这个问题是关于我无法使用Istio入口网关将gRPC客户端连接到Kubernetes(AWS EKS)中托管的gRPC服务 在kubernetes一侧:我有一个带有Go进程的容器,在端口8081上监听gRPC。端口暴露在容器级别。我定义了一个kubernetes服务并公开了8081。我定义了一个istio网关,它选择istio:ingressgateway并为gRPC打开8081端口。最后,我定义了一个istio virtualservice,其中包含端口8081上任何内容的路由 在客户端:我有

这个问题是关于我无法使用Istio入口网关将gRPC客户端连接到Kubernetes(AWS EKS)中托管的gRPC服务

在kubernetes一侧:我有一个带有Go进程的容器,在端口8081上监听gRPC。端口暴露在容器级别。我定义了一个kubernetes服务并公开了8081。我定义了一个istio网关,它选择istio:ingressgateway并为gRPC打开8081端口。最后,我定义了一个istio virtualservice,其中包含端口8081上任何内容的路由

在客户端:我有一个Go客户端,可以向服务发送gRPC请求

  • 当我
    kubectl port forward-n mynamespace service/myservice 8081:8081
    并通过
    client-url localhost:8081
    调用我的客户机时,它工作正常
  • 当我关闭端口并使用
    客户端-url[redact]-[redact].us-west-2.elb.amazonaws.com:8081调用时,我的客户端无法连接。(该url是
    kubectl get svc istio ingresgateway-n istio system-o jsonpath='{.status.loadBalancer.ingres[0].hostname}'的输出,附加了
    :8081
日志:

getent hosts [redacted]-[redacted].us-west-2.elb.amazonaws.com
istioctl proxy-status istio-ingressgateway-[pod name]
istioctl proxy-config routes istio-ingressgateway-[pod name]
  • 我查看了istio系统/istio入口网关服务日志。我没有看到尝试的连接
  • 我在阅读本教程时确实看到了我之前建立的bookinfo连接。该教程起了作用,我可以打开浏览器查看bookinfo产品页面,入口网关日志显示“GET/productpage HTTP/1.1”200。所以Istio入口网关可以工作,只是我不知道如何为新的gRPC端点配置它
Istio的入口网关

kubectl describe service -n istio-system istio-ingressgateway
输出以下内容,我怀疑这是问题所在,尽管我努力打开了8081端口,但它并没有被列出。我对默认打开了多少端口感到困惑,我没有打开它们(欢迎对如何关闭我不使用的端口发表评论,但这不是问题的原因)

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
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
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
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
istioctl proxy-status istio-ingressgateway-[pod name]
istioctl proxy-config routes istio-ingressgateway-[pod name]
输出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入口通道的路线:

getent hosts [redacted]-[redacted].us-west-2.elb.amazonaws.com
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中做到这一点,我猜我可以添加一个
主机:[hostname]
在gRPC报头中。不幸的是,如果这是我可以路由的方式,这意味着需要在网关上读取报头,这要求在我希望在pod处终止时在网关处终止TLS

我开始明白我无法使用默认的istio入口网关打开端口8081。该服务不会公开该端口,我假设创建一个网关将更新“引擎盖下”的服务但事实并非如此。我可以选择的外部端口是:80、443、31400、15443、15021,我认为我的网关只需要依赖这些端口。我已将网关和虚拟服务更新为使用端口80,然后客户端就可以连接到服务器了

我不确定您到底是如何尝试为入口网关添加自定义端口的,但这是可能的

据我所知,有3种方法可以实现,以下是带有@A_Suh、@Ryota和@pepped提供的示例链接的选项


额外资源:


这意味着我必须区分多个服务,而不是通过端口(显然不能从同一端口路由到两个服务),而是通过SNI,我不清楚如何在gRPC中做到这一点,我猜我可以添加一个主机:[主机名]不幸的是,如果这是我可以路由的方式,这意味着需要在网关上读取报头,这就要求在我希望在pod处终止时在网关处终止TLS


我看到您已经创建了新的问题,所以让我们开始吧。

我已经成功地将端口添加到入口网关,但仍然无法将客户端连接到服务器。对我来说,端口转发也可以工作,但当我尝试通过入口连接时,会出现以下错误。这里的istio ingressgateway位于GKE上,因此它使用的是全局HTT负载均衡器

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)

LAODBANCER应指向入口控制器,所有其他“服务”应为“节点端口”类型istio ingressgateway服务是LoadBalancer类型,其外部ip是AWS ELB定义的主机名,所有其他服务都是ClusterIP类型。感谢@Jakub的回答。我一直在到处搜索您链接中提供的信息,我一定使用了错误的搜索词。让我阅读所有这些内容,然后我将接受你的回答。