0

I have a fastapi application that connects to postgres. I've dockerized the application such that the api runs in one container and postgres runs in another container on the same network and they can talk to each other happily. I want to make some alembic migrations run every time I start the containers with docker compose up, and skip if neccessary tables and relations are already present.

I can start the api and have it talk to postgres without running the migrations (in which case requests sent to the api will cause errors due to the missing tables):

version: "3"
services:

  api:
    build: .
    depends_on:
      - postgres
    ports:
      - 8000:8000
    volumes:
      - ./:/usr/src/app
    command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload #&& alembic upgrade head
    environment:
      - HOST=postgres
      - DB
      - DB_USER
      - DB_PASSWORD
      - JWT_SECRET
      - JWT_ALGORITHM
      - JWT_EXPIRY_MINUTES
      - ALLOWED_ORIGINS

  postgres:
    image: postgres
    environment:
      - POSTGRES_PASSWORD
      - POSTGRES_DB
    volumes:
      - postgres-db:/var/lib/postgresql/data
    
volumes:
  postgres-db:

and I can run the migrations without starting the api:

version: "3"
services:

  api:
    build: .
    depends_on:
      - postgres
    ports:
      - 8000:8000
    volumes:
      - ./:/usr/src/app
    command: alembic upgrade head #&& uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
    environment:
      - HOST=postgres
      - DB
      - DB_USER
      - DB_PASSWORD
      - JWT_SECRET
      - JWT_ALGORITHM
      - JWT_EXPIRY_MINUTES
      - ALLOWED_ORIGINS

  postgres:
    image: postgres
    environment:
      - POSTGRES_PASSWORD
      - POSTGRES_DB
    volumes:
      - postgres-db:/var/lib/postgresql/data
    
volumes:
  postgres-db:

But if I use

alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

I get... sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) connection to server at "postgres" (172.25.0.2), port 5432 failed: Connection refused

and if I use

uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload && alembic upgrade head

I get... sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "users" does not exist 1-api-1 | LINE 1: INSERT INTO users (email, password) VALUES ('user1@me.com', ...

i.e. the migrations haven't run

What do I need to do to make postgres start up properly, THEN try to run the migrations, THEN start the api?

  • Have you seen https://stackoverflow.com/questions/35069027/docker-wait-for-postgresql-to-be-running ? i.e. how to make compose wait with starting your other container until postgres is ready? You can also perform the connection test in the startup-script of your own container, but having it in your compose configuration should work fine. – MatsLindh Mar 10 '23 at 20:41
  • Thanks @MatsLindh I've seen similar solutions, but if docker-compose gives us "depends_on" to wait until a db is ready to connect, isn't it kind of a hack to do it manually by setting up a health check? Surely if using just depends_on I can make uvicorn wait and have the api successfully connect without running the migrations, or successfully wait to run the migrations without starting the api, there must be some way I can make it automatically do both? – TheGreatO96 Mar 10 '23 at 20:56
  • I'm not sure what you mean, the `depends_on` check uses the defined healthcheck to determine if `service_healthy` is true - i.e., you can't have one without the other. When the command defined in `healthcheck` succeeds, `service_healthy` becomes true, and the dependent container is started. You can then run the migrations as part of your startup routine for the api (the regular way to do this is to just run the migrations every time your container start - if the db is up to date, nothing happens). – MatsLindh Mar 10 '23 at 22:02
  • I had misunderstood how depends_on and service_healthy work and after finding them in the docs I see you are now exactly correct: https://docs.docker.com/compose/compose-file/compose-file-v3/#depends_on If you'll post your first comment as an answer I'll mark it as correct @MatsLindh – TheGreatO96 Mar 10 '23 at 23:04
  • I'll mark it as a duplicate instead, as the other question/answer shows how to implement it properly with more information than what would be available in this question. Great that it solved your problem! – MatsLindh Mar 10 '23 at 23:19

0 Answers0