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?
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 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, --reload
flag rechargera automatiquement gunicorn après tout scp/rsync.docker-compose build web && docker-compose up -d
). Cela peut être plus lent que l'approche rsync si votre dossier src est volumineux.
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!
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.