Comment effectuez-vous les migrations de bases de données Django lors de l'utilisation de Docker-Compose?

99

J'ai configuré une application Docker Django / PostgreSQL en suivant attentivement les instructions de démarrage rapide de Django sur le site Docker .

La première fois que j'exécute le manage.py migrate de Django, en utilisant la commande sudo docker-compose run web python manage.py migrate, cela fonctionne comme prévu. La base de données est construite à l'intérieur du conteneur Docker PostgreSQL très bien.

Les modifications apportées à l'application Django elle-même sont également reflétées dans le conteneur Docker Django, au moment où je les enregistre. C'est bien!

Mais si je change ensuite un modèle dans Django et que j'essaie de mettre à jour la base de données Postgres pour qu'elle corresponde au modèle, aucun changement n'est détecté, donc aucune migration ne se produit, quel que soit le nombre de fois que j'exécute makemigrationsou migrateencore.

En gros, chaque fois que je change le modèle Django, je dois supprimer les conteneurs Docker (en utilisant sudo docker-compose rm) et recommencer avec une nouvelle migration.

J'essaie toujours de comprendre Docker, et il y a beaucoup de choses que je ne comprends pas sur son fonctionnement, mais celui-ci me rend dingue. Pourquoi la migration ne voit-elle pas mes modifications? Qu'est-ce que je fais mal?

John
la source
Avez-vous compris pourquoi? J'obtiens la réponse ci-dessous et cela fonctionne: You just have to log into your running docker container and run your commands.mais quelle est la raison pour laquelle cela se comporte de cette façon? @LouisBarranqueiro
lukik

Réponses:

104

Il vous suffit de vous connecter à votre conteneur docker en cours d'exécution et d'exécuter vos commandes.

  1. Construisez votre pile: docker-compose build -f path/to/docker-compose.yml
  2. Lancez votre stack: docker-compose up -f path/to/docker-compose.yml
  3. Afficher les conteneurs exécutant le docker: docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
3fcc49196a84        ex_nginx          "nginx -g 'daemon off"   3 days ago          Up 32 seconds       0.0.0.0:80->80/tcp, 443/tcp   ex_nginx_1
66175bfd6ae6        ex_webapp         "/docker-entrypoint.s"   3 days ago          Up 32 seconds       0.0.0.0:32768->8000/tcp       ex_webapp_1
# postgres docker container ...
  1. Obtenez le CONTAINER ID de votre application django et connectez-vous à:
docker exec -t -i 66175bfd6ae6 bash
  1. Maintenant que vous êtes connecté, allez dans le bon dossier: cd path/to/django_app

  2. Et maintenant, chaque fois que vous modifiez vos modèles, exécutez-les dans votre conteneur: python manage.py makemigrationsetpython manage.py migrate

Je vous recommande également d'utiliser un docker-entrypoint pour que votre fichier conteneur django docker s'exécute automatiquement:

  • collecstatique
  • émigrer
  • runserver ou démarrez-le avec gunicorn ou uWSGI

Voici un exemple ( docker-entrypoint.sh):

#!/bin/bash

# Collect static files
echo "Collect static files"
python manage.py collectstatic --noinput

# Apply database migrations
echo "Apply database migrations"
python manage.py migrate

# Start server
echo "Starting server"
python manage.py runserver 0.0.0.0:8000
Louis Barranqueiro
la source
16
Je vous recommande également d'utiliser un docker-entrypoint pour que votre fichier de conteneur docker django s'exécute automatiquement - de telles opérations ne devraient jamais être exécutées automatiquement - je veux dire en particulier migrer .
Opal
7
Peu importe l'environnement dans lequel vous vous trouvez, le déploiement doit toujours se ressembler. Si les migrations sont automatisées, elles peuvent être exécutées simultanément, ce qui est fortement déconseillé. Par exemple, sur heroku - les migrations ne sont jamais exécutées dans le cadre du déploiement.
Opal
5
en même temps? Nous voici dans un environnement de développement. Je cours makemigrations. la prochaine fois que je lancerai ma pile, migratemettra à jour la base de données avec les dernières migrations annulées, sinon l'application django ne fonctionnera pas correctement ... C'est juste un raccourci dans dev env pour être sûr que vous avez le bon schéma de base de données avec l'application actuelle
Louis Barranqueiro
2
@LouisBarranqueiro, je voulais dire plusieurs instances, une seule base de données.
Opal
1
Pour l'étape 4, je recommanderais: docker exec -ti $ CONTAINER_ID / bin / sh
Santiago Magariños
52

J'utilise ces méthodes:

services:
  web:
    build: .
    image: uzman
    command: python manage.py runserver 0.0.0.0:8000
    ports:
      - "3000:3000"
      - "8000:8000"
    volumes:
      - .:/code
    depends_on:
      - migration
      - db
  migration:
    image: uzman
    command: python manage.py migrate --noinput
    volumes:
      - .:/code
    depends_on:
      - db

En utilisant la dockerhiérarchie que nous avons créée, la migration du service s'exécute après la configuration de la base de données et avant d'exécuter le service principal. Désormais, lorsque vous exécutez, votre service dockerexécutera des migrations avant d'exécuter le serveur; regardez que le migrationserveur est appliqué sur la même image que le serveur Web, cela signifie que toutes les migrations seront prises à partir de votre projet, évitant ainsi les problèmes.

Vous évitez ainsi de faire un point d'entrée ou quoi que ce soit d'autre.

SalahAdDin
la source
1
Comment build: .fonctionne avec image: J'obtiens l'erreur que la migration ne peut pas extraire l'image nommée
Aaron McMillin
2
Je l'ai résolu en mettant build:le migrationcar il fonctionnera avantweb
Aaron McMillin
4
Cela ne permet-il pas à l'image uzman de fonctionner et de consommer de la RAM pour toujours? Aussi, quelle est l'image d'Uzman?
mlissner
C'est mon image docker personnalisée, je n'ai pas encore testé la RAM.
SalahAdDin
32

Faites fonctionner votre pile, puis lancez une commande d'exécution docker-compose en un seul coup. Par exemple

#assume django in container named web
docker-compose run web python3 manage.py migrate

Cela fonctionne très bien pour la base de données SQLite intégrée (par défaut), mais également pour une base de données dockerisée externe répertoriée comme dépendance. Voici un exemple de fichier docker-compose.yaml

version: '3'

services:
  db:
    image: postgres
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

https://docs.docker.com/compose/reference/run/

Oliver Shaw
la source
12

Vous pouvez utiliser la docker execcommande

docker exec -it container_id python manage.py migrate
SuperNova
la source
1
Cela devrait être la réponse.
tolga
Pour obtenir le container_id mentionné, faites docker pset recherchez la colonne COMMAND pour le serveur django.
Jai Sharma
5

Si vous avez quelque chose comme ça dans votre docker-compose.yml

version: "3.7"

services:

  app:
    build:
      context: .
      dockerfile: docker/app/Dockerfile
    ports:
    - 8000:8000
    volumes:
        - ./:/usr/src/app
    depends_on:
      - db

  db:
    image: postgres
    restart: always
    environment:
      POSTGRES_USER: docker
      POSTGRES_PASSWORD: docker
      POSTGRES_DB: docker

Ensuite, vous pouvez exécuter simplement ...

~$ docker-compose exec app python manage.py makemigrations
~$ docker-compose exec app python manage.py migrate
Robert Johnstone
la source
2

Je sais que c'est vieux, et peut-être qu'il me manque quelque chose ici (si oui, s'il vous plaît, éclairez-moi!), Mais pourquoi ne pas simplement ajouter les commandes à votre start.shscript, exécuté par Docker pour lancer votre instance? Cela ne prendra que quelques secondes supplémentaires.

NB J'ai défini la DJANGO_SETTINGS_MODULEvariable pour m'assurer que la bonne base de données est utilisée, car j'utilise différentes bases de données pour le développement et la production (bien que je sache que ce n'est pas la «meilleure pratique»).

Cela a résolu le problème pour moi:

#!/bin/bash
# Migrate the database first
echo "Migrating the database before starting the server"
export DJANGO_SETTINGS_MODULE="edatool.settings.production"
python manage.py makemigrations
python manage.py migrate
# Start Gunicorn processes
echo "Starting Gunicorn."
exec gunicorn edatool.wsgi:application \
    --bind 0.0.0.0:8000 \
    --workers 3
TBZ92
la source
1

En utilisant docker exec, j'obtenais l'erreur suivante:

AppRegistryNotReady("Models aren't loaded yet.")

J'ai donc utilisé cette commande à la place:

docker-compose -f local.yml run django python manage.py makemigrations
Santiago Magariños
la source