Search code examples
kubernetesgoogle-cloud-platformgoogle-kubernetes-engineload-balancinggke-networking

Allow two ports on multi-region ingress for GKE service


I have two ports on node.js, 4000 and 5050, open for normal api and web socket (require session affinity for web socket) respectively.

Below is my mcs.yaml

apiVersion: networking.gke.io/v1
kind: MultiClusterService
metadata:
  name: terraback-mcs
  namespace: terraback
  labels:
    version: v1
spec:
  template:
    spec:
      selector:
        app: terraback
      ports:
        - name: web
          protocol: TCP
          port: 8080
          targetPort: 4000

mci.yaml

apiVersion: networking.gke.io/v1
kind: MultiClusterIngress
metadata:
  name: terraback-ingress
  namespace: terraback
  labels:
    version: v1
spec:
  template:
    spec:
      backend:
        serviceName: terraback-mcs
        servicePort: 8080

deployment.yaml

# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: terraback-instance
  namespace: terraback
  labels:
    app: terraback
spec:
  replicas: 1
  selector:
    matchLabels:
      app: terraback
  template:
    metadata:
      labels:
        app: terraback
    spec:
      containers:
      - name: terraback-app
        # Replace $LOCATION with your Artifact Registry location (e.g., us-west1).
        # Replace $GCLOUD_PROJECT with your project ID.
        image: us-east1-docker.pkg.dev/terraback-v2/terraback-repo/terraback-instance:latest
        # This app listens on port 8080 for web traffic by default.
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            value: "8080"
---

How should I make changes to allow additional port 5050?

I have tried the method from Zer0, with the modification of mci from validation error for multiingress yaml file for GKE and it works.


Solution

  • You need to create an additional port in your terraback-mcs service. This will serve the web socket connections. The following changes will be required:

    apiVersion: networking.gke.io/v1
    kind: MultiClusterService
    metadata:
      name: terraback-mcs
      namespace: terraback
      labels:
        version: v1
    spec:
      template:
        spec:
          selector:
            app: terraback
          ports:
            - name: web
              protocol: TCP
              port: 8080
              targetPort: 4000
            - name: web-socket
              protocol: TCP
              port: 8081
              targetPort: 5050
    
    

    You will then need to add an additional backend to your MultiClusterIngress. This can be done as follows:

    apiVersion: networking.gke.io/v1
    kind: MultiClusterIngress
    metadata:
      name: terraback-ingress
      namespace: terraback
      labels:
        version: v1
    spec:
      template:
        spec:
          backend:
            serviceName: terraback-mcs
            servicePort: 8080 # <==== This gets routed to service port 8080->4000
          rules:
          - host: web.socket.hostname #<==== adjust this as needed
              http:
                paths:        
                  - backend:
                    serviceName: terraback-mcs
                    servicePort: 8081 # <=== This gets routed to servicePort 8081 => 5050
    

    This Ingress will route incoming requests to the provided host if there is a match. Otherwise, the connection will be forwarded to the default host, which will be your API service.

    I hope this gives you an idea of how to configure multiple ports with MultiClusterService and MultiClusterIngress objects. I'm unsure what is the point of the terraback-instance deployment. I don't believe this is your Node.JS application, since it neither exposes port 5050 nor port 4000. It it is your application indeed, then you need to expose both ports, correctly as:

    ports:
      - name: api-port
        containerPort: 4000
      - name: web-socket-port
        containerPort: 5050
    

    Summary

    The traffic flow will be like this:

    1. All incoming traffic on the hostname web.socket.hostname will be rerouted by the ingress to the service with port 8081. This, will be routed by the service, to the container port 5050.
    2. All the incoming traffic other than the hostname above, will be rerouted by the Ingress to the Service on port 8080. This, will be routed by the service, to the container port 4000.

    Understand that Ingress objects process the incoming traffic on the basis of a host and path matching. And forward to backend services on certain ports based on the result of this match. In the current configuration, the ingress rule is defining a default backend only, because of which all the traffic coming in, will be forwarded to the same backend service configured.

    Once you make these changes, the ingress will separate traffic based on the host and forward the traffic to the appropriate service backend.

    Hope this helps.