diff --git a/Dockerfile b/Dockerfile index bc58c96c..d4df0f5c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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/ diff --git a/docker-compose.yml b/docker-compose.yml index eae9d801..e3b44f77 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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 diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 8ed7fdfb..c2510db9 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -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 diff --git a/docker/uwsgi.ini b/docker/uwsgi.ini deleted file mode 100644 index 02a648c6..00000000 --- a/docker/uwsgi.ini +++ /dev/null @@ -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 \ No newline at end of file diff --git a/docs/config/settings.md b/docs/config/settings.md index 5211f7b5..deea1148 100644 --- a/docs/config/settings.md +++ b/docs/config/settings.md @@ -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. diff --git a/docs/deploy/docker.md b/docs/deploy/docker.md index 7d99e80c..84ced49e 100644 --- a/docs/deploy/docker.md +++ b/docs/deploy/docker.md @@ -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 +… + +``` diff --git a/pyproject.toml b/pyproject.toml index a49dd2b6..cc08e1cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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] diff --git a/umap/settings/base.py b/umap/settings/base.py index ecb51326..1e0cdd69 100644 --- a/umap/settings/base.py +++ b/umap/settings/base.py @@ -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")