ws-example
shows an simple example implementation of a Golang Websocket server. It is primarily an exploration of
gorilla/websockets
and nginx
to proxy websocket connections.
Using nginx
as a proxy, we can run multiple websocket servers and distribute connections among them.
See details below for running the application locally.
Simply running docker-compose up
is enough to get the services up and functional. Connect a websocket client to
http://localhost:8080/ws
to interact with the websocket server.
An nginx
service will start which proxies websocket connections to ws-backend-n
. nginx
is used to provide
a single host to connect to (e.g. localhost:8080
) but distribute requests across multiple backends.
The ws-backend-n
services are a simple Golang application using gorilla/websocket
that echoes back any message received but prepends the hostname to differentiate which backend host you are connected to.
Use websocat
to connect as a client for demonstration purposes. It can be installed with Homebrew (brew install websocat
).
For example:
$ websocat -E --ping-interval 5 --ping-timeout 10 ws://localhost:8080/ws
This gives an interactive shell to send and received messages to the backend. Type a message and press enter to see a response.
$ websocat -E --ping-interval 5 --ping-timeout 10 ws://localhost:8080/ws
[a9de44781391] hello :) type a message and press ENTER
hello
[a9de44781391] hello
Press CTRL+C
to exit, with the -E
this will close the connection immediately with the backend as well.
Docker Swarm can be used to emulate an environment that would be more similar to production. The docker-compose.swarm.yml
can be used to deploy the service stack with one nginx
service and, initially, one ws-backend
service. From there,
the ws-backend
service can be scaled arbitrarily and nginx
will automatically proxy requests to all backends.
Deploy websockets
stack using docker-compose.swarm.yml
$ docker stack deploy --compose-file=docker-compose.swarm.yml websockets
Creating service websockets_nginx
Creating service websockets_ws-backend
View tasks in the websockets
stack
$ docker stack ps websockets
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
w992fkm1363w websockets_nginx.1 nginx:1.19.2 carb Running Running about a minute ago
54ipaz8sal94 websockets_ws-backend.1 golang:1.15.2-buster carb Running Running about a minute ago
Scale ws-backend
service in stack
$ docker service scale websockets_ws-backend=2
websockets_ws-backend scaled to 2
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged
Use websocat
to connect to the services
$ websocat -E --ping-interval 5 --ping-timeout 10 ws://localhost:8080/ws
[886396d2edcc] hello :) type a message and press ENTER
asdf
[886396d2edcc] asdf
...
$ websocat -E --ping-interval 5 --ping-timeout 10 ws://localhost:8080/ws
[1eba9cf95b52] hello :) type a message and press ENTER
adsf
[1eba9cf95b52] adsf
Note that we have connected to two different hosts 886396d2edcc
and 1eba9cf95b52
. This indicates that nginx
is correctly proxying connections to an arbitrary number of backends and we are therefore naively load balancing the
websocket connections.
View logs for ws-backend
services
docker service logs -f websockets_ws-backend
websockets_ws-backend.2.plyyp6ztzydh@carb | Got message: asdf
websockets_ws-backend.1.54ipaz8sal94@carb | Got message: adsf