web-dev-qa-db-fra.com

Rechargement automatique des modifications de code avec Django développement dans Docker avec Gunicorn

J'utilise un conteneur Docker pour le développement Django, et le conteneur exécute Gunicorn avec Nginx. J'aimerais des modifications de code pour le chargement automatique, mais la seule façon de les faire charger est en reconstruisant avec docker-compose (docker-compose build). Le problème avec "build" est qu'il réexécute toutes mes installations pip.

J'utilise le Gunicorn --reload flag, qui est censé faire ce que je veux. Voici mes fichiers de configuration Docker:

## Dockerfile:
FROM python:3.4.3
RUN mkdir /code
WORKDIR /code
ADD . /code/
RUN pip install -r /code/requirements/docker.txt

## docker-compose.yml:
web:
  restart: always
  build: .
  expose:
    - "8000"
  links:
    - postgres:postgres
  volumes:
    - /usr/src/app/static
  env_file: .env
  command: /usr/local/bin/gunicorn myapp.wsgi:application -w 2 -b :8000 --reload

nginx:
  restart: always
  build: ./config/nginx
  ports:
    - "80:80"
  volumes:
    - /www/static
  volumes_from:
    - web
  links:
    - web:web

postgres:
  restart: always
  image: postgres:latest
  volumes:
    - /var/lib/postgresql
  ports:
    - "5432:5432"

J'ai essayé certaines des autres commandes Docker (docker-compose restart, docker-compose up), mais le code ne sera pas actualisé.

Qu'est-ce que je rate?

39
Dolan Antenucci

Grâce à kikicarbonell, j'ai cherché à avoir un volume pour mon code, et après avoir regardé le Docker Compose recommandé Django setup , j'ai ajouté volumes: - .:/code à mon conteneur Web dans docker-compose.yml, et maintenant toutes les modifications de code que j'effectue s'appliquent automatiquement.

## docker-compose.yml:
web:
  restart: always
  build: .
  expose:
    - "8000"
  links:
    - postgres:postgres
  volumes:
    - /usr/src/app/static
    - .:/code
  env_file: .env
  command: /usr/local/bin/gunicorn myapp.wsgi:application -w 2 -b :8000 --reload

Update: pour un exemple complet d'utilisation de Gunicorn et Django avec Docker, consultez ceci exemple de projet de Rackspace , qui montre également comment d'utiliser docker-machine pour lancer la configuration sur des serveurs distants comme Rackspace Cloud.

Avertissement: actuellement, cette méthode ne fonctionne pas lorsque votre code est local et que l'hôte docker est distant (par exemple, sur un fournisseur de cloud comme Digital Ocean ou Rackspace ). Cela s'applique également aux machines virtuelles si votre système de fichiers local n'est pas monté sur la machine virtuelle. Notez qu'il existe des pilotes de volume séparés (par exemple, flocker), et qu'il y a - peut-être quelque chose pour répondre à ce besoin. Pour l'instant, le "correctif" consiste à rsync/scp vos fichiers jusqu'à un répertoire sur l'hôte de docker distant. Puis le --reload flag rechargera automatiquement gunicorn après tout scp/rsync.  Mise à jour: Si vous appuyez sur le code pour supprimer l'hôte docker, je trouve qu'il est beaucoup plus facile de simplement reconstruire le conteneur docker (par exemple, docker-compose build web && docker-compose up -d). Cela peut être plus lent que l'approche rsync si votre dossier src est volumineux.

34
Dolan Antenucci

Vous avez un autre problème: Docker met en cache chaque couche qu'il crée. Vous ne devriez pas avoir à relancer l'installation de pip à chaque fois!

ADD . /code/
RUN pip install -r /code/requirements/docker.txt

C'est votre problème - Docker vérifie chaque instruction ADD pour voir si des fichiers ont changé et invalide le cache pour cela et à chaque étape ultérieure si c'est le cas. La bonne façon de procéder est ...

ADD ./requirements/docker.txt /code/requirements/
RUN pip install -r /code/requirements/docker.txt
ADD ./code/

Ce qui invalidera uniquement votre ligne d'installation pip si votre fichier d'exigences change!

24
Paul Becotte

Comme je n'ai jamais trouvé de solution souhaitable, considérez ce hack intéressant. En postant ici, je voulais voir si quelqu'un avait des expériences similaires/bonnes/mauvaises avec ce "contournement".

Pour faire recharger le code localement pour le développement, j'ai simplement créé une vue qui appelle immédiatement exit(). La sortie plantera Django et un rechargement se produira là où des modifications de code sont disponibles. Le redémarrage prend une fraction de seconde et peut être effectué via un onglet du navigateur, un requests.get appel, ou tout autre appel similaire. Le rechargement n'est pas automatique mais il saute tout décalage Docker tel qu'un redémarrage.

Lorsque la sortie est appelée, vous verrez l'incrément PID (si les journaux de queue):

web    | [2019-07-15 18:29:52 +0000] [22] [INFO] Worker exiting (pid: 22)
web    | [2019-07-15 18:29:52 +0000] [24] [INFO] Booting worker with pid: 24

J'espère que cela aide les autres et/ou se nourrit de cette approche.

1
Marc