Search code examples
kubernetesload-balancinggoogle-kubernetes-enginerpckubernetes-health-check

GKE RPC Health Check with multiple ports and different protocols under the same backend service


I am trying to spin up a third-party service that accepts connections in 4 different ports:

x-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: x-deployment
  labels:
    app: x
...
ports:
  - containerPort: 8000 # HttpGraphQLServer
  - containerPort: 8001 # WebSocketServer
  - containerPort: 8020 # JsonRpcServer
  - containerPort: 8030 # HttpIndexingServer
livenessProbe:
  tcpSocket:
    port: 8020

x-service.yaml

apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: x-rpc-config
spec:
  healthCheck:
    checkIntervalSec: 7
    timeoutSec: 3
    healthyThreshold: 2
    unhealthyThreshold: 2
    type: HTTP2
    port: 8020
---
apiVersion: v1
kind: Service
metadata:
  name: x-service
  annotations:
    beta.cloud.google.com/backend-config: '{"default": "x-rpc-config"}'
spec:
  selector:
    app: x
  ports:
    - name: graphql
      port: 8000
      targetPort: 8000
    - name: subscription
      port: 8001
      targetPort: 8001
    - name: indexing
      port: 8030
      targetPort: 8030
    - name: jrpc
      port: 8020
      targetPort: 8020
  type: NodePort

ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: backend-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: backend-dev-ip-address
    networking.gke.io/managed-certificates: backend-certificate
spec:
  rules:
    - host: x.dev.domain.io
      http:
        paths:
          - path: /rpc
            backend:
              serviceName: x-service
              servicePort: 8020
          - path: /idx
            backend:
              serviceName: x-service
              servicePort: 8030
          - path: /ws
            backend:
              serviceName: x-service
              servicePort: 8001
          - path: /*
            backend:
              serviceName: x-service
              servicePort: 8000

By default the GKE LoadBalancer runs the Health Check on HTTP:80, if I spin up the backend-service (x-service.yaml) without the BackendConfig (x-rpc-config), it is able to detect only 2 healthy backend-services, both with HTTP ports: 8000 and 8030). However the backend-services listen to ports: 8020 (RPC) and 8030 (WS) are not considered healthy. I believe it happens because of the protocol type, so I've created the BackendConfig (x-rpc-config) to run a TPC Health Check instead, using HTTP2 protocol for port 8020 - which is where the livenessProbe is pointing to.

The pods and services are created properly, but the Load Balancer still fails to detect them as healthy services. The console simply shows the following warning:

Some backend services are in UNHEALTHY state

The goal is to open up the port 8020 (RPC) but also keep the 8000 (HTTP) working. Is it possible? Do I need another type of Load Balancer or it is just a config issue?

I could not find any example of HealthCheck config for multiple ports with different protocols under the same service. It is probably an anti-pattern?

Thanks in advance.


Solution

  • Solution

    Instead of using an Ingress, which will launch a HTTP/HTTPs Load Balancer on GCP by default, I've changed the Service to work as a LoadBalancer with a custom HTTP2 health check config. By default this configuration will spin up a TCP Load Balancer on GCP. For instance:

    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: rpc-config
    spec:
      healthCheck:
        checkIntervalSec: 10
        timeoutSec: 3
        healthyThreshold: 2
        unhealthyThreshold: 2
        type: HTTP2
        port: 8020
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: x-service
      annotations:
        cloud.google.com/app-protocols: '{"rpc-a":"HTTP2", "rpc-b":"HTTP2", "rpc-c":"HTTP2"}'
        beta.cloud.google.com/backend-config: '{"default": "rpc-config"}'
    spec:
      selector:
        app: x-node
      ports:
        - name: rpc-a
          port: 5001
          protocol: TCP
          targetPort: 5001
        - name: rpc-b
          port: 8020
          protocol: TCP
          targetPort: 8020
        - name: rpc-c
          port: 8000
          protocol: TCP
          targetPort: 8000
      type: LoadBalancer
    

    The next step is to enable the SSL for the TCP LB. I saw GCP has the SSL Proxy LB, that might solve it. Just need to figure out the proper configuration for that, I could not find it in their docs.