Tengo un proyecto con la siguiente estructura:
proj src application app.py manage.py migrations Dockerfile docker-compose.yaml
Mi objetivo es ejecutar migraciones desde el directorio de la aplicación para crear tablas en la base de datos durante la composición de la ventana acoplable.
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
¿Cómo puedo hacer eso?
¿Qué hay de usar un tercer contenedor para esta tarea? Como debe ejecutarse solo una vez, hasta donde yo sé, agregarlo a un punto de entrada podría no ser lo mejor que se puede hacer, a menos que tenga algunos controles para evitar ejecutarlo cada vez que se inicia el contenedor, incluso si no dañará, es un proceso innecesario de hacer.
El uso de un tercer contenedor hará lo siguiente:
Cuando ejecute docker-compose up
, se iniciará de acuerdo con el orden que desee, ejecutará el comando y luego saldrá. Con respecto a la ruta, puede crear un volumen con nombre compartido entre el contenedor de la aplicación real y el contenedor de la tarea de migración. Por ejemplo:
He agregado un servicio
base
para evitar la duplicación en el 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
Otras notas:
links
porque docker-compose por defecto crea una red.expose
también, el contenedor verá el puerto del otro siempre que estén en la misma red.wait-for-it
o wait-for
como se explica en la siguiente respuestaprobemos con docker-compose.yml
--- version: "3" services: web: links: - "db" build: . ports: - "5000:5000" volumes: - .:/code entrypoint: - python - manage.py - db - upgrade 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
Agregaría un script bash que tenga los comandos que desea ejecutar durante el inicio y lo usaría como el punto de entrada predeterminado en su imagen. Por lo general, es una buena práctica llamar a este script entrypoint.sh
#!/usr/bin/env bash python manage.py db upgrade flask run --host=0.0.0.0
Y luego, en su Dockerfile, reemplace la última línea con la siguiente
RUN chmod u+x ./entrypoint.sh ENTRYPOINT ["./entrypoint.sh"]
Si desea ejecutar el comando de actualización solo en la redacción de Docker, en lugar de cambiar el punto de entrada predeterminado en la imagen, puede anularlo en el archivo de redacción de esta manera
web: links: - "db" build: . ports: - "5000:5000" volumes: - .:/code depends_on: - db entrypoint: /code/entrypoint.sh env_file: - .env