使用 Nginx-Ingress-Controller 在 AWS 上的 EKS 中使用 gRPC

Posted

技术标签:

【中文标题】使用 Nginx-Ingress-Controller 在 AWS 上的 EKS 中使用 gRPC【英文标题】:gRPC in EKS on AWS with Nginx-Ingress-Controller 【发布时间】:2020-10-01 17:07:31 【问题描述】:

我在 AWS EKS 中设置了 gRPC 服务器,并使用 nginx-Ingress-Controller 执行负载平衡。我尝试通过将 gRPC 服务器入口设置为 like 来终止 NLB 的 TLS

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
  name: my-grpc
  namespace: myspace
spec:
  rules:
    - host: my.test.com
      http:
        paths:
          - path: /
            backend:
              serviceName: grpc-server
              servicePort: 8080

另外,我使用 Amazon Certificate Manager 来管理 NLB 的 TLS,所以我必须将 Nginx-Ingress-Controller Value.yaml 的 Helm Chart 更改为以下字段

controller:
  service:
    enabled: true
    annotations: 
      service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:xxxxxxxxxxx
      service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
      service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,8443"
      service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "3600"
      service.beta.kubernetes.io/aws-load-balancer-type: nlb
      service.beta.kubernetes.io/aws-load-balancer-internal: "true"

    targetPorts:
      http: http
      https: http

问题是,我无法通过 443 端口成功调用并让客户端连接到 gRPC 服务器。

问题发生在 NLB 和 Nginx 之间,但原因和原因尚不清楚。任何形式的帮助将不胜感激。

注意: 我知道 ingress-nginx 的示例有 TLS 字段,但是如果我使用 ACM,我应该在这里放什么。

【问题讨论】:

【参考方案1】:

我终于通过 AWS + NLB + EKS 得到了一些东西。 我从这个basic grpc app开始

用你的 URL 替换“fortune-teller.stack.build”的实例(例如 example.com)

在入口处,我不得不改变 tls -> secret 我之前创建的 tls-secret 的名称using this guide

kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
  name: fortune-ingress
  namespace: default
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: fortune-teller-service
          servicePort: grpc
  tls:
  - secretName: tls-secret
    hosts:
      - example.com

在 cert.yaml 中,更改

    spec -> 我的 URL (example.com) 的域

在 svc.yaml 中,添加注解和“type:LoadBalancer”

apiVersion: v1
kind: Service
metadata:
  name: fortune-teller-service
  namespace: default
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
    service.beta.kubernetes.io/aws-load-balancer-internal: "false"
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:<REGION>:<MY ACCOUNT>:certificate/<CERT ID>"
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"
spec:
  type: LoadBalancer
  selector:
    k8s-app: fortune-teller-app
  ports:
  - port: 50051
    targetPort: 50051
    name: grpc

通过自述文件部署所有内容后,在 AWS 控制台中找到 NLB。

    监听器选项卡 -> 选择监听器 (50051) 并点击“编辑” 将协议更改为 TLS,我将端口更改为 443 在 ALPN 策略下,选择“HTTP2Only” 在“默认操作 -> 转发到”下保持相同的目标组 选择一个策略版本(我选择了 ELBSecurityPolicy2016-08,但将对其进行升级)以及与您的 URL 相关联的 ACM 证书 点击“更新” 将您的 DNS 名称指向您的 NLB

现在等待...因为侦听器更新似乎需要几分钟时间。

grpcurl example.com:443 build.stack.fortune.FortuneTeller/Predict

我还能够通过交换图像、端口,当然还有名称,让我的应用程序成功运行。

我犯的错误导致它对我不起作用:

入口中没有 TLS 密钥 当 AWS 文档说您的目标组必须是“TLS 目标组”时,请相信他们。如果您遵循此示例,则永远不会交换 TG。 TG 保持为 TCP TG 并且仍然有效。

【讨论】:

这绝对是在 NLB 终止 tls 的一种方式!但是对于我的问题,我用另一种方式解决了。 谢谢,@CrookedSmile 您是否尝试在 gRPC 服务器上终止 TLS? @CrookedSmile 我是 K8s 的新手,为什么我们这里需要一个入口资源(在这种情况下我们只添加了一个服务)?我们不能只有负载均衡器类型的服务,它会将流量路由到服务【参考方案2】:

感谢 CrookedSmile 的回答,但事实证明我的问题的根本原因在于我的 Nginx-Ingress-Controller 设置,我最终以这种方式解决了它:

当我使用 Nginx-Ingress-Controller 时,我错误地认为在 NLB 终止 TLS 和在 Nginx 终止 TLS 是一回事。但事实并非如此。

在我的情况下,我不需要在 NLB 终止 TLS,我需要在 Nginx 终止它。

所以我做了以下两件事:

    我恢复了我在本节AWS L7 ELB SSL Termination之后所做的事情。

    Nginx 由我的应用程序 Ingress 文件配置。所以我必须设置 gRPC 服务器入口的 TLS 字段,如ingress.yaml example here。

然后 TLS 在 Nginx 成功终止,我可以在 NLB 后面调用我的 gRPC 服务器,并在两者之间使用 Nginx-Ingress-Controller。

补充说明:目前,Nginx-Ingress-Controller 尚不支持 ACM(2020 年 7 月 1 日),因此您必须自己管理每个证书。

【讨论】:

【参考方案3】:

@CrookedSmile - 当您部署类型为 LoadBalancer 的服务时,它会在您的 AWS 账户中创建一个网络负载均衡器。现在,当您创建一个 Nginx Ingress 控制器时,这就是另一个在后台创建的负载均衡器。根据您的说明,您将通过 Loadbalancer 公开服务 - 作为服务类型的一部分创建。当您修改目标组侦听器端口时,它会中断您的 Ingress 和此服务负载均衡器之间的通信,因为根据您的 Kubernetes 服务清单,负载均衡器侦听器的所需状态是 50051。

您可以按照以下顺序部署示例 grpc 应用。

https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/grpc

    部署算命应用
$ kubectl create -f app.yaml
    将服务部署为类型:ClusterIP
$ kubectl create -f svc.yaml
    部署 nginx-ingress 控制器
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/do/deploy.yaml
    部署入口资源
$ kubectl create -f ingress.yaml

    最后,添加一个主机条目来欺骗你的域名 例如:“fortune-teller.stack.build”,带有你的 Ingress LB 的 A 记录。

    验证

$ grpcurl --insecure fortune-teller.stack.build:443 build.stack.fortune.FortuneTeller/Predict
    
      "message": "Fremen add life to spice!"
    

简而言之,这是工作流程。

GRPC 请求 --> Nginx Ingress NLB --> 后端服务(集群 IP) --> 应用程序 pods

【讨论】:

以上是关于使用 Nginx-Ingress-Controller 在 AWS 上的 EKS 中使用 gRPC的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)