skip to Main Content

I’m looking for some guidance on exposing UDP services on GKE using the ingress-nginx controller. After following the instructions on https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/ I was able to access it when deploying to a local minikube VM using the ConfigMap method. However, when I deploy to GKE the services are unreachable over the IP of the ingress controller service.

I see the ports (1053 and 15353) on the controller are mapped correctly:

NAMESPACE       NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                                                     AGE
ingress-nginx   ingress-nginx-controller             LoadBalancer   10.51.252.115   <redacted>      80:32307/TCP,443:30514/TCP,1053:32764/UDP,15353:31385/UDP   54d

The cluster itself was created using the google_container_cluster Terraform module with default settings and the controller works well handling HTTPS traffic. One thing I did notice is that the auto-generated firewall rules omit UDP for the specified ports, and use TCP instead. Manually adding a UDP firewall rule for those ports didn’t work.

NAME                                          NETWORK                        DIRECTION  PRIORITY  ALLOW                              DENY  DISABLED
k8s-fw-a62a982b26a034e0e97258af6717b8b0       cluster-network-labs-us-west1  INGRESS    1000      tcp:80,tcp:443,tcp:1053,tcp:15353        False

I’ve deployed a simple UDP ping-pong server which works both locally on bare metal and on minikube as a kubernetes service using the ingress-nginx controller. That same controller with an identical configuration causes client requests to time out.

Server

package server

import (
    "fmt"
    "net"
    "os"
    "time"

    "github.com/spf13/cobra"
)

func response(udpServer net.PacketConn, addr net.Addr, buf []byte) {

    fmt.Println("msg", string(buf))

    time := time.Now().Format(time.ANSIC)
    responseStr := fmt.Sprintf("%v. msg: %v", time, string(buf))

    udpServer.WriteTo([]byte(responseStr), addr)
}

var Command = &cobra.Command{
    Use:   "server",
    Short: "Debug UDP server.",
    Long:  `Provides a UDP server endpoint which responds to pings.`,
    RunE: func(cmd *cobra.Command, args []string) error {

        udpServer, err := net.ListenPacket("udp", fmt.Sprintf(":%d", serverPort))
        if err != nil {
            return err
        }
        defer udpServer.Close()

        fmt.Fprintf(os.Stdout, "listening :%dn", serverPort)

        for {
            buf := make([]byte, 1024)
            _, addr, err := udpServer.ReadFrom(buf)
            if err != nil {
                continue
            }
            go response(udpServer, addr, buf)
        }

    },
}

var serverPort int

func init() {
    Command.PersistentFlags().IntVar(&serverPort, "port", 1053, "Port to open an listen for UDP packets")
}

Client

package client

import (
    "fmt"
    "net"
    "os"

    "github.com/spf13/cobra"
)

var Command = &cobra.Command{
    Use:   "client",
    Short: "Debug UDP client.",
    Long:  `Provides a UDP client endpoint which responds to pings.`,
    RunE: func(cmd *cobra.Command, args []string) error {

        udpServer, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", queryHost, queryPort))

        if err != nil {
            return err
        }

        conn, err := net.DialUDP("udp", nil, udpServer)
        if err != nil {
            return err
        }
        defer conn.Close()

        _, err = conn.Write([]byte(msg))
        if err != nil {
            return err
        }

        received := make([]byte, 1024)
        _, err = conn.Read(received)
        if err != nil {
            println("Read data failed:", err.Error())
            os.Exit(1)
        }

        println(string(received))

        return nil
    },
}

var msg string
var queryHost string
var queryPort int

func init() {

    Command.PersistentFlags().StringVar(&msg, "msg", "echo", "Message used to send ping/pong requests over UDP")
    Command.PersistentFlags().StringVar(&queryHost, "host", "127.0.0.1", "Host used to send ping/pong requests over UDP")
    Command.PersistentFlags().IntVar(&queryPort, "port", 1053, "Port used to send ping/pong requests over UDP")
}

Has anyone seem something similar to this or have any ideas on where I can dig in further?
Thanks

Versions:

  • ingress-nginx helm chart – 4.4.0
  • ingress-nginx – 1.5.1
  • Kubernetes – v1.24.5-gke.600
  • registry.terraform.io/hashicorp/google – v4.43.0

2

Answers


  1. As per this SO1 & Official Doc it is not possible to expose a UDP service externally on GKE.

    But as per the referral document you mentioned it is possible to using NGINX Ingress.

    Ingress does not support TCP or UDP services. For this reason this Ingress controller uses the flags --tcp-services-configmap and --udp-services-configmap to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format: <namespace/service name>:<service port>:[PROXY]:[PROXY].

    This guide is describing how it can be achieved using minikube but doing this on a on-premises kubernetes is different and requires a few more steps.

    Please go through SO for more information.

    Login or Signup to reply.
  2. Make sure if you are exposing your service which LoadBalnacer type it’s creating. With Nginx ingress by default, it might be creating the TCP load balancer only which might be supporting the TCP not sure if Nginx ingress supports the UDP or not.

    Network Load Balancer is a good option if you want to expose the UDP service directly as type:LoadBalancer, as it supports the UDP/TCP both.

    Ref : https://stackoverflow.com/a/69709859/5525824

    Ref for LB service

    apiVersion: v1
    kind: Service
    metadata:
      name: udp-service
    spec:
      selector:
        log: "true"
      ports:
      - name: udp-input
        port: 3333
        protocol: UDP
        targetPort: 3333
      type: LoadBalancer
    

    For Nginx you would like to give this try : https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/ OR https://github.com/kubernetes/ingress-nginx/issues/4370

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: udp-services
      namespace: ingress-nginx
    data:
      53: "kube-system/kube-dns:53"
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search