Personal tools
Usare Header HTTP per debug di server in produzione

pdb.set_trace()

Jun 30, 2015

Usare Header HTTP per debug di server in produzione

Non sarà corretto, eppure in qualche sfortunato caso può capitare di dover inserire un breakpoint in produzione. Come farlo senza ostacolare l'esperienza degli utenti?

La situazione

Un'installazione di produzione di un'applicazione Web sta facendo qualcosa che non va, c'è di sicuro un bug che si presenta solo nella configurazione di produzione e per quanto ci si sforzi non si riesce a riprodurre il problema su ambiente di test. Anche tecniche primitive come l'aggiunta di messaggi di log aggiuntivi in produzione non sono servite ad individuare il problema.

E' uno di quei casi in cui verrebbe da dire "ci vorrebbe un bel breakpoint", fermare l'esecuzione del codice per eseguire analisi... ma per ovvi motivi un breakpoint in produzione è qualcosa di delicato e non facilmente fattibile.

L'ambiente

La situazione descritta nasce da un'installazione Plone/Zope, ma la tecnica usata non è necessariamente legata a questo framework (né al mondo Python di per se).

L'architettura è composta da:

  • un web server (Apache) non sotto il nostro controllo
  • uno strato di cache/reverse-proxy di frontend (Varnish)
  • un bilanciatore di carico (HAProxy)
  • una serie di application server identici (istanze Zope  con configurazione zeoclient/zeoserver) su cui viene eseguito il bilanciamento
  • un'istanza di debug

Il debug canonico

L'istanza di debug avrebbe tutti gli strumenti per gestire al meglio la ricerca del problema (ad esempio il verbose security attivo, possibilità di modifiche al codice sorgente "live", ...) ma non viene inclusa nel bilanciamento.
Questo significa che non è raggiungibile via Web e se si sospetta che il problema sia in parte legato a qualcosa che non dipende direttamente dal nostro codice (un sistema di autenticazione utenti esterno, comportamenti non corretti del web server di front-end, ...) l'istanza di debug risulta purtroppo inutile.

Debug in produzione?

Mettere un breakpoint in produzione sarebbe quindi la strada, ma a prescindere dalla mancanza di funzionalità di debug di cui le istanze di produzione soffrono (prodotti specifici, configurazioni differenti, ...) questo porta comunque a dover affrontare il problema che il sito è live.

E necessario quindi che nessuno dei visitatori/utenti che normalmente fruiscono il servizio si trovino in una situazione di blocco della navigazione perché sono incappati nel nostro breakpoint.

La soluzione

La soluzione adottata è piuttosto semplice e comprende i seguenti strumenti:

  • Una configurazione alla modifica per Varnish
  • Un plugin di Firefox

L'idea è la seguente: inserire l'istanza di debug nella filiera delle istanze di produzione ma come backend alternativo per Varnish, in pratica il proxy di cache, che di solito ha un unico backend (il bilanciatore) in questo caso dovrebbe gestire un secondo backend bypassando il bilanciatore di carico: la nostra istanza di debug.

La modifica alla configurazione di Varnish è semplice:

backend default {
.host = "${balancer:http-host}";
.port = "${balancer:port}";
# ...
}

backend debug {
.host = "${instance-debug:host}";
.port = "${instance-debug:port}";
# ...
}

Il problema ora è istruire Varnish per farci (noi soltanto) pilotare al backend di debug. Le soluzioni sono molteplici: se semplicemente il problema si replicasse con uno specifico URL potremmo catturare la presenza di un parametro segreto nella query string, qualcosa come:

http://miohost/.../?debug=secret

Ma per casi più complicati la soluzione migliore deve essere persistente nella nostra navigazione: un cookie o un header speciale.

La soluzione adottata è un header. Esiste un comodo plugin per Firefox: Modify Headers che è utilizzabile ogni volta sia necessario manipolare gli header inviati al server.

In questo caso scegliamo un header "speciale", qualcosa come "DEBUG" e se vogliamo proprio essere paranoici anche un valore segreto.

Http Headers per Firefox

Una volta abilitato dobbiamo modificare di nuovo la configurazione di Varnish.

# ...

sub vcl_recv {
set req.grace = 120s;
set req.backend = default;

# ...

if (req.http.DEBUG == "secretsecret12390" ) {
set req.backend = debug;
}

# ...

}

Ora possiamo tranquillamente mettere il nostro breakpoint all'interno del codice sospetto ed iniziare l'analisi pur accedendo all'applicazione in produzione.

Questo stesso lavoro potrebbe essere fatto direttamente da configurazione di Apache ma come detto sopra non è scontato che il web server di front-end dell'applicazione sia sotto il nostro controllo.

...e buon debug a tutti.

comments powered by Disqus