Update the Dockerfile to expose websockets (#2576)

The Dockerfile now uses ASGI by default (via uvicorn).
This commit is contained in:
Yohan Boniface 2025-04-03 17:16:56 +02:00 committed by GitHub
commit 6582e85f18
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 70 additions and 85 deletions

View file

@ -1,10 +1,9 @@
# This part installs deps needed at runtime.
FROM python:3.11-slim AS common
FROM python:3.11-slim AS runtime
RUN apt-get update && \
apt-get install -y --no-install-recommends \
tini \
uwsgi \
sqlite3 \
libpq-dev \
gdal-bin \
@ -14,7 +13,7 @@ RUN apt-get update && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# This part adds deps needed only at buildtime.
FROM common AS build
FROM runtime AS build
RUN apt-get update && \
apt-get install -y --no-install-recommends \
@ -39,9 +38,9 @@ WORKDIR /srv/umap
COPY . /srv/umap
RUN /venv/bin/pip install .[docker,s3]
RUN /venv/bin/pip install .[docker,s3,sync]
FROM common
FROM runtime
COPY --from=build /srv/umap/docker/ /srv/umap/docker/
COPY --from=build /venv/ /venv/

View file

@ -1,5 +1,15 @@
services:
# Usefull only to use the real time collaboration
redis:
image: redis:latest
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 1s
timeout: 3s
retries: 5
command: ["redis-server"]
db:
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
@ -14,7 +24,9 @@ services:
depends_on:
db:
condition: service_healthy
image: umap/umap:2.0.2
redis:
condition: service_healthy
image: umap/umap:2.9.3
ports:
- "${PORT-8000}:8000"
environment:
@ -23,6 +35,8 @@ services:
- SITE_URL=https://umap.local/
- UMAP_ALLOW_ANONYMOUS=True
- DEBUG=1
- WEBSOCKET_ENABLED=1
- REDIS_URL=redis://redis:6379
volumes:
- data:/srv/umap/uploads

View file

@ -9,5 +9,5 @@ umap collectstatic --noinput
umap wait_for_database
# then migrate the database
umap migrate
# run uWSGI
exec uwsgi --ini docker/uwsgi.ini
# run the server
exec uvicorn --proxy-headers --no-access-log --host 0.0.0.0 umap.asgi:application

View file

@ -1,26 +0,0 @@
[uwsgi]
http = :$(PORT)
home = /venv
module = umap.wsgi:application
master = True
vacuum = True
max-requests = 5000
processes = 4
enable-threads = true
static-map = /static=/srv/umap/static
static-map = /uploads=/srv/umap/uploads
buffer-size = 32768
; Run the websocket server only when the env variable
; WEBSOCKET_ENABLED is set to True.
; This is enough for the base docker image, but does not
; take into account the settings as the source of truth.
if-env = WEBSOCKET_ENABLED
websocket_enabled = %(_)
endif =
if-opt = websocket_enabled=True
print = Starting the Websocket Server (WEBSOCKET_ENABLED=%(websocket_enabled))
attach-daemon = umap run_websocket_server
endif =
lazy-apps = true

View file

@ -354,52 +354,7 @@ Otherwise, use any valid [python-social-auth configuration](https://python-socia
#### WEBSOCKET_ENABLED
A WebSocket server is packaged with uMap, and can be turned-on to activate
"real-time collaboration". In practice, in order to enable it, a few settings
are exposed.
Setting `WEBSOCKET_ENABLED` to `True` will allow users to enable real-time collaboration.
A switch will be available for them in the "advanced properties" of the map.
Setting `WEBSOCKET_ENABLED` to `True` will **not** enable real-time
collaboration on all the maps served by the server. Instead, a switch will be
available in the "advanced properties" of the map.
The websocket server can be started with the following command:
```bash
umap run_websocket_server
```
And can take optional settings `--host` and `--port` (default values are defined in
the settings).
Configuration example:
```python
WEBSOCKET_ENABLED = True
WEBSOCKET_BACK_HOST = "localhost"
WEBSOCKET_BACK_PORT = 8002
WEBSOCKET_FRONT_URI = "ws://localhost:8002"
```
These settings can also be set with the (same names) environment variables.
#### WEBSOCKET_BACK_HOST
#### WEBSOCKET_BACK_PORT
The internal host and port the websocket server will connect to.
#### WEBSOCKET_FRONT_URI
The connection string that will be used by the client to connect to the
websocket server. In practice, as it's useful to put the WebSocket server behind
TLS encryption, the values defined by `WEBSOCKET_FRONT_URI` are different than
the values defined by `WEBSOCKET_BACK_PORT` and `WEBSOCKET_BACK_HOST`.
This value is comprised of three parts:
```
protocol://host:port
```
- `protocol`: can either be `ws` for plain unencrypted WebSockets, or `wss` when using TLS encryption.
- `host`: is the address where the connection will be sent. It should be public facing.
- `port`: is the port that is open on the host.
See [the documentation about ASGI deployment](../deploy/asgi.md) for more information.

View file

@ -14,7 +14,7 @@ services:
app:
# Check https://hub.docker.com/r/umap/umap/tags to find the latest version
image: umap/umap:2.0.2
image: umap/umap:2.9.3
ports:
# modify the external port (8001, on the left) if desired, but make sure it matches SITE_URL, below
- "8001:8000"
@ -48,3 +48,45 @@ User accounts can be managed via the Django admin page ({SITE_URL}/admin). The r
```bash
umap createsuperuser
```
## Developping with Docker
If you want to develop with podman or docker, here are commands that might be useful, given that you have a postgreSQL server running locally and that your settings are located at `umap.conf`:
You can build the docker image with:
```bash
podman build -t umap .
```
And run it with:
```bash
podman run -v ./umap.conf:/tmp/umap.conf -e UMAP_SETTINGS=/tmp/umap.conf -it --network host umap
```
## Real time collaboration
To enable real time collaboration when using Docker, a Redis service must be added. Something like this in `docker-compose.py` world:
```yaml title="docker-compose.yml"
services
redis:
image: redis:latest
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
command: ["redis-server"]
app:
depends_on:
redis:
condition: service_healthy
environment:
- WEBSOCKET_ENABLED=1
- REDIS_URL=redis://redis:6379
```

View file

@ -65,7 +65,7 @@ test = [
"moto[s3]==5.1.1"
]
docker = [
"uwsgi==2.0.28",
"uvicorn==0.34.0",
]
s3 = [
"django-storages[s3]==1.14.5",
@ -73,6 +73,7 @@ s3 = [
sync = [
"pydantic==2.11.1",
"redis==5.2.1",
"websockets==15.0.1",
]
[project.scripts]

View file

@ -346,4 +346,4 @@ WEBSOCKET_ENABLED = env.bool("WEBSOCKET_ENABLED", default=False)
WEBSOCKET_BACK_HOST = env("WEBSOCKET_BACK_HOST", default="localhost")
WEBSOCKET_BACK_PORT = env.int("WEBSOCKET_BACK_PORT", default=8001)
REDIS_URL = "redis://localhost:6379"
REDIS_URL = env("REDIS_URL", default="redis://localhost:6379")