compartir - Una mejor forma de reiniciar/recargar Gunicorn(a través de Upstart) después de ''git pull''ing mis proyectos de Django
actualizar repositorio github (5)
Estoy buscando algo mejor que sudo restart projectname
cada vez que sudo restart projectname
un git pull origin master
, que saca mis últimos cambios a un proyecto de Django. Este comando de restart
, creo, está relacionado con Upstart, que utilizo para iniciar / finalizar mi proceso de servidor de Gunicorn.
Este reinicio provoca una breve interrupción. Los usuarios que accedan al servidor web (nginx) recibirán 500, porque Gunicorn todavía está reiniciando. De hecho, parece reiniciarse instantáneamente, pero la página tarda unos segundos en cargarse.
¿Alguna idea sobre cómo hacer esto sin interrupciones? Idealmente, me gustaría emitir mi git pull
y las recargas de Gunicorn automáticamente.
Systemd, gunicornio y Ubuntu
Aquí está el one-liner, si está ejecutando su servicio de gunicorn con systemd .
systemctl status gunicorn | sed -n ''s/.*Main PID: /(.*/)$//1/g p'' | cut -f1 -d'' '' | xargs kill -HUP
Detalles paso a paso
Dado que el FAQ dice que la forma correcta de volver a cargar correctamente a los trabajadores es usando kill -HUP <Main PID>
, donde <Main PID>
es la identificación del proceso maestro, extraemos el PID maestro usando systemctl, y ejecuta kill -HUP <Main PID>
.
1) Obtenga información sobre el proceso desde systemd utilizando el nombre del servicio
systemctl status gunicorn
donde gunicorn
es el nombre del servicio, ubicado en /etc/systemd/system/
.
Ejemplo de salida:
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) Obtener el ID de proceso (PID) del proceso principal de Armeria
El comando sed funciona de la siguiente manera: sed ''s/<search this>/<replace with this>/g''
-
s
significa para el comando sustitutivo , yg
significa que busca toda la entrada globalmente . - La
-n
indica a sed que no imprima todas las líneas (o, de hecho, que no imprima nada). - La
p
al final le dice a sed que imprima la línea correspondiente . - Buscamos
.*Main PID: /(.*/)$
, Que es un patrón de expresión regular, que tiene las siguientes partes:..*
Coincide con cualquier carácter (.
) Cero o más veces (*
). Luego buscamosMain PID:
seguido de cualquier carácter, repetido cero o más veces (.*
). Para capturar todos los caracteres después delMain PID:
-text, incluimos.*
Entre paréntesis, que se escapan con barras diagonales inversas:/(.*/)
.$
indica el final de línea. - La parte "reemplazar con esto" del comando sed es simplemente
/1
, lo que significa el primer conjunto de caracteres capturados.
Ejemplo de salida:
ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn | sed -n ''s/.*Main PID: /(.*/)$//1/g p''
10673 (gunicorn)
3) Deshacerse de los personajes adicionales
Pipe la salida para cut . El cut -f1 -d'' ''
significa que
- La cadena está delimitada por espacios: Aquí
-d
determina el delimitador, que es el caracter justo después de la-d
. Como el delimitador es espacio, lo incluimos entre comillas. -
-f
significa que el corte se realiza utilizando el delimitador (y no por bytes), y-f1
significa que queremos extraer el primer elemento de la lista.
Ejemplo de salida:
ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn | sed -n ''s/.*Main PID: /(.*/)$//1/g p'' | cut -f1 -d'' ''
10673
4) Usa el PID principal
La canalización a xargs significa simplemente ejecutar el comando con argumentos de la tubería en el lado izquierdo. Como estamos conectando solo el PID principal a xargs,
systemctl status gunicorn-django | sed -n ''s/.*Main PID: /(.*/)$//1/g p'' | cut -f1 -d'' '' | xargs kill -HUP
es básicamente lo mismo que
echo <Main PID > | xargs kill -HUP
que se traduce en
kill -HUP <Main PID >
Editar
Una solución un poco más sólida sería usar cut -f1 -d$''/n''
o grep -m1 ""
delante de cut -f1 -d'' ''
, para seleccionar solo la primera línea del partido. No puedo imaginar ninguna circunstancia, donde habría dos coincidencias para el Main PID:
sin embargo.
Ejecutamos Gunicorn bajo Supervisor, pero esta es la forma más simple y limpia que hemos encontrado para recargar graciosamente Gunicorn cuando se confunde:
sudo pkill -HUP -f gunicorn.*master
Para aquellos que no usan supervisord: lo que Rob dijo, también funciona con ps,
ps aux |grep gunicorn |grep projectname | awk ''{ print $2 }'' |xargs kill -HUP
Para una recarga elegante, en su lugar debe usar el comando de reload
de Upstart, por ejemplo:
sudo reload jobname
De acuerdo con la página de manual initctl (Upstart), reload
enviará una señal HUP
al proceso:
reload JOB [KEY=VALUE]...
Sends the SIGHUP signal to running process of the named JOB instance.
... que para Gunicorn desencadenará un reinicio elegante (ver FAQ ).
Puedes decirle a Gunicorn que recargue con gracia usando la señal HUP
así:
kill -HUP <pid>
(ver las FAQ para más detalles)
Utilizo Supervisor para controlar mi servidor de Gunicorn, lo que me permite usar esta forma (ligeramente hacky) de volver a cargar Gunicorn después de una implementación:
supervisorctl status gunicorn | sed "s/.*[pid ]/([0-9]/+/)/,.*//1/" | xargs kill -HUP
Obviamente podrías lograr algo similar con pidof
o ps
.
En realidad, se ejecuta desde un script Fabric , por lo que ni siquiera tengo que iniciar sesión en el servidor.