I have a project with the following structure:
proj
  src
    application
      app.py
      manage.py
      migrations
  Dockerfile
  docker-compose.yaml
My goal is to run migrations from the application directory to create tables in the database during docker-compose.
python manage.py db upgrade
Dockerfile
FROM python:3.7-alpine
ADD requirements.txt /code/
WORKDIR /code
RUN apk add --no-cache postgresql-dev gcc python3 musl-dev && \
    pip3 install -r requirements.txt
ADD . /code
EXPOSE 5000
WORKDIR /code/src/application
CMD ["flask", "run", "--host=0.0.0.0"]
docker-compose.yaml
---
version: "3"
services:
  web:
    links:
      - "db"
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    depends_on:
      - db
    env_file:
      - .env
  db:
    image: postgres:10
    restart: always
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=app
    ports:
      - "5432:5432"
    expose:
      - 5432
How can I do that?
I'd add a bash script that has the commands you want to run during startup and use that as the default entry point in your image. It's usually best practice to call this script entrypoint.sh
#!/usr/bin/env bash
python manage.py db upgrade
flask run --host=0.0.0.0
And then, in your Dockerfile, replace the last line with the following
RUN chmod u+x ./entrypoint.sh
ENTRYPOINT ["./entrypoint.sh"]
If you want to run the upgrade command only in Docker compose then instead of changing the default entry point in the image you can just override it in the compose file like this
  web:
    links:
      - "db"
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    depends_on:
      - db
    entrypoint: /code/entrypoint.sh
    env_file:
      - .env
                        What about using a third container for this task? As it needs to be execute only one time as far as i know, so adding it to an entrypoint might not the best thing to be done unless you have some checks to avoid running it each time the container starts even if it wont harm, its an unnecessary process to do.
Using a third container will do the following:
When you run docker-compose up it will start according to the order you want and run the command then exit. Regarding the path you may create a shared named volume between the actual application container and the migration-task container. For example:
I have added a
baseservice to avoid duplication in the docker-compose
version: "3"
services:
  base:
    build: .
    volumes:
      - .:/code
    env_file:
      - .env
    command: 'false'
  web:
    extends:
      service: base
    command: flask run --host=0.0.0.0
    links:
      - "db"
    ports:
      - "5000:5000"
    depends_on:
      - db
  db:
    image: postgres:10
    restart: always
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=app
    ports:
      - "5432:5432"
    expose:
      - 5432
  migrations:
    extends:
      service: base
    command: python manage.py db upgrade
    depends_on:
      - db
Other notes:
links is not needed because docker-compose by default creates a network.expose is not needed too, container will see each other's port as long as they are in the same network.wait-for-it or wait-for as explained in the following answer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With