* Update golang images in code samples * fix sampleconsistency test |
||
|---|---|---|
| .. | ||
| cmd/server | ||
| config | ||
| pkg/handlers | ||
| Dockerfile | ||
| README.md | ||
| go.mod | ||
| go.sum | ||
README.md
WebSocket - Go
A simple WebSocket server that performs the HTTP upgrade and prints log messages on all standardized WebSocket events, such as open, message, close and error. The server is written in Golang and uses the Gorilla WebSocket library.
Before you begin
- A Kubernetes cluster with Knative installed and DNS configured. See Install Knative Serving.
- ko or Docker installed and running on your local machine, and a Docker Hub account configured (we'll use it for a container registry).
The sample code.
-
If you look in
cmd/server/main.go, you will themainfunction setting ahandleWebSocketfunction and starting the web server on the/wscontext: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
handleWebSocketperforms the protocol upgrade and assigns various websocket handler functions, such asOnOpenorOnMessage: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) } }() } -
The WebSocket application logic is located in the
pkg/handlers/handlers.gofile and contains callbacks for each WebSocket event:func OnOpen(conn *websocket.Conn) { log.Printf("WebSocket connection opened: %v", conn.RemoteAddr()) } func OnMessage(conn *websocket.Conn, messageType int, message []byte) { log.Printf("Received message from %v: %s", conn.RemoteAddr(), string(message)) if err := conn.WriteMessage(messageType, message); err != nil { log.Printf("Error sending message: %v", err) } } func OnClose(conn *websocket.Conn) { log.Printf("WebSocket connection closed: %v", conn.RemoteAddr()) conn.Close() } func OnError(conn *websocket.Conn, err error) { log.Printf("WebSocket error from %v: %v", conn.RemoteAddr(), err) }
Build the application
Dockerfile
- If you look in
Dockerfile, you will see a method for pulling in the dependencies and building a small Go container based on Alpine. You can build and push this to your registry of choice via:
# Build and push the container on your local machine.
docker buildx build --platform linux/arm64,linux/amd64 -t "<image>" --push .
ko
- You can use
koto build and push just the image with:
ko publish github.com/knative/docs/code-samples/serving/websockets-go
However, if you use ko for the next step, this is not necessary.
Deploy the application
yaml (with Dockerfile)
- If you look in
service.yaml, take the<image>name you used earlier and insert it into theimage:field, then run:
kubectl apply -f config/service.yaml
yaml (with ko)
- If using
koto build and push:
ko apply -f config/service.yaml
Testing the WebSocket server
Get the URL for your Service with:
kubectl get ksvc
NAME URL LATESTCREATED LATESTREADY READY REASON
websocket-server http://websockets-server.default.svc.cluster.local websockets-server-00001 websocket-server-00001 True
Now run a container with the wscat CLI and point it to the WebSocket application ws://websocket-server.default.svc.cluster.local/ws, like:
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
```>
The above is scaling to exactly one pod, since only one client was connected. Since Knative Serving allows you a dynamic scalling, a certain number of concurrent connections lead to a number of pods.
NOTE: Depending on the target annotation you have (
autoscaling.knative.dev/target) you can scale based on num of connections.