Une meilleure façon de redémarrer / recharger Gunicorn (via Upstart) après 'git pull'ing mes projets Django
Je cherche quelque chose de mieux que sudo restart projectname
chaque fois que j'émet un git pull origin master
, qui abaisse mes dernières modifications à un projet Django. Cette commande restart
, je crois, est liée à Upstart, que j'utilise pour démarrer / top mon processus de serveur Gunicorn.
Ce redémarrage provoque une brève panne. Les utilisateurs qui frappent le serveur web (nginx) recevront un 500, Car Gunicorn redémarre toujours. En fait, il semble redémarrer instantanément, mais il faut quelques secondes pour le chargement des pages.
Des idées sur la façon de faire cela sans couture? Idéalement, je voudrais émettre mes git pull
et Gunicorn rechargements automatiquement.
5 réponses
Pour un rechargement gracieux, vous devriez plutôt utiliser la commande reload
de Upstart, par exemple:
sudo reload jobname
Selon la page de manuel initctl (Upstart) , reload
envoie un signal HUP
au processus:
reload JOB [KEY=VALUE]...
Sends the SIGHUP signal to running process of the named JOB instance.
...ce qui pour Gunicorn déclenchera un redémarrage gracieux (voir FAQ).
Vous pouvez dire à Gunicorn de recharger gracieusement en utilisant le signal HUP
comme ceci:
kill -HUP <pid>
(voir la FAQ pour plus de détails)
J'utilise Supervisor pour contrôler mon serveur Gunicorn, ce qui me permet d'utiliser cette façon (légèrement hacky) de recharger Gunicorn après un déploiement:
supervisorctl status gunicorn | sed "s/.*[pid ]\([0-9]\+\)\,.*/\1/" | xargs kill -HUP
Vous pouvez évidemment réaliser quelque chose de similaire avec pidof
, ou ps
.
Ceci est en fait exécuté à partir d'un script Fabric , donc je n'ai même pas besoin de me connecter au serveur à tout.
Pour ceux qui n'utilisent pas supervisord: ce que Rob a dit, cela fonctionne aussi avec ps,
ps aux |grep gunicorn |grep projectname | awk '{ print $2 }' |xargs kill -HUP
Systemd, gunicorn et Ubuntu
Voici le One-liner, si vous utilisez votre service gunicorn avec systemd .
systemctl status gunicorn | sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP
Détails étape par étape
Puisque les documents gunicorn indiquent que la bonne façon de recharger gracieusement les travailleurs est d'utiliser kill -HUP <Main PID>
, où <Main PID>
est l'id de processus du processus maître, nous extrayons le PID maître en utilisant systemctl, et exécutons kill -HUP <Main PID>
.
1) Obtenir des informations sur le processus à partir de systemd en utilisant le nom de le service
systemctl status gunicorn
Où gunicorn
est le nom du service, située à /etc/systemd/system/
.
Exemple de sortie:
ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn
● gunicorn.service - Gunicorn server for yourproject.com
Loaded: loaded (/etc/systemd/system/gunicorn.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2017-11-04 19:16:24 UTC; 1h 15min ago
Main PID: 10673 (gunicorn)
CGroup: /system.slice/gunicorn.service
├─10673 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
├─11069 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
├─11070 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
└─11071 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
Nov 04 20:27:04 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:27:04 +0000] [11047] [INFO] Booting worker with pid: 11047
Nov 04 20:27:04 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:27:04 +0000] [11048] [INFO] Booting worker with pid: 11048
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [10673] [INFO] Handling signal: hup
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [10673] [INFO] Hang up: Master
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11046] [INFO] Worker exiting (pid: 11046)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11047] [INFO] Worker exiting (pid: 11047)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11048] [INFO] Worker exiting (pid: 11048)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11069] [INFO] Booting worker with pid: 11069
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11070] [INFO] Booting worker with pid: 11070
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11071] [INFO] Booting worker with pid: 11071
2) récupère l'ID de processus (PID) du processus gunicorn principal
Le sed commande fonctionne comme suit: sed 's/<search this>/<replace with this>/g'
-
s
signifie pour l' remplacer commande, etg
signifie que la recherche de l'ensemble de l'input mondiale. - l'indicateur
-n
indique à sed pas à d'imprimer chaque ligne (ou en fait, de ne pas imprimer quoi que ce soit.) - Le
p
à la fin indique à sed de imprimer le contenu de la ligne. - nous recherchons
.*Main PID: \(.*\)$
, qui est un modèle d'expression régulière, qui a les parties suivantes:.*
correspond à n'importe quel caractère (.
) zéro fois ou plus (*
). Ensuite, nous recherchonsMain PID:
suivi de tous les caractères, répétés zéro ou plusieurs fois (.*
). Pour capturer tous les caractères après leMain PID:
- text, nous enfermons le.*
entre parenthèses, qui sont échappés avec barre oblique inverse:\(.*\)
.$
indique la fin de la ligne. - la partie" remplacer par cette " de la commande sed est juste
\1
, ce qui signifie le premier ensemble de caractères capturé.
Exemple de sortie:
ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn | sed -n 's/.*Main PID: \(.*\)$/\1/g p'
10673 (gunicorn)
3) débarrassez - vous des caractères supplémentaires
Acheminez la sortie vers cut . Le cut -f1 -d' '
signifie, que
- la chaîne est délimitée par un espace: ici
-d
détermine le délimiteur, qui est le caractère juste après le-d
. Puisque le délimiteur est espace, nous joignons cela entre guillemets. -
-f
signifie juste que la coupe est faite en utilisant le délimiteur (et non en octets), et-f1
signifie que nous voulons prendre le premier élément de la liste.
Exemple de sortie:
ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn | sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' '
10673
4) Utilisez le PID principal
Piping à xargs signifie simplement exécuter la commande avec des arguments du tuyau sur le côté gauche. Puisque nous sifflons juste le PID principal à xargs,
systemctl status gunicorn-django | sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP
Est fondamentalement la même chose chose comme
echo <Main PID > | xargs kill -HUP
Qui se traduit par
kill -HUP <Main PID >
Modifier
Une solution un peu plus robuste serait d'utiliser cut -f1 -d$'\n'
ou grep -m1 ""
devant cut -f1 -d' '
, pour ne choisir que la première ligne du match. Je ne peux pas comprendre les circonstances, où il y aurait deux matches pour le Main PID:
, cependant.
Nous exécutons Gunicorn sous superviseur, mais c'est le moyen le plus simple et le plus propre que nous ayons trouvé pour recharger gracieusement Gunicorn quand il est confus:
sudo pkill -HUP -f gunicorn.*master