Project

General

Profile

SupervisorPerDjango » History » Version 3

Simone Piccardi, 12/11/2014 06:22 PM

1 1 Mark Caglienzi
h1. Uso di Supervisor per controllare più istanze di Django
2 1 Mark Caglienzi
3 1 Mark Caglienzi
"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.
4 1 Mark Caglienzi
5 1 Mark Caglienzi
Per ogni approfondimento riguardo a supervisor, si rimanda alla "documentazione ufficiale":http://supervisord.org.
6 1 Mark Caglienzi
7 1 Mark Caglienzi
*NB*: Supervisor "non funziona con Python 3":http://supervisord.org/introduction.html#platform-requirements.
8 1 Mark Caglienzi
9 1 Mark Caglienzi
h2. Prerequisiti
10 1 Mark Caglienzi
11 1 Mark Caglienzi
* @# apt-get install supervisor@
12 1 Mark Caglienzi
* Progetto django in @/home/utente/projects/django/@
13 1 Mark Caglienzi
14 1 Mark Caglienzi
h2. Configurazione di supervisor
15 1 Mark Caglienzi
16 1 Mark Caglienzi
Debian installa supervisor e avvia il demone @supervisord@ con il file @/etc/supervisor/supervisord.conf@ che contiene queste direttive:
17 1 Mark Caglienzi
18 1 Mark Caglienzi
<pre>
19 1 Mark Caglienzi
; supervisor config file
20 1 Mark Caglienzi
21 1 Mark Caglienzi
[unix_http_server]
22 1 Mark Caglienzi
file=/var/run/supervisor.sock   ; (the path to the socket file)
23 1 Mark Caglienzi
chmod=0700                       ; sockef file mode (default 0700)
24 1 Mark Caglienzi
25 1 Mark Caglienzi
[supervisord]
26 1 Mark Caglienzi
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
27 1 Mark Caglienzi
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
28 1 Mark Caglienzi
childlogdir=/var/log/supervisor            ; ('AUTO' child log dir, default $TEMP)
29 1 Mark Caglienzi
30 1 Mark Caglienzi
; the below section must remain in the config file for RPC
31 1 Mark Caglienzi
; (supervisorctl/web interface) to work, additional interfaces may be
32 1 Mark Caglienzi
; added by defining them in separate rpcinterface: sections
33 1 Mark Caglienzi
[rpcinterface:supervisor]
34 1 Mark Caglienzi
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
35 1 Mark Caglienzi
36 1 Mark Caglienzi
[supervisorctl]
37 1 Mark Caglienzi
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL  for a unix socket
38 1 Mark Caglienzi
39 1 Mark Caglienzi
; The [include] section can just contain the "files" setting.  This
40 1 Mark Caglienzi
; setting can list multiple files (separated by whitespace or
41 1 Mark Caglienzi
; newlines).  It can also contain wildcards.  The filenames are
42 1 Mark Caglienzi
; interpreted as relative to this file.  Included files *cannot*
43 1 Mark Caglienzi
; include files themselves.
44 1 Mark Caglienzi
45 1 Mark Caglienzi
[include]
46 1 Mark Caglienzi
files = /etc/supervisor/conf.d/*.conf
47 1 Mark Caglienzi
</pre>
48 1 Mark Caglienzi
49 1 Mark Caglienzi
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).
50 1 Mark Caglienzi
51 1 Mark Caglienzi
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).
52 1 Mark Caglienzi
53 1 Mark Caglienzi
h3. Creazione del file @django.conf@
54 1 Mark Caglienzi
55 1 Mark Caglienzi
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à).
56 1 Mark Caglienzi
Si crei il file @/etc/supervisor/conf.d/django.conf@ per la gestione delle istanze di django (in questo esempio si useranno i devserver):
57 1 Mark Caglienzi
58 1 Mark Caglienzi
<pre>
59 1 Mark Caglienzi
[program:django]
60 1 Mark Caglienzi
numprocs=4
61 1 Mark Caglienzi
directory=/home/utente/projects/django
62 1 Mark Caglienzi
command=python manage.py runserver 80%(process_num)02d
63 1 Mark Caglienzi
process_name=%(program_name)s_%(process_num)02d
64 1 Mark Caglienzi
user=utente
65 1 Mark Caglienzi
redirect_stderr=true
66 1 Mark Caglienzi
stdout_logfile=/home/utente/projects/django/supervisor_stdout_%(process_num)02d.log
67 1 Mark Caglienzi
stopsignal=KILL
68 1 Mark Caglienzi
stopasgroup=true
69 1 Mark Caglienzi
killasgroup=true
70 1 Mark Caglienzi
</pre>
71 1 Mark Caglienzi
72 1 Mark Caglienzi
La sezione @[program:django]@ contiene quindi le impostazioni di base per gestire 4 istanze di django. Le singole righe significano:
73 1 Mark Caglienzi
74 1 Mark Caglienzi
* Numero di processi da avviare.
75 1 Mark Caglienzi
* Directory in cui entrare prima di eseguire il comando.
76 1 Mark Caglienzi
* 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@.
77 1 Mark Caglienzi
* Nome del processo i-esimo. In questo esempio si chiameranno @django_00@, @django_01@, @django_02@, @django_03@.
78 1 Mark Caglienzi
* 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.
79 1 Mark Caglienzi
* Redirigere gli @stderr@ dei processi creati nei rispettivi @stdout@.
80 1 Mark Caglienzi
* File in cui loggare @stdout@.
81 1 Mark Caglienzi
* 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.
82 1 Mark Caglienzi
83 1 Mark Caglienzi
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....
84 1 Mark Caglienzi
85 1 Mark Caglienzi
h2. Uso di @supervisorctl@
86 1 Mark Caglienzi
87 1 Mark Caglienzi
Questo è un programma che può essere usato per inviare comandi una tantum:
88 1 Mark Caglienzi
89 1 Mark Caglienzi
<pre>
90 1 Mark Caglienzi
# supervisorctl start all
91 1 Mark Caglienzi
</pre>
92 1 Mark Caglienzi
93 1 Mark Caglienzi
oppure avviato senza parametri perché fornisca una shell da cui poter interrogare @supervisord@:
94 1 Mark Caglienzi
95 1 Mark Caglienzi
<pre>
96 1 Mark Caglienzi
# supervisorctl 
97 1 Mark Caglienzi
django:django_00                   RUNNING    pid 9633, uptime 0:41:34
98 1 Mark Caglienzi
django:django_01                   RUNNING    pid 9634, uptime 0:41:34
99 1 Mark Caglienzi
django:django_02                   RUNNING    pid 9648, uptime 0:41:33
100 1 Mark Caglienzi
django:django_03                   RUNNING    pid 9659, uptime 0:41:32
101 1 Mark Caglienzi
supervisor> help
102 1 Mark Caglienzi
103 1 Mark Caglienzi
default commands (type help <topic>):
104 1 Mark Caglienzi
=====================================
105 1 Mark Caglienzi
add    clear  fg        open  quit    remove  restart   start   stop  update 
106 1 Mark Caglienzi
avail  exit   maintail  pid   reload  reread  shutdown  status  tail  version
107 1 Mark Caglienzi
108 1 Mark Caglienzi
supervisor> stop all
109 1 Mark Caglienzi
django_00: stopped
110 1 Mark Caglienzi
django_01: stopped
111 1 Mark Caglienzi
django_02: stopped
112 1 Mark Caglienzi
django_03: stopped
113 1 Mark Caglienzi
supervisor> start all
114 1 Mark Caglienzi
django_00: started
115 1 Mark Caglienzi
django_01: started
116 1 Mark Caglienzi
django_02: started
117 1 Mark Caglienzi
django_03: started
118 1 Mark Caglienzi
</pre>
119 1 Mark Caglienzi
120 1 Mark Caglienzi
Come si vede qui è possibile interrogare il demone e vedere i processi attivi, fermarli, avviarli, ed è anche presente un help in linea.
121 1 Mark Caglienzi
122 1 Mark Caglienzi
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).
123 2 Simone Piccardi
124 2 Simone Piccardi
125 2 Simone Piccardi
h2. Impostazione di invio di email di avviso e di allarme via supervisor. 
126 2 Simone Piccardi
127 2 Simone Piccardi
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:
128 2 Simone Piccardi
129 2 Simone Piccardi
<pre>
130 2 Simone Piccardi
easy_install superlance
131 2 Simone Piccardi
</pre> 
132 2 Simone Piccardi
133 2 Simone Piccardi
che instellerà tutto il necessario, compresi gli script che ci interessano che verranno posti sotto @/usr/local/bin/@.
134 2 Simone Piccardi
135 2 Simone Piccardi
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:
136 2 Simone Piccardi
137 2 Simone Piccardi
<pre>
138 2 Simone Piccardi
[eventlistener:crashmail]
139 3 Simone Piccardi
command=/usr/local/bin/crashmail -a -m sviluppatore@dominio.it
140 2 Simone Piccardi
events=PROCESS_STATE
141 2 Simone Piccardi
</pre>
142 2 Simone Piccardi
143 2 Simone Piccardi
in questo caso in genere il servizio viene riavviato automaticamente da @supervisor@.
144 2 Simone Piccardi
145 2 Simone Piccardi
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:
146 2 Simone Piccardi
147 2 Simone Piccardi
<pre>
148 2 Simone Piccardi
[eventlistener:fatalmailbatch]
149 3 Simone Piccardi
command=/usr/local/bin/fatalmailbatch --toEmail="sistemista@dominio.it" --fromEmail="supervisor@dominio.it" --subject="Alarm for a fatal crash"
150 2 Simone Piccardi
events=PROCESS_STATE,TICK_60
151 2 Simone Piccardi
</pre>
152 2 Simone Piccardi
153 2 Simone Piccardi
Si possono ovviamente attivare entrambe le notifiche aggiungendo entrambe le sezioni indicate.