Как я могу настроить свой экземпляр Django / Python docker так, чтобы обновления отражались немедленно? - PullRequest
3 голосов
/ 05 марта 2020

У меня есть приложение Docker 2.0 / Python 3.7, которое я загружаю в контейнер docker вместе с сопровождающими его изображениями в Интернете и базе данных (ниже приведен файл docker -compose.yml). ..

version: '3'

services:
  mysql:
    restart: always
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: 'maps_data'
      # So you don't have to use root, but you can if you like
      MYSQL_USER: 'chicommons'
      # You can use whatever password you like
      MYSQL_PASSWORD: 'password'
      # Password for root access
      MYSQL_ROOT_PASSWORD: 'password'
    ports:
      - "3406:3406"
    volumes:
      - my-db:/var/lib/mysql

  web:
    restart: always
    build: ./web
    ports:           # to access the container from outside
      - "8000:8000"
    env_file: .env
    environment:
      DEBUG: 'true'
    command: /usr/local/bin/gunicorn maps.wsgi:application -w 2 -b :8000
    depends_on:
      - mysql

  apache:
    restart: always
    build: ./apache/
    ports:
      - "9090:80"
    links:
      - web:web

volumes:
  my-db:

Вот веб-файл / файл Docker, который контролирует Django часть стека ...

FROM python:3.7-slim

RUN apt-get update && apt-get install

RUN apt-get install -y libmariadb-dev-compat libmariadb-dev
RUN apt-get update \
    && apt-get install -y --no-install-recommends gcc \
    && rm -rf /var/lib/apt/lists/*

RUN python -m pip install --upgrade pip
RUN mkdir -p /app/

WORKDIR /app/

COPY requirements.txt requirements.txt
RUN python -m pip install -r requirements.txt

COPY entrypoint.sh /app/
COPY . /app/
RUN ["chmod", "+x", "/app/entrypoint.sh"]

ENTRYPOINT ["/app/entrypoint.sh"]

Мой вопрос, есть ли способ настроить такие вещи, что когда я делаю локальное изменение в файле Python, это изменение немедленно отражается в моем работающем экземпляре Docker? Прямо сейчас, если я внесу изменение, я должен запустить

docker-compose down --rmi all
docker-compose up

Как вы можете себе представить, это длительный процесс, особенно если просто изменить один файл.

Ответы [ 4 ]

1 голос
/ 05 марта 2020

Смонтируйте источники в вашей локальной системе к источникам в docker через том и настройте веб-сервер внутри с динамической перезагрузкой при изменении файла, для сервера gunicorn это параметр --reload.

0 голосов
/ 14 марта 2020

Я бы выбрал другой подход, чем тот, который описан здесь в других ответах.

Во-первых, Django уже предоставляет вам runserver, который начинает легкий вес сервер разработки , который автоматически перезагружает код Python при каждом запросе. В большинстве случаев это самый простой способ запустить сервер разработки с автоматической перезагрузкой и всем остальным. Вы можете прочитать больше выше runserver, перейдя по предоставленной ссылке. Примечание: Вы должны убедиться, что у вас есть объект приложения WSGI, заданный параметром WSGI_APPLICATION в вашем файле конфигурации.

Вы можете запустить Django, используя команду runserver, просто запустив bash команда типа python ./manage.py runserver 0.0.0.0:8000. Перед запуском команды runserver я обычно хотел бы также выполнить команду migrate, чтобы избежать ошибок (я только что узнал об этом из опыта).

В вас docker-compose эти команды будут выглядеть примерно так:

...
  web:
    ...
    command: >
      bash -c "python ./manage.py migrate &&
               ./manage.py runserver 0.0.0.0:8000" # Simple bash command to run migrate followed by runserver
    ...

Приведенный выше код был бы идеален сам по себе, но при запуске runserver в docker-compose, как правило, вам придется ждать, пока ваша база данных завершит инициализацию sh, чтобы Django могла использовать ее (обсуждается позже в комментариях). Вы можете сделать это, создав простой файл в вашей директории web с именем wait_for_db.py и следующий код:

import os
import logging
from time import time, sleep
import MySQLdb

check_timeout = os.getenv("DB_CHECK_TIMEOUT", 30)
check_interval = os.getenv("DB_CHECK_INTERVAL", 1)
interval_unit = "second" if check_interval == 1 else "seconds"
config = {
    "dbname": os.getenv("MYSQL_DATABASE", "maps_data"),
    "user": os.getenv("MYSQL_USER", "chicommons"),
    "password": os.getenv("MYSQL_PASSWORD", "password"),
    "host": os.getenv("DATABASE_URL", "mysql")
}

start_time = time()
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logger.addHandler(logging.StreamHandler())


def db_isready(host, user, password, dbname):
    while time() - start_time < check_timeout:
        try:
            conn = MySQLdb.connect(**vars())
            logger.info("Database is ready! ✨")
            conn.close()
            return True
        except Exception:
            logger.info(f"Database isn't ready. Waiting for {check_interval} {interval_unit}...")
            sleep(check_interval)

    logger.error(f"We could not connect to the database within {check_timeout} seconds.")
    return False


db_isready(**config)

Чтобы запустить указанный выше файл в вашей docker-compose, вам потребуется чтобы обновить раздел command, как показано ниже:

...
  web:
    ...
    command: >
      bash -c "python wait_for_db.py &&
               ./manage.py migrate &&
               ./manage.py runserver 0.0.0.0:8000" # Again, note that I am simply executing a python file in a simple bash command followed by the same old migrate and runserver commands
    ....

Наконец, последний шаг (и, вероятно, самый важный), вам необходимо убедиться, что вы используете тома в Docker , что другие прекрасно объяснили в своих ответах здесь, но просто для ясности вот код для этого в вашем docker-compose файле:

...
  web:
    ...
    volumes:
    - ./web/:/app 
    # The part to the left side of the colon is the location in your computer relative to the current file, and to the left side is the location within the docker container.
    # It is app because remember in your Dockerfile, you copy everything to /app directory. ;)
    ...

Одно последнее замечание, runserver не должно быть выполняется на производстве. Как правило, на производстве вам не потребуется повторная загрузка в реальном времени, поэтому ваша более ранняя конфигурация для WSGI - это путь к go на производстве. Вам потребуется разделить файлы производства и разработки docker-compose.

0 голосов
/ 13 марта 2020

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

Docker составьте файл:

version: '3'

services:
  mysql:
    restart: always
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: 'maps_data'
      # So you don't have to use root, but you can if you like
      MYSQL_USER: 'chicommons'
      # You can use whatever password you like
      MYSQL_PASSWORD: 'password'
      # Password for root access
      MYSQL_ROOT_PASSWORD: 'password'
    ports:
      - "3406:3406"
    volumes:
      - my-db:/var/lib/mysql

  web:
    restart: always
    build: ./web
    ports:           # to access the container from outside
      - "8000:8000"
    env_file: .env
    environment:
      DEBUG: 'true'
    command: /usr/local/bin/gunicorn maps.wsgi:application -w 2 -b :8000 --reload
    volumes:
      - .:/app/           #Please update path here
    depends_on:
      - mysql

  apache:
    restart: always
    build: ./apache/
    ports:
      - "9090:80"
    links:
      - web:web

volumes:
  my-db:

Вы можно также проверить похожие вопросы:

Почему docker -компонованная сборка не отражает мои django изменения кода?

Автоматическая перезагрузка изменений кода с развитием Django в Docker с Gunicorn

0 голосов
/ 05 марта 2020

Вы можете создать том. С томом вы можете поделиться папкой между вашей машиной и контейнером docker. Это создаст том в папке Volume / web на том же уровне, что и docker -compose, и в / opt / app внутри вашего контейнера.

При этом вы можете работать локально и получать изменения отражено в вашем docker контейнере. В зависимости от вашей точки входа, вы можете остановить свое приложение и перезапустить его, не перезапуская контейнер или нет.

В gunicorn вы можете использовать опцию --reload, чтобы автоматически перезагружать сервер при наличии изменений.

  web:
    restart: always
    build: ./web
    ports:           # to access the container from outside
      - "8000:8000"
    env_file: .env
    environment:
      DEBUG: 'true'
    command: /usr/local/bin/gunicorn maps.wsgi:application -w 2 -b :8000
    depends_on:
      - mysql

    volumes:
      - ./volumes/web:/opt/app
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...