Как вы выполняете миграцию базы данных Django при использовании Docker-Compose?

110

Я установил приложение Docker Django / PostgreSQL, внимательно следуя инструкциям Django Quick Start на сайте Docker .

Когда я в первый раз запускаю Django manage.py migrate, используя эту команду sudo docker-compose run web python manage.py migrate, он работает должным образом. База данных прекрасно встроена в контейнер Docker PostgreSQL.

Изменения, внесенные в само приложение Django, также отражаются в контейнере Docker Django, когда я их сохраняю. Здорово!

Но если я затем изменю модель в Django и попытаюсь обновить базу данных Postgres, чтобы она соответствовала модели, никаких изменений не обнаруживается, поэтому миграция не происходит независимо от того, сколько раз я запускаю makemigrationsили migrateснова.

По сути, каждый раз, когда я меняю модель Django, мне приходится удалять контейнеры Docker (используя sudo docker-compose rm) и начинать заново с новой миграцией.

Я все еще пытаюсь разобраться в Docker, и я очень многого не понимаю в том, как он работает, но этот сводит меня с ума. Почему миграция не видит мои изменения? Что я делаю не так?

Джон
источник
Вы выяснили, почему? Я получил ответ ниже, и он работает: You just have to log into your running docker container and run your commands.но по какой причине он так себя ведет? @LouisBarranqueiro
lukik

Ответы:

115

Вам просто нужно войти в свой запущенный контейнер докеров и выполнить свои команды.

  1. Создайте свой стек: docker-compose build -f path/to/docker-compose.yml
  2. Запустите свой стек: docker-compose up -f path/to/docker-compose.yml
  3. Отображение контейнеров с запущенным докером: 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. Получите CONTAINER ID вашего приложения django и войдите в:
docker exec -t -i 66175bfd6ae6 bash
  1. Теперь вы вошли в систему, затем перейдите в нужную папку: cd path/to/django_app

  2. И теперь, каждый раз, когда вы редактируете свои модели, запускайте в своем контейнере: python manage.py makemigrationsиpython manage.py migrate

Я также рекомендую вам использовать точку входа в докер, чтобы ваш файл контейнера докеров django запускался автоматически:

  • коллективный
  • мигрировать
  • runserver или запустите его с помощью gunicorn или uWSGI

Вот пример ( 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
Луи Барранкейро
источник
16
Я также рекомендую вам использовать точку входа в докер, чтобы ваш файл контейнера докеров django запускался автоматически - такие операции никогда не должны запускаться автоматически - я имею в виду особенно миграцию .
Opal
7
Неважно, в какой среде вы находитесь - развертывание всегда должно выглядеть одинаково. Если миграции автоматизированы, они могут выполняться одновременно, что крайне не рекомендуется. Например, на heroku - миграции никогда не выполняются как часть развертывания.
Opal
5
по совместительству? Здесь мы находимся в среде разработки. Я бегу makemigrations. в следующий раз, когда я запущу свой стек, я migrateобновлю базу данных с помощью последних отмененных миграций, иначе приложение django не будет работать правильно ... Это просто ярлык в dev env, чтобы убедиться, что вы получили правильную схему базы данных с текущим приложением
Луи Барранкейро
2
@LouisBarranqueiro, я имел в виду несколько экземпляров, одну БД.
Opal
1
Для шага 4 я бы порекомендовал: docker exec -ti $ CONTAINER_ID / bin / sh
Сантьяго Магариньос,
51

Я использую такой метод:

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

Используя dockerсозданную нами иерархию, миграция службы выполняется после настройки базы данных и до запуска основной службы. Теперь, когда вы запустите, ваша служба dockerбудет запускать миграции перед запуском сервера; посмотрите, что migrationсервер применяется к тому же изображению, что и веб-сервер, это означает, что все миграции будут взяты из вашего проекта, чтобы избежать проблем.

Таким образом вы избегаете создания точки входа или чего-то еще.

СалахАддин
источник
2
Как build: .работает image: я получаю сообщение об ошибке, что миграция не может извлечь указанное изображение
Аарон Макмиллин,
2
Я решил это, поместив build:на , migrationтак как он будет работать доweb
Аарон Макмиллин
5
Разве это не заставляет образ uzman работать и постоянно потреблять оперативную память? А что такое узманское изображение?
mlissner
Это мой кастомный образ докера, ОЗУ пока не тестировал.
SalahAdDin
33

Запустите свой стек, а затем запустите однократную команду запуска docker-compose. Например

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

Это отлично работает для встроенной (по умолчанию) базы данных SQLite, но также и для внешней докеризованной базы данных, которая указана как зависимость. Вот пример файла 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/

Оливер Шоу
источник
12

Вы можете использовать docker execкоманду

docker exec -it container_id python manage.py migrate
Сверхновая звезда
источник
1
Это должен быть ответ.
Толга
Чтобы получить упомянутый container_id, выполните, docker psа затем найдите столбец COMMAND для сервера django.
Джай Шарма
6

Если у вас есть что-то подобное в вашем 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

Тогда вы можете просто запустить ...

~$ docker-compose exec app python manage.py makemigrations
~$ docker-compose exec app python manage.py migrate
Роберт Джонстон
источник
3

Я знаю, что это устарело, и, возможно, мне что-то здесь не хватает (если да, просветите меня!), Но почему бы просто не добавить команды в свой start.shскрипт, запускаемый Docker для запуска вашего экземпляра? Это займет всего несколько дополнительных секунд.

NB. Я установил DJANGO_SETTINGS_MODULEпеременную, чтобы убедиться, что используется правильная база данных, поскольку я использую разные базы данных для разработки и производства (хотя я знаю, что это не «лучшая практика»).

Это решило это для меня:

#!/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
источник
1

Используя docker exec, я получал следующую ошибку:

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

Поэтому вместо этого я использовал эту команду:

docker-compose -f local.yml run django python manage.py makemigrations
Сантьяго Магариньос
источник