Docker image - setup uplinks

What I’m trying to do:
I’m trying to run an instance locally via docker. I have it running, and now I’m trying to access things via a server uplink, but I’m not able to find how to do it.

What I’ve tried and what’s not working:

I see on the documentation,

      --uplink-key KEY                      Key to connect server (privileged) uplinks to this app
      --client-uplink-key KEY               Key to connect client (unprivileged) uplinks to this app

but I’m looking through the docker info, https://github.com/anvil-works/anvil-runtime/tree/4b804c5fc4b11e051359f4542897b700f66834c3/packaging/app-server, it doesn’t seem like it creates uplinks

I think I’m understanding the structure and think I can create my own container based on the Dockerfile, but I wanted to check if I’m missing something or if there’s something I can do before going that route.

I use this regularly, so I can confirm it all works fine.

You start your app server with the --uplink-key argument you found in the docs. Set that to something and keep a note of it.

Then, when you write your uplink script, use that key in your anvil_server.connect call.

Thank you!

Do you by any chance have it setup via docker or did you manually installed everything?

Trying to find out what should be the best way to handle this.

I use docker. As long as you bind a port correctly in your docker file, you can connect a script using uplink from the host machine.

So am I correct in that there’s nothing on the prebuilt image and that all I need to do is modify the dockerfile, add --uplink-key and a value to it and build it?

I don’t know what prebuilt image you’re referring to, but yes, you need to start the server with the uplink key argument in the docker file and build an image from it.

Now that I’m back at a proper keyboard instead of a phone, here’s a little more detail of how I do things…

I use a Dockerfile that’s almost identical to the one you linked to above:

FROM python:3

RUN apt-get -yyy update && apt-get -yyy install \
    software-properties-common \
    postgresql-client \
&&  wget -O- https://apt.corretto.aws/corretto.key | apt-key add - && \
    add-apt-repository 'deb https://apt.corretto.aws stable main'

RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
    (dpkg -i google-chrome-stable_current_amd64.deb || apt install -y --fix-broken) && \
    rm google-chrome-stable_current_amd64.deb


RUN apt-get -yyy update && apt-get -yyy install java-1.8.0-amazon-corretto-jdk ghostscript

COPY anvil_app/requirements.txt ./
RUN pip install -r requirements.txt
RUN anvil-app-server || true

VOLUME /apps
WORKDIR /apps

RUN mkdir /anvil-data

RUN useradd anvil
RUN chown -R anvil:anvil /anvil-data
USER anvil

I generally have packages that need to be installed on the server and those are defined in a requirements.txt file, so you can see a few extra lines for that.

I’ve also removed the ENTRYPOINT and CMD commands because I handle those using docker compose. Here’s a typical docker compose file for the anvil app server:

version: '3'
services:
  anvil:
    build:
        context: .
        dockerfile: Dockerfile
    ports:
      - 3030:3030
    volumes:
      - ./anvil_app:/apps/<my app>
      - ./anvil_app/.anvil-data:/anvil-data
    command: anvil-app-server --data-dir /anvil-data --app /apps/<my app> --uplink-key ${ANVIL_UPLINK_KEY} --auto-migrate
    environment:
      - ANVIL_UPLINK_KEY=${ANVIL_UPLINK_KEY}
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:3030 || exit 1"]
      interval: 20s
      timeout: 10s
      retries: 5

I use a .env file to hold various config options - e.g. ANVIL_UPLINK_KEY - but you could instead hard code that into the command.

If I need convenient access to the database, I use one of the official postgres docker images, add a ‘database’ service to the docker compose file and add the --database option to the app server startup command. I often also add a pgadmin container and docker compose service for that.

For a production system, I use either Gitlab CI/CD or Github Actions to build my docker images and store them in either Gitlab Container Registry or Github Container Registry. A new build is triggered whenever a change is merged to the main branch of the app.

On the production host, I have the docker compose and .env files and nothing else - the only difference being that the docker compose file has an image entry pointing to whichever registry I used instead of the build options.

Finally, I add Watchtower and Portainer services to the docker compose file. Watchtower monitors the registry and automatically pulls the image and restarts the container whenever it detects a change. Portainer gives me a convenient web front end to the containers so I can start/stop them and view the logs from my browser.

My workflow is then to work on my app, merge into main when I’m happy with my changes and watch my production app refresh and restart automatically a few minutes later.

3 Likes

Owe, Thank you! This is perfect.

By prebuilt image I meant the one that Anvil has here, Docker Hub.

I was able to build an image based on the previous dockerfile with a key to test and it works, but I like your setup better with docker-compose. I’ll switch to this.

I really appreciate your detailed setup! I’m wanting to do some work on this and it’ll just be quicker to have it all locally right now. It’s also good knowing that if anything happens, we can self-host it.

This is amazing. Thanks again!

1 Like