SupervisorPerDjango » Cronologia » Versione 2
Versione 1 (Mark Caglienzi, 13-12-2013 17:47) → Versione 2/3 (Simone Piccardi, 11-12-2014 18:21)
h1. Uso di Supervisor per controllare più istanze di Django
"Supervisor":http://supervisord.org è presente in Debian, e permette il controllo (avvio, stop, riavvio automatico, logging, eccetera) di programmi che devono essere monitorati nel loro funzionamento. In questa guida si avvieranno e si gestiranno quattro istanze del devserver di un'applicazione Django in locale.
Per ogni approfondimento riguardo a supervisor, si rimanda alla "documentazione ufficiale":http://supervisord.org.
*NB*: Supervisor "non funziona con Python 3":http://supervisord.org/introduction.html#platform-requirements.
h2. Prerequisiti
* @# apt-get install supervisor@
* Progetto django in @/home/utente/projects/django/@
h2. Configurazione di supervisor
Debian installa supervisor e avvia il demone @supervisord@ con il file @/etc/supervisor/supervisord.conf@ che contiene queste direttive:
<pre>
; supervisor config file
[unix_http_server]
file=/var/run/supervisor.sock ; (the path to the socket file)
chmod=0700 ; sockef file mode (default 0700)
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP)
; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket
; The [include] section can just contain the "files" setting. This
; setting can list multiple files (separated by whitespace or
; newlines). It can also contain wildcards. The filenames are
; interpreted as relative to this file. Included files *cannot*
; include files themselves.
[include]
files = /etc/supervisor/conf.d/*.conf
</pre>
e come si vede il demone risponde alla unix socket @/var/run/supervisor.sock@, e @supervisorctl@ (software che presenta una shell di controllo) usa questa socket per inviare comandi al demone (che serviranno per monitorare, avviare, riavviare, fermare i servizi configurati).
Grazie alla direttiva @[include]@ supervisor carica file di configurazione aggiuntivi dalla directory @/etc/supervisor/conf.d/@, quindi questo file può essere lasciato così (a meno di aver bisogno di settaggi particolari).
h3. Creazione del file @django.conf@
Come si vedrà, i file di configurazione di supervisor supportano la sintassi python per fare output di valori come se si scrivesse in una stringa ("qui":http://supervisord.org/configuration.html?highlight=python#configuration-file la pagina che spiega approfonditamente, con esempi, questa funzionalità).
Si crei il file @/etc/supervisor/conf.d/django.conf@ per la gestione delle istanze di django (in questo esempio si useranno i devserver):
<pre>
[program:django]
numprocs=4
directory=/home/utente/projects/django
command=python manage.py runserver 80%(process_num)02d
process_name=%(program_name)s_%(process_num)02d
user=utente
redirect_stderr=true
stdout_logfile=/home/utente/projects/django/supervisor_stdout_%(process_num)02d.log
stopsignal=KILL
stopasgroup=true
killasgroup=true
</pre>
La sezione @[program:django]@ contiene quindi le impostazioni di base per gestire 4 istanze di django. Le singole righe significano:
* Numero di processi da avviare.
* Directory in cui entrare prima di eseguire il comando.
* Comando da eseguire per ogni processo avviato (dato che @numprocs@ è stato specificato, ed è diverso da 1, bisogna che in @command@ sia presente @%(process_num)02d@ per differenziare le righe di comando). In questo esempio, con @numprocs@ che va da 0 a 3, verranno avviati 4 processi alle porte @8000@, @8001@, @8002@, @8003@.
* Nome del processo i-esimo. In questo esempio si chiameranno @django_00@, @django_01@, @django_02@, @django_03@.
* Utente da usare per lanciare i comandi. In questo esempio @supervisord@ tenta di passare all'utente @utente@, in modo da non lanciare i comandi come utente di @supervisord@ (che potrebbe essere @root@). Se questo tentativo fallisce, il comando non viene eseguito.
* Redirigere gli @stderr@ dei processi creati nei rispettivi @stdout@.
* File in cui loggare @stdout@.
* Le ultime tre righe sono necessarie per far sì che @supervisord@ riesca a killare correttamente i devserver di django senza lasciare processi orfani né bloccare le porte in caso di riavvio di un'istanza.
Di default i processi vengono avviati all'avvio di @supervisord@, ma si può impedire (@autostart=false@), si può richiedere che i processi siano sempre riavviati in caso di segnali di @KILL@ (@autorestart@), si possono configurare i timeout di attesa quando un processo cambia stato, il tipi di exit code attesi per discriminare quando un processo esce correttamente o per qualche errore/malfunzionamento (@exit_codes@), eccetera....
h2. Uso di @supervisorctl@
Questo è un programma che può essere usato per inviare comandi una tantum:
<pre>
# supervisorctl start all
</pre>
oppure avviato senza parametri perché fornisca una shell da cui poter interrogare @supervisord@:
<pre>
# supervisorctl
django:django_00 RUNNING pid 9633, uptime 0:41:34
django:django_01 RUNNING pid 9634, uptime 0:41:34
django:django_02 RUNNING pid 9648, uptime 0:41:33
django:django_03 RUNNING pid 9659, uptime 0:41:32
supervisor> help
default commands (type help <topic>):
=====================================
add clear fg open quit remove restart start stop update
avail exit maintail pid reload reread shutdown status tail version
supervisor> stop all
django_00: stopped
django_01: stopped
django_02: stopped
django_03: stopped
supervisor> start all
django_00: started
django_01: started
django_02: started
django_03: started
</pre>
Come si vede qui è possibile interrogare il demone e vedere i processi attivi, fermarli, avviarli, ed è anche presente un help in linea.
Se @supervisord@ è stato avviato da @root@, e nel file @supervisord.conf@ il setting @chmod@ è 0700, ovviamente un utente non privilegiato non potrà accedere alla socket di interrogazione, e @supervisorctl@ andrà lanciato da @root@ (come nell'esempio qui sopra).
h2. Impostazione di invio di email di avviso e di allarme via supervisor.
Il pacchetto @superlance@ consente agganciare a @supervisor@ degli utili script che consentono di osservarne gli eventi per eseguire opportune azioni. Due di questi sono particolarmente utili, il primo per notificare crash di un servizio osservato, il secondo per avvisare di un servizio fermo per un fallimento fatale. Per poterlo utilizzare è anzitutto necessario installare il relativo pacchetto python con:
<pre>
easy_install superlance
</pre>
che instellerà tutto il necessario, compresi gli script che ci interessano che verranno posti sotto @/usr/local/bin/@.
A questo punto basterà registrare sull'eventlistner di @supervisor@ i due script che ci interessano; il primo è @crashmail@, che spedisce una email tutte le volte che un servizio esce inaspettatamente con un errore, contenente il nome del servizio e le relative informazioni, per questo basta aggiungere a @/etc/supervisor/supervisord.conf@ qualcosa del tipo:
<pre>
[eventlistener:crashmail]
command=/usr/local/bin/crashmail -a -m piccardi@truelite.it
events=PROCESS_STATE
</pre>
in questo caso in genere il servizio viene riavviato automaticamente da @supervisor@.
Il secondo script, @fatalmailbatch@, tiene invece sotto ossevazione gli eventi ed invia una email di allarme (su un periodo di un minuto) quando rileva che un servizio si ferma nello stato @FATAL@, segno che @supervisor@ ha fallito nel tentativo di farlo ripartire, in questo caso occorre aggiungere a @/etc/supervisor/supervisord.conf@ qualcosa del tipo:
<pre>
[eventlistener:fatalmailbatch]
command=/usr/local/bin/fatalmailbatch --toEmail="piccardi@truelite.it" --fromEmail="supervisor@truelite.it" --subject="Alarm for a fatal crash"
events=PROCESS_STATE,TICK_60
</pre>
Si possono ovviamente attivare entrambe le notifiche aggiungendo entrambe le sezioni indicate.