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
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.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