blog.notmyidea.org/content/code/2024-05-13-umap-flyio.md
2024-05-14 16:00:14 +02:00

4.5 KiB

title tags
Deploying on fly.io docker, deployment, websockets

I spent some time today deploying uMap to fly.io, using a Dockerfile. Here are some notes I took.

First, I had to install the flyctl command. On OSX, with brew, it's:

brew install flyctl

Fly is using docker containers under the hood, and provides some tools to help create the files. In the case of uMap, I already had a Dockerfile, so it wasn't necessary.

Creating an app

I created an app:

fly apps create

By answering the questions. It eventually generated a fly.toml file., that I actually rewrote to fit my needs:

app = 'umap'
primary_region = 'iad'
console_command = 'umap shell'

[build]
  dockerfile = "Dockerfile"

[[services]]
  internal_port = 8000
  protocol = 'tcp'
  processes = ["app"]

  [[services.ports]]
    handlers = ['http']
    port = 80
    force_https = true

  [[services.ports]]
    handlers = ['http', "tls"]
    port = 443

[[vm]]
  memory = '1gb'
  cpu_kind = 'shared'
  cpus = 1

The services section could be simplified by using the http_service section, but as I will need to configure websockets on a different port, it seems to be a better bet.

Creating PostgreSQL / PostGIS database

I created a postgres app, that I named postgres_umap by answering the questions asked by this command:

flyctl postgres create

Then I had to activate the PostGIS extension, by connecting to the postgres cluster…

flyctl postgres connect -a postgres-umap

… and enter this:

CREATE EXTENSION postgis

At this stage, the machine crashed, and a fly logs -a postgres-umap told me that it was out of memory. I bumped the memory a bit with this:

# got the id of the machine with
fly machine status -a postgres-umap
# and then bumped the memory to 1024mb
fly machine update 3d8dd964a25978 --vm-memory 1024 --app postgres-umap

Redoing the CREATE EXTENSION postgis; worked this time.

Once this is done, I used this utility:

fly postgres attach postgres-umap --app umap

This created users, passwords and a database for me, and set the proper secrets for my app. Neat.

I received an email telling me this costs money, so after initializing the postgis database, I scaled the instance down:

fly machine update 3d8dd964a25978 --vm-memory 256 --app postgres-umap

Handling secrets

Additionally to environment variables (which are present in the fly.toml file), I also had to define some secrets, using fly secrets:

secrets set SECRET_KEY=S0_S3CR3T

At some point, I had to unset some of them with:

secrets unset SECRET_KEY

I also added a few env vars:

[env]
  WEBSOCKET_URI = "wss://xxx.fly.dev:8001"
  WEBSOCKET_HOST = "0.0.0.0"
  WEBSOCKET_ENABLED = "True"
  UMAP_ALLOW_ANONYMOUS = "True"

Deploying

With this in place, I could deploy these two machines with fly deploy.

Adding support for WebSockets

This can change in the future, but for now, I have two servers, a WebSocket server listening on port 8001, separate from the uwsgi server listening on 443 and 80.

It is possible to define some specific commands that will replace the default CMD one of the Dockerfile.

To do this, I used the [processes] section, and named the default one django, because it's running the django server with uwsgi:

[processes]
ws = "/venv/bin/python /venv/lib/python3.11/site-packages/umap/ws.py"
django = "/srv/umap/docker/entrypoint.sh"

… and added a new services definition:

[[services]]
    internal_port = 8001
    protocol = 'tcp'
    processes = ['ws']
    
    [[services.ports]]
      handlers = ['tls']
      port = 8001

Also, I'm not sure why I had to downgrade the number of processes:

fly scale count 1 --process-group=django
fly scale count 1 --process-group=ws

Using a custom domain

I wanted this to be hosted on my domain, so I went with adding a CNAME, following this documentation:

CNAME 	xxx 	xxx.fly.dev

And then generated the SSL certs:

fly certs add xxx.domain.tld

Persisting files

Everything was working smoothly until I realize that the files weren't actually persisted. For the files to be persisted, I needed to add volumes in the toml file:

[mounts]
  source="umap_data"
  destination="/srv/umap/uploads"

And create the volumes with the cli:

fly volume create umap_data -r iad -n2
fly deploy