Analizzeremo le basi del logging in Docker e Kubernetes, e poi esamineremo due strumenti che possono essere utilizzati tranquillamente in produzione: Grafana Loki e il stack EFK (Elasticsearch + Fluent Bit + Kibana).
Il materiale dell'articolo è un riassunto di . Se hai desiderio e, soprattutto, necessità produttiva, puoi seguire un corso completo su .

Logging in Docker.
A livello di Kubernetes, le applicazioni sono eseguite nei pod, ma a un livello inferiore funzionano di solito in Docker. Pertanto, è necessario configurare il logging in modo da raccogliere i log dai container. I container vengono avviati da Docker — quindi è fondamentale capire come è strutturato il logging a livello di Docker.
Spero che ogni lettore sappia: i log dell'applicazione devono essere scritti in stdout/stderr e non all'interno del container. I log sono aggregati dal Docker Daemon, e lui lavora precisamente con i log che vengono inviati a stdout/stderr. Inoltre, scrivere i log all'interno del container comporta dei problemi: il container si gonfia a causa del log in crescita (poiché probabilmente non c'è Logrotate nel container), e Docker Daemon non è a conoscenza di questo log.
Docker ha diversi driver di log o plugin per la raccolta dei log dei container. Nella versione gratuita di Docker Community Edition (CE) ci sono meno driver di log rispetto alla versione commerciale Docker Enterprise Edition (EE).

Non ho mai utilizzato Docker EE nella pratica: in Southbridge cerchiamo di attenerci a soluzioni Open Source, e la maggior parte delle funzionalità aggiuntive di Docker EE non è necessaria per i clienti.
Driver di log in Docker CE:
local — scrittura dei log in file interni del Docker Daemon;
json-file — creazione di un json-log nella cartella di ogni container;
journald — invio dei log a journald.
Le impostazioni di logging in Docker si trovano nel file daemon.json.
Nel campo “log-driver” si indica il plugin, e nel campo “log-opts” le sue impostazioni. Nell'esempio sopra è indicato il plugin “json-file”, con una limitazione sulle dimensioni del log — “max-size”: “10m”; limitazione sul numero di file (impostazioni di rotazione) — “max-file”: “3”; così come i valori che verranno allegati ai log.

Alcune impostazioni del driver di log possono essere impostate tramite l'utilità da riga di comando. È comodo se è necessario avviare un container separato con un driver di log diverso.
Ecco come appare lo schema di logging in Docker:

Come funziona lo schema: il log driver, ad esempio json-file, crea dei file. I raccoglitori di log (Rsyslog, Fluentd, Logagent e altri) raccolgono questi file e li inviano per l'archiviazione in Elastic, Sematext o altri storage.
Caratteristiche del logging in Kubernetes
In termini semplici, lo schema di logging in Kubernetes appare così: c'è un pod, all'interno c'è un container, il container invia i log a stdout/stderr. Successivamente, Docker crea un file e registra i log, che possono essere ruotati.

Consideriamo le peculiarità del logging in Kubernetes.
Conservare i log tra i deployment. Questa è una condizione necessaria per la corretta configurazione del logging. Se non si conservano i log tra i deployment, con l'uscita di una nuova versione dell'applicazione i log precedenti verranno sovrascritti, e il riavvio del container comporterà anche la perdita dei log. In Kubernetes c'è un'opzione —previous, che consente di visualizzare i log dell'applicazione fino all'ultimo riavvio del Pod, ma non oltre.
Aggregare i log da tutte le istanze. Se i microservizi sono ospitati nel cloud, il provider cloud si occupa del controllo del sistema. Se i microservizi sono su hardware proprio, oltre ai log dei container, è necessario raccogliere anche i log del sistema.
In passato non c'erano strumenti comodi per raccogliere i log sia dal sistema che dai microservizi. Di solito, un strumento raccoglieva i log di sistema (ad esempio, Rsyslog), mentre un altro raccolse i log da Docker (ad esempio, journal-bit configurando il log driver di Docker su journald). Abbiamo provato a usare journal-bit per raccogliere i log sia dai container (nel log driver di Docker specificare che devono essere scritti in journald), che dal sistema (in CentOS 7 ci sono già systemd e journald). La soluzione funziona, ma non è ideale. Quando ci sono troppi log, journal-bit inizia a laggare e i messaggi si perdono.
Gli esperimenti sono continuati e abbiamo trovato un altro modo. In CentOS 7 i principali log di sistema (messages, audit, secure) vengono duplicati nella var-log sotto forma di file. Anche in Docker è possibile configurare il salvataggio dei log in file json. Di conseguenza, questi file di CentOS 7 e Docker possono essere raccolti insieme.
Col tempo, è diventata popolare la soluzione ELK Stack. Questa è una combinazione di diversi strumenti: Elasticsearch, Logstash e Kibana.
Elasticsearch memorizza i log dai container, Logstash raccoglie i log dalle istanze, Kibana consente di elaborare i log ricevuti e di costruire grafici su di essi. Per un certo periodo, si è utilizzato attivamente ELK Stack, ma, a mio avviso, il suo tempo sta passando. Più avanti parlerò del perché.
Aggiungere metadati. I pod, le applicazioni e i contenitori possono essere avviati ovunque. Inoltre, un'applicazione può avere più istanze. I log sono registrati in un formato unico e noi dobbiamo capire quale replica si tratta, quale Pod l'ha scritto e in quale namespace si trova. È per questo che ai log è necessario aggiungere metadati.
Parse i log. È divertente, ma i costi per il supporto del sistema di log e monitoraggio possono superare le spese per l'applicazione principale. Quando ricevi decine e centinaia di migliaia di log al secondo, sembra ovvio, ma è comunque necessario conoscere il limite. Uno dei modi per trovare questo limite è il parsing dei log.
In generale, non è necessario raccogliere e memorizzare tutti i log, ma è sufficiente inviarne solo alcuni per la memorizzazione, ad esempio, i log con stato «warning» o «error». Se si tratta di log di nginx o controller ingress, si possono memorizzare solo quelli il cui stato è diverso da 200. Ma questo non è un consiglio universale: se stai costruendo in qualche modo un'analisi basata sui log di Nginx, è ovvio che vale la pena raccoglierli.
Non si consiglia di filtrare i log senza riflettere, perché i dati filtrati potrebbero non essere sufficienti per un'analisi adeguata. D'altra parte, forse è necessario condurre l'analisi non a livello di log, ma a livello di raccolta delle metriche. In tal modo non ci sarà bisogno di memorizzare centinaia di migliaia di righe con codice 200. Uno degli approcci consiste nell'ottenere informazioni sul traffico e sugli errori dalle metriche dei controller ingress.
In generale, qui è necessario riflettere attentamente: cosa vuoi memorizzare e per quanto tempo, altrimenti si presenterà una situazione in cui il sistema di log consumerà più risorse del progetto principale.
Attualmente non esiste una soluzione standard per la registrazione. A differenza del monitoraggio, dove esiste una soluzione predominante chiamata Prometheus, nella registrazione non c'è uno standard.
Nell'ambito di questa lezione esamineremo due strumenti: uno popolare e l'altro in aumento di popolarità. Oltre a questi, ce ne sono altri, ma in questo articolo non ne parleremo.
Tenendo conto di tutte le caratteristiche sopra esaminate, la registrazione in Kubernetes può ora essere rappresentata con il seguente schema:

Rimane il log del contenitore, la rotazione, ma appare un agente-raccoglitore che raccoglie i log e li invia per la memorizzazione (nello schema — nel Logging Backend). L'agente opera su ciascun nodo e, in genere, è avviato in Kubernetes.
Ora consideriamo gli strumenti per il logging.
Grafana Loki
È comparso di recente, ma è già diventato piuttosto noto. I suoi vantaggi: è facile da installare, consuma poche risorse e non richiede l'installazione di Elasticsearch, poiché memorizza i dati in un TSDB (time series database). Nell'articolo precedente ho scritto che Prometheus memorizza i dati in tale database, e questo è uno dei numerosi punti in comune tra i due prodotti. Gli sviluppatori affermano addirittura che Loki è "Prometheus per il mondo del logging".
Una breve digressione sul TSDB per chi non ha letto. : Il TSDB gestisce bene l'archiviazione di grandi quantità di dati di serie temporali, ma non è concepito per una conservazione prolungata. Se per qualche motivo hai bisogno di conservare i log per più di due settimane, è meglio configurare il loro invio a un'altra Banca Dati.
Un altro vantaggio di Loki è l'uso di Grafana per la visualizzazione dei dati. È molto conveniente: in Grafana guardiamo i dati di monitoraggio e collegando Loki possiamo anche vedere i log. Dai log è possibile creare grafici.
L'architettura di Loki appare più o meno così:

Tramite un DaemonSet su tutti i server del cluster viene distribuito un agente — Promtail o Fluent Bit. L'agente raccoglie i log. Loki li preleva e li memorizza nel TSDB. I log vengono aggiornati con metadati, il che è comodo: è possibile filtrare per Pods, namespaces, nomi dei contenitori e persino etichette.
Loki funziona in un'interfaccia conosciuta di Grafana. Loki ha anche un proprio linguaggio di query, chiamato LogQL, che per nome e sintassi è simile al PromQL di Prometheus. Nell'interfaccia di Loki ci sono suggerimenti per le query, quindi non è necessario conoscerle a memoria.

Loki nell'interfaccia di Grafana.
Utilizzando i filtri, in Loki è possibile trovare codici (“400”, “404” e qualsiasi altro); visualizzare i log da tutta la node; filtrare tutti i log contenenti la parola “error”. Cliccando su un log, si apre una scheda con tutte le informazioni relative all'evento.
In Loki ci sono strumenti sufficienti che permettono di estrarre i log necessari, anche se a dire il vero potrebbero essercene di più a livello tecnico. Attualmente Loki è in fase di attiva evoluzione e sta guadagnando popolarità.
Elastic + Fluent Bit + Kibana (EFK Stack)
Il stack EFK è uno strumento di logging più classico e altrettanto popolare.
All'inizio dell'articolo si menzionava ELK (Elasticsearch + Logstash + Kibana), ma questo stack è obsoleto a causa di Logstash, non molto performante e che richiede molte risorse. Al suo posto è stato utilizzato un agente più leggero e performante, Fluentd, e dopo un po' di tempo gli è stato affiancato — un agente raccoglitore ancora più leggero e più performante.
Se è vero ciò che dicono gli sviluppatori, Fluent Bit è più di 100 volte migliore in termini di prestazioni rispetto a Fluentd: «lì dove Fluentd consuma 20 MB di RAM, Fluent Bit ne consuma solo 150 KB» — una citazione diretta dalla documentazione. Guardando a questo, Fluent Bit è stato utilizzato più frequentemente.
Fluent Bit ha meno funzionalità rispetto a Fluentd, ma soddisfa le esigenze principali, quindi lo utilizziamo principalmente.
Schema di funzionamento dello stack EFK: l'agente raccoglie i log da tutti i pod (di solito è un DaemonSet in esecuzione su tutti i server del cluster) e li invia a una sorgente dati (Elasticsearch, PostgreSQL o Kafka). Kibana si collega alla sorgente dati e trae tutte le informazioni necessarie.

presenta le informazioni in un'interfaccia web comoda. Ci sono grafici, filtri e molte altre cose.

Dai log è possibile creare interi dashboard.

Funzionalità di Fluent Bit
Poiché di Fluent Bit, di solito, si sa meno rispetto a Logstash, esaminiamolo un po' più nel dettaglio. Fluent Bit può essere logicamente suddiviso in 6 moduli, a cui è possibile aggiungere plugin che espandono le funzionalità di Fluent Bit.

Modulo Input raccoglie log da file, servizi systemd e persino da socket TCP (basta indicare l'endpoint e Fluent Bit inizierà a collegarsi). Queste funzionalità sono sufficienti per raccogliere log sia dal sistema che dai container.
In produzione utilizziamo più spesso i plugin (può essere diretto su una cartella con log) e (può essere indicato da quali servizi raccogliere log).
Modulo Parser porta i log a una forma uniforme. Per impostazione predefinita, i log di Nginx sono una stringa. Con l'aiuto di un plugin, questa stringa può essere convertita in JSON: definendo i campi e i loro valori. Con JSON è molto più facile lavorare rispetto a un log basato su stringhe, perché offre possibilità di ordinamento più flessibili.
Modulo Filter. A questo livello vengono filtrati i log non necessari. Ad esempio, vengono inviati a memorizzazione solo log con valore “warning” o con determinate etichette. I log filtrati finiscono in un buffer.
Modulo Buffer. Fluent Bit ha due tipi di buffer: buffer di memoria e buffer su disco. Il buffer è uno spazio di archiviazione temporaneo per i log, necessario in caso di errori o guasti. Tutti vogliono risparmiare sulla RAM, quindi di solito si opta per il buffer su disco. Ma è importante considerare che, prima di essere scritti su disco, i log vengono comunque scaricati in memoria.
Modulo Routing/Output contiene le regole e gli indirizzi per l'invio dei log. Come già detto, i log possono essere inviati a Elasticsearch, PostgreSQL o, ad esempio, Kafka.
È interessante notare che da Fluent Bit i log possono essere inviati a Fluentd. Poiché il primo è più leggero e meno funzionale, tramite esso si possono raccogliere i log e inviarli a Fluentd, dove possono essere ulteriormente elaborati e inviati agli archivi con l'ausilio di plugin aggiuntivi.
Se prevedi di utilizzare Elasticsearch…
Infine, due consigli per chi intende utilizzare Elasticsearch in produzione come archivio di log.
- Imposta avvisi tramite . Questo programma estrae dai log unici messaggi importanti e genera alert via email o su un altro canale. Tuttavia, non molto tempo fa è emersa .
- Ruota i log utilizzando l'applicazione oppure interagendo con l'API di Elasticsearch. Di per sé, Elastic sta ora facendo passi significativi nella gestione della vita degli indici senza strumenti di terze parti. In generale, non ha senso mantenere i log a lungo: è improbabile che un log sia necessario dopo due settimane; se è veramente critico, sarà certamente stato gestito entro quel periodo. In caso estremo, i log vecchi possono essere archiviati e inviati in un luogo per la conservazione a lungo termine. Ho sentito parlare di log particolari che, per legge, devono essere conservati fino a 5 anni. Personalmente non mi sono mai trovato in una situazione simile, ma non considererei queste informazioni equivalenti ai log normali e probabilmente li conservarei separatamente.
Continua…
Autore: Marsel Abraev, amministratore certificato Kubernetes, ingegnere praticante presso , relatore e sviluppatore di corsi .
Fonte: habr.com
