Vinay Varma

Live reload of a webserver inside a docker container

Environemnt setup errors are always annoying. They suck time better than mousquitoes suck blood. I had a clean environment inside a docker image. The docker file looked like this:

FROM python:3.10

# install necessary system level packages

WORKDIR /my-server
COPY ./requirements.txt /my-server/requirements.txt

# install python depndencies
RUN pip install --no-cache-dir --upgrade -r /my-server/requirements.txt

COPY ./src /my-server/src
COPY ./tools /my-server/tools
COPY ./application.py /my-server/application.py

EXPOSE 5000

CMD ["uvicorn", "application:application", "--host", "0.0.0.0", "--port", "5000"]

and a docker-compose file like this

version: "3.7"

services:
  fastapi:
    build: .
    image: my-server-fastapi
    ports:
      - 5000:5000
    container_name: fastapi
    environment:
      - ENVIRONMENT=${ENVIRONMENT}
  worker:
    build: .
    image: my-server-worker
    command: bash tools/run-worker.sh
    container_name: worker
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}

Since my local env was broken, whenever I had to make a test call, I did docker-compose up --build. While this was working, I had to stop and restart the docker containers for ever code change. I needed a way to enable live reload inside the docker containers but I did not want to modify the existing Dockerfle or the docker-compose.yaml file.

I thought attaching the code as a volume to the docker containers to override the code (copied inside at docker image build time) would solve the issue but it did not. The trick was to add WATCHFILES_FORCE_POLLING=true as a env variable.

I added a docker-compose.dev.yaml file like this:

version: "3.7"

services:
  fastapi:
    build: .
    image: my-server-fastapi
    ports:
      - 5000:5000
    container_name: fastapi-dev
    working_dir: /my-server
    command: uvicorn application:application --host 0.0.0.0 --reload --port 5000 # hostname had to be 0.0.0.0 for 5000 port to be exposed to the host machine.
    volumes:
      - ./src:/my-server/src
      - ./tools:/my-server/tools
      - ./application.py:/my-server/application.py
    environment:
      - WATCHFILES_FORCE_POLLING=true
      - ENVIRONMENT=${ENVIRONMENT}

and I spun up the server like this:

docker-compose -f docker-compose.dev.yaml up --build

This way I could enable live reload inside the docker containers (where I have a working environment) without making adjustments on the original Dockerfile and the docker-compose.yaml file on which deployments depend on.

Reference about WATCHFILES_FORCE_POLLING env variable