Jak przeprowadzasz migracje baz danych Django przy użyciu Docker-Compose?

107

Skonfigurowałem aplikację Docker Django / PostgreSQL ściśle według instrukcji szybkiego startu Django na stronie Docker .

Kiedy po raz pierwszy uruchamiam migrację manage.py Django za pomocą polecenia sudo docker-compose run web python manage.py migrate, działa to zgodnie z oczekiwaniami. Baza danych jest dobrze zbudowana wewnątrz kontenera Docker PostgreSQL.

Zmiany dokonane w samej aplikacji Django są również odzwierciedlane w kontenerze Docker Django, w momencie ich zapisywania. Wspaniale!

Ale jeśli następnie zmienię model w Django i spróbuję zaktualizować bazę danych Postgres, aby pasowała do modelu, żadne zmiany nie zostaną wykryte, więc migracja nie nastąpi, niezależnie od tego, ile razy uruchomię makemigrationslub migrateponownie.

Zasadniczo za każdym razem, gdy zmieniam model Django, muszę usunąć kontenery Dockera (używając sudo docker-compose rm ) i zacząć od nowa z nową migracją.

Nadal próbuję się skupić na Dockerze i jest strasznie dużo rzeczy, których nie rozumiem, jak to działa, ale to doprowadza mnie do szału. Dlaczego migracja nie wyświetla moich zmian? Co ja robię źle?

Jan
źródło
Czy wiesz, dlaczego? Otrzymuję odpowiedź poniżej i działa: You just have to log into your running docker container and run your commands.ale jaki jest powód, dla którego tak się zachowuje? @LouisBarranqueiro
lukik

Odpowiedzi:

113

Wystarczy zalogować się do uruchomionego kontenera docker i uruchomić polecenia.

  1. Zbuduj swój stos: docker-compose build -f path/to/docker-compose.yml
  2. Uruchom swój stos: docker-compose up -f path/to/docker-compose.yml
  3. Wyświetl Docker z uruchomionymi kontenerami: 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. Pobierz ID KONTENERA swojej aplikacji django i zaloguj się do:
docker exec -t -i 66175bfd6ae6 bash
  1. Teraz jesteś zalogowany, a następnie przejdź do odpowiedniego folderu: cd path/to/django_app

  2. A teraz za każdym razem, gdy edytujesz swoje modele, uruchom w swoim kontenerze: python manage.py makemigrationsipython manage.py migrate

Polecam również użycie docker-entrypoint, aby Twój plik kontenera docker django działał automatycznie:

  • kolekcjonerski
  • migrować
  • runerver lub uruchom go za pomocą gunicorn lub uWSGI

Oto przykład ( 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
źródło
16
Polecam również użycie docker-entrypoint, aby twój plik kontenera docker django działał automatycznie - takie operacje nigdy nie powinny być uruchamiane automatycznie - mam na myśli zwłaszcza migrację .
Opal
7
Nie ma znaczenia, w jakim środowisku jesteś - wdrożenie powinno zawsze wyglądać tak samo. Jeśli migracje są zautomatyzowane, mogą być uruchamiane równolegle, co jest wysoce odradzane. Np. Na heroku - migracje nigdy nie są uruchamiane jako część wdrożenia.
Opal
5
zwięźle? Tutaj jesteśmy w dev env. Biegnę makemigrations. następnym razem, gdy uruchomię mój stos, migratezaktualizuje bazę danych z cofniętymi ostatnimi migracjami, w przeciwnym razie aplikacja django nie będzie działać poprawnie ... To tylko skrót w dev env, aby upewnić się, że masz odpowiedni schemat bazy danych z bieżącą aplikacją
Louis Barranqueiro
2
@LouisBarranqueiro, miałem na myśli wiele instancji, jedną bazę danych.
Opal
1
W kroku 4 polecam: docker exec -ti $ CONTAINER_ID / bin / sh
Santiago Magariños
51

Używam tej metody:

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

Korzystając z dockerutworzonej przez nas hierarchii, migracja usługi przebiega po skonfigurowaniu bazy danych, a przed uruchomieniem usługi głównej. Teraz, gdy uruchomisz usługę docker, migracje zostaną uruchomione przed uruchomieniem serwera; Wygląda na to, że migrationserwer jest stosowany na tym samym obrazie, co serwer WWW, oznacza to, że wszystkie migracje zostaną pobrane z twojego projektu, unikając problemów.

Unikniesz w ten sposób punktu wejścia lub czegokolwiek innego.

SalahAdDin
źródło
2
Jak build: .działa, gdy pojawia image: się błąd, że migracja nie może pobrać nazwanego obrazu
Aaron McMillin
2
Postanowiłem go poprzez umieszczenie build:na migrationponieważ to będzie działać, zanimweb
Aaron McMillin
4
Czy to nie powoduje, że obraz uzmana działa i zużywa pamięć RAM na zawsze? Co to jest obraz uzmana?
mlissner
To mój niestandardowy obraz dockera, ale nie testowałem jeszcze pamięci RAM.
SalahAdDin
33

Uruchom stos, a następnie wyślij jednorazowe polecenie uruchamiania docker-compose. Na przykład

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

Działa to świetnie w przypadku wbudowanej (domyślnej) bazy danych SQLite, ale także w przypadku zewnętrznej dokeryzowanej bazy danych, która jest wymieniona jako zależność. Oto przykład pliku 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
źródło
12

Możesz użyć docker execpolecenia

docker exec -it container_id python manage.py migrate
SuperNova
źródło
1
To powinna być odpowiedź.
tolga
Aby uzyskać wspomniany identyfikator_kontenera, zrób, docker psa następnie poszukaj kolumny COMMAND dla serwera django.
Jai Sharma
6

Jeśli masz coś takiego w swoim 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

Następnie możesz po prostu uruchomić ...

~$ docker-compose exec app python manage.py makemigrations
~$ docker-compose exec app python manage.py migrate
Robert Johnstone
źródło
2

Wiem, że to jest stare i może czegoś mi brakuje (jeśli tak, proszę mnie oświecić!), Ale dlaczego nie dodać poleceń do swojego start.shskryptu, uruchamianego przez Dockera, aby uruchomić instancję? Zajmie to tylko kilka dodatkowych sekund.

NB ustawiłemDJANGO_SETTINGS_MODULE zmienną, aby upewnić się, że używana jest poprawna baza danych, ponieważ używam różnych baz danych do programowania i produkcji (chociaż wiem, że nie jest to „najlepsza praktyka”).

To rozwiązało to dla mnie:

#!/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
źródło
1

Używając docker exec, otrzymywałem następujący błąd:

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

Więc zamiast tego użyłem tego polecenia:

docker-compose -f local.yml run django python manage.py makemigrations
Santiago Magariños
źródło