【问题标题】:Unable to open Istio ingress-gateway for gRPC无法为 gRPC 打开 Istio 入口网关
【发布时间】: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


【解决方案1】:

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

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

据我检查here 可以通过 3 种方式进行,以下是@A_Suh、@Ryota 和@peppered 提供的示例链接选项。


其他资源:


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

我看到你已经创建了新问题here,所以让我们移到那里。

【讨论】:

  • 感谢@Jakub 的回答。我一直在到处搜索您链接中提供的信息,我一定是使用了错误的搜索词。让我读完所有这些,然后我会接受你的回答。
【解决方案2】:

我已成功将端口添加到入口网关,但仍然无法让客户端连接到服务器。对我来说,端口转发也有效,但是当我尝试通过入口连接时出现错误。这里 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)

【讨论】:

    猜你喜欢
    • 2021-06-24
    • 1970-01-01
    • 2020-11-09
    • 2023-01-12
    • 2019-11-21
    • 2021-07-12
    • 2017-11-29
    • 1970-01-01
    • 2020-05-07
    相关资源
    最近更新 更多