Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run flask_migrate in Docker

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?

like image 608
maslak Avatar asked Mar 18 '19 14:03

maslak


2 Answers

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
like image 140
prithajnath Avatar answered Sep 29 '22 13:09

prithajnath


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 base service 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.
  • You might face some kind of race conditioning where your database is not actually ready for connections and your django application tries to connect to it. So in order to solve this issue you will need to use wait-for-it or wait-for as explained in the following answer
like image 40
Mostafa Hussein Avatar answered Sep 29 '22 14:09

Mostafa Hussein