【问题标题】:gRPC socket closed on kubernetes with ingressgRPC 套接字在具有入口的 kubernetes 上关闭
【发布时间】:2019-09-14 12:45:41
【问题描述】:

我有一个 gRPC 服务器,可以在我的本地机器上正常工作。我可以从 python 应用程序发送 grpc 请求并获得正确的响应。

我将服务器放入 GKE 集群(只有一个节点)。我在集群前面有一个普通的 TCP 负载均衡器。在此设置中,我的本地客户端能够从某些请求中获得正确的响应,但不能从其他请求中获得。我认为是 gRPC 流式传输不起作用。

我认为这是因为流式传输需要 HTTP/2 连接,该连接需要 SSL。

我在 GKE 中获得的标准负载均衡器似乎不支持 SSL,因此我按照文档设置了一个支持 SSL 的入口负载均衡器。我正在使用 Lets-Encrypt 证书。

现在所有 gRPC 请求都返回

status = StatusCode.UNAVAILABLE

details = "套接字关闭"

debug_error_string = "{"created":"@1556172211.931158414","description":"收到错误 同行 ipv4:ip.of.ingress.service:443", "file":"src/core/lib/surface/call.cc", "file_line":1041,"grpc_message":"套接字关闭","grpc_status": 14}"

IP 地址是我的入口服务的外部 IP 地址。 入口 yaml 如下所示:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: rev79-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: "rev79-ip"
    ingress.gcp.kubernetes.io/pre-shared-cert: "lets-encrypt-rev79"
    kubernetes.io/ingress.allow-http: "false" # disable HTTP
spec:
  rules:
  - host: sub-domain.domain.app
    http:
      paths:
      - path: /*
        backend:
          serviceName: sandbox-nodes
          servicePort: 60000

来自我的 python 应用程序的请求的子域和域与入口规则中的主机匹配。

它连接到一个如下所示的节点端口:

apiVersion: v1
kind: Service
metadata:
  name: sandbox-nodes
spec:
  type: NodePort
  selector:
    app: rev79
    environment: sandbox
  ports:
  - protocol: TCP
    port: 60000
    targetPort: 9000

节点本身有两个容器,如下所示:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: rev79-sandbox
  labels:
    app: rev79
    environment: sandbox
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: rev79
        environment: sandbox
    spec:
      containers:
      - name: esp
        image: gcr.io/endpoints-release/endpoints-runtime:1.31
        args: [
          "--http2_port=9000",
          "--service=rev79.endpoints.rev79-232812.cloud.goog",
          "--rollout_strategy=managed",
          "--backend=grpc://0.0.0.0:3011"
        ]
        ports:
        - containerPort: 9000
      - name: rev79-uac-sandbox
        image: gcr.io/rev79-232812/uac:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 3011
        env:
        - name: RAILS_MASTER_KEY
          valueFrom:
            secretKeyRef:
              name: rev79-secrets
              key: rails-master-key

节点端口的目标是连接到部署在云端的gRPC服务的ESP容器,后端是实现API后端的Rails应用程序。这个 rails 应用程序没有运行 rails 服务器,而是一个专用的 gRPC 服务器,附带 grpc_for_rails gem

Rails 应用程序中的 grpc_server 不会在日志中记录任何操作,所以我认为请求不会那么远。

kubectl get ingress 报告这个:

NAME            HOSTS                   ADDRESS            PORTS   AGE
rev79-ingress   sub-domain.domain.app   my.static.ip.addr   80      7h

显示端口 80,即使它是使用 SSL 设置的。这似乎是一个错误。当我检查curl -kv https://sub-domain.domain.app 时,入口服务器可以很好地处理请求,并使用 HTTP/2。它会再次出现 HTML 格式的服务器错误,但我不确定是什么产生的。

API 需要一个 API 密钥,python 客户端将其插入到每个请求的元数据中。

当我转到 GCP 控制台的端点页面时,我看到 API 没有注册任何请求,因为放入了入口负载均衡器,所以看起来请求没有到达 EPS 容器。

那么为什么我在使用 gRPC 时收到“套接字关闭”错误?

【问题讨论】:

  • 您可以在您的 python 客户端上添加这些环境变量以获得更详细的调试信息:GRPC_VERBOSITY=DEBUG 和 GRPC_TRACE=api,channel,call_error,connectivity_state,http,server_channel 如果您将其添加到您的问题中,它可能有助于回答它。您是否使用任何类型的代理? (企业代理一般不支持grpc/http2)
  • 我发现我的健康检查失败了。现在,我在为我的 gRPC 后端进行功能性健康检查时遇到了问题,并就此提出了单独的问题。一旦我真正开始工作,我会在这里发布答案

标签: sockets kubernetes grpc kubernetes-ingress


【解决方案1】:

我说过,一旦我得到它的工作,我会回来并在这里发布答案。看起来我从来没有这样做过。作为一个信守诺言的人,我现在将发布对我有用的配置文件。

在我的部署中,我对 ESP 容器进行了活跃度和就绪度探测。这使得部署顺利进行,无需停机:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: rev79-sandbox
  labels:
    app: rev79
    environment: sandbox
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: rev79
        environment: sandbox
    spec:
      volumes:
      - name: nginx-ssl
        secret:
          secretName: nginx-ssl
      - name: gcs-creds
        secret:
          secretName: rev79-secrets
          items:
            - key: gcs-credentials
              path: "gcs.json"
      containers:
      - name: esp
        image: gcr.io/endpoints-release/endpoints-runtime:1.45
        args: [
          "--http_port", "8080",
          "--ssl_port", "443",
          "--service", "rev79-sandbox.endpoints.rev79-232812.cloud.goog",
          "--rollout_strategy", "managed",
          "--backend", "grpc://0.0.0.0:3011",
          "--cors_preset", "cors_with_regex",
          "--cors_allow_origin_regex", ".*",
          "-z", " "
        ]
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 60
          timeoutSeconds: 5
          periodSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /healthz
            port: 8080
          timeoutSeconds: 5
          failureThreshold: 1
        volumeMounts:
        - name: nginx-ssl
          mountPath: /etc/nginx/ssl
          readOnly: true
        ports:
        - containerPort: 8080
        - containerPort: 443
          protocol: TCP
      - name: rev79-uac-sandbox
        image: gcr.io/rev79-232812/uac:29eff5e
        imagePullPolicy: Always
        volumeMounts:
          - name: gcs-creds
            mountPath: "/app/creds"
        ports:
        - containerPort: 3011
          name: end-grpc
        - containerPort: 3000
        env:
        - name: RAILS_MASTER_KEY
          valueFrom:
            secretKeyRef:
              name: rev79-secrets
              key: rails-master-key

这是我的服务配置,它将部署暴露给负载均衡器:

apiVersion: v1
kind: Service
metadata:
  name: rev79-srv-ingress-sandbox
  labels:
    type: rev79-srv
  annotations:
    service.alpha.kubernetes.io/app-protocols: '{"rev79":"HTTP2"}'
    cloud.google.com/neg: '{"ingress": true}'
spec:
  type: NodePort 
  ports:
  - name: rev79
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    app: rev79
    environment: sandbox

这是我的入口:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: rev79-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: "rev79-global-ip"
spec:
  tls:
  - secretName: sandbox-api-rev79-app-tls
  rules:
  - host: sandbox-api.rev79.app
    http:
      paths:
      - backend:
          serviceName: rev79-srv-ingress-sandbox
          servicePort: 443

我正在使用 cert-manager 来管理证书。

现在已经很久了。我不记得我是否做了其他任何事情来解决我遇到的问题

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-18
    • 2021-06-24
    • 2020-12-20
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 2012-12-04
    相关资源
    最近更新 更多