Skip to content

Building WebSocket Applications with Knative using Golang

Author: Matthias Weßendorf, Senior Principal Software Engineer @ Red Hat

Knative Serving supports multiple protocols for running serverless workloads, such as HTTP, HTTP/2, gRPC or WebSocket. The WebSocket protocol allows a full-duplex communication over one single TCP connection between client applications and servers. The WebSocket protocol starts as an HTTP "Upgrade" request and then switchs the connection from HTTP over to the WebSocket protocol, allowing real-time and bidirectional communication between the peers. In this article we show how to build a scalable WebSocket server with Knative.

Note

The sample application discussed here can be found in the Knative docs repository.

HTTP Upgrade

Since every WebSocket application starts with an HTTP Upgrade request, we need a Go web server that handles classic HTTP requests. The sample uses gorilla/websocket for the WebSocket implementation. The complete server is checked in at cmd/server/main.go; use that file rather than recreating it from snippets. Its upgrader accepts any origin for demonstration purposes; restrict allowed origins for production.

The main function starts the web server on the /ws context and registers a handleWebSocket handle function:

func main() {
    http.HandleFunc("/ws", handleWebSocket)
    fmt.Println("Starting server on :8080...")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatalf("Server error: %v", err)
    }
}

The handleWebSocket performs the protocol upgrade and assigns various websocket handler functions, such as OnOpen or OnMessage:

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Printf("Error upgrading to websocket: %v", err)
        return
    }
    handlers.OnOpen(conn)

    go func() {
        defer handlers.OnClose(conn)
        for {
            messageType, message, err := conn.ReadMessage()
            if err != nil {
                handlers.OnError(conn, err)
                break
            }
            handlers.OnMessage(conn, messageType, message)
        }
    }()
}

Note

For a cleaner separation of concerns the different On... handlers are located in separate handlers package.

WebSocket handlers

The callbacks for each WebSocket event are checked in at pkg/handlers/handlers.go. OnOpen, OnClose and OnError log the connected peer's remote address and connection events. OnMessage logs each incoming message and echoes it back with the original text or binary message type. The deferred close in the server ensures the connection is released when its read loop exits.

Testing the WebSocket server

Note

The easiest way to build and deploy Golang applications is using ko, as described on the actual sample application.

Once the Knative Serving application was deployed to the Kubernetes cluster, you can test it. For that you need to receive the actual URL for the service of the WebSocket application:

kubectl get ksvc websockets-server

The reported URL depends on your cluster's domain configuration. To connect from outside the cluster, change http:// to ws:// (or https:// to wss:// for TLS) and append /ws.

Alternatively, launch a container inside Kubernetes and run wscat against the cluster-local address:

kubectl run --rm -i --tty wscat --image=monotykamary/wscat --restart=Never -- -c ws://websockets-server.default.svc.cluster.local/ws

Afterward you can chat with the WebSocket server like:

If you don't see a command prompt, try pressing enter.
Connected (press CTRL+C to quit)
> Hello
< Hello
>

Knative can scale the application based on concurrent connections. The number of pods depends on autoscaling settings and traffic, not just the number of clients.

Below is an example of a scaled out application when running a larger number of concurrent requests against it:

k get pods 
NAME                                                READY   STATUS    RESTARTS   AGE
websocket-server-00001-deployment-f785cbd65-42mrn   2/2     Running   0          16s
websocket-server-00001-deployment-f785cbd65-76bjr   2/2     Running   0          14s
websocket-server-00001-deployment-f785cbd65-98cwb   2/2     Running   0          18s
websocket-server-00001-deployment-f785cbd65-9fdbl   2/2     Running   0          18s
websocket-server-00001-deployment-f785cbd65-bpvjj   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-c6f47   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-fl6kk   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-gnffw   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-hqpfx   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-j4v9d   2/2     Running   0          18s
websocket-server-00001-deployment-f785cbd65-j72vk   2/2     Running   0          18s
websocket-server-00001-deployment-f785cbd65-k856w   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-kmmng   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-l4f2v   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-lpfr9   2/2     Running   0          14s
websocket-server-00001-deployment-f785cbd65-mn26w   2/2     Running   0          16s
websocket-server-00001-deployment-f785cbd65-mr98h   2/2     Running   0          18s
websocket-server-00001-deployment-f785cbd65-prjmj   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-v696v   2/2     Running   0          18s
websocket-server-00001-deployment-f785cbd65-ws5k9   2/2     Running   0          20s
websocket-server-00001-deployment-f785cbd65-xmszx   2/2     Running   0          18s
websocket-server-00001-deployment-f785cbd65-znhrr   2/2     Running   0          20s

Note

Depending on the target annotation you have (autoscaling.knative.dev/target) you can scale based on num of connections.

We use analytics and cookies to understand site traffic. Information about your use of our site is shared with Google for that purpose. Learn more.

× OK