Le verifiche di liveness in Kubernetes possono essere pericolose

Nota di traduzione.: L'ingegnere principale di Zalando, Henning Jacobs, ha notato più volte che gli utenti di Kubernetes hanno problemi a comprendere lo scopo delle probe di liveness (e readiness) e il loro corretto utilizzo. Pertanto, ha raccolto i suoi pensieri in questa nota concisa, che diventerà parte della documentazione K8s nel tempo.

Le verifiche di liveness in Kubernetes possono essere pericolose

Le verifiche di stato, note in Kubernetes come liveness probes (cioè, letteralmente, "test di vitalità" — nota del traduttore), possono essere piuttosto pericolose. Consiglio di evitarle quando possibile: le uniche eccezioni sono i casi in cui sono veramente necessarie e si è completamente consapevoli della specificità e delle conseguenze del loro utilizzo. In questo articolo si parlerà delle verifiche di liveness e readiness e si dirà in quali casi è opportuno e non vale la pena utilizzarle.

Il mio collega Sandor ha recentemente condiviso su Twitter gli errori più comuni che incontra, inclusi quelli relativi all'uso delle probe di readiness/liveness:

Le verifiche di liveness in Kubernetes possono essere pericolose

Una livenessProbe impostata in modo errato può aggravare le situazioni di alta carico (disattivazione a valanga + avvio potenzialmente lungo del contenitore/applicazione) e portare ad altre conseguenze negative come il crollo delle dipendenze (vedi anche il mio recente articolo sulla limitazione del numero di richieste nella combo K3s+ACME). È ancora peggio quando una liveness probe è combinata con un controllo di salute di una dipendenza (health check), in cui si trova un database esterno: un singolo malfunzionamento del database riavvierà tutti i tuoi contenitori!

Il messaggio principale "Non utilizzare le liveness probes" in questo caso aiuta poco, quindi vediamo a cosa servono le verifiche di readiness e liveness.

Nota: la maggior parte del test sottostante è stata originariamente inclusa nella documentazione interna per gli sviluppatori di Zalando.

Le verifiche di Readiness e Liveness

Kubernetes fornisce due meccanismi importanti, chiamati liveness probes e readiness probes. Essi eseguono periodicamente un'azione, ad esempio inviano una richiesta HTTP, aprono una connessione TCP o eseguono un comando nel contenitore, per confermare che l'applicazione funzioni correttamente.

Kubernetes utilizza readiness probes, per capire quando il contenitore è pronto a ricevere traffico. Un pod è considerato pronto a funzionare se tutti i suoi contenitori sono pronti. Una delle applicazioni di questo meccanismo è controllare quali pod vengono utilizzati come backend per i servizi Kubernetes (e in particolare per l'Ingress).

Le sonde di liveness aiutano Kubernetes a capire quando è il momento di riavviare il contenitore. Ad esempio, un controllo di questo tipo può intercettare un deadlock, quando un'applicazione 'si blocca' in un punto. Riavviare il contenitore in questo stato aiuta a far ripartire l'applicazione da un punto morto, nonostante gli errori, ma può anche portare a fallimenti a cascata (vedi sotto).

Se provi a distribuire un aggiornamento dell'applicazione che non supera i controlli di liveness/readiness, la distribuzione si fermerà, poiché Kubernetes attenderà lo stato Pronto da tutti i pod.

Esempio

Ecco un esempio di readiness probe che controlla il percorso /health tramite HTTP con impostazioni predefinite (intervallo: 10 secondi, timeout: 1 secondo, soglia di successo: 1, soglia di errore: 3):

# часть общего описания deployment'а/стека
podTemplate:
  spec:
    containers:
    - name: my-container
      # ...
      readinessProbe:
        httpGet:
          path: /health
          port: 8080

Raccomandazioni

  1. Per microservizi con endpoint HTTP (REST, ecc.) definisci sempre una readiness probe, che verifica se l'applicazione (pod) è pronta a ricevere traffico.
  2. Assicurati che la readiness probe verifichi la prontezza della porta effettiva del server web:
    • utilizzando porte per esigenze amministrative, denominate 'admin' o 'management' (ad esempio, 9090), per readinessProbe, assicurati che l'endpoint restituisca OK solo se la porta HTTP principale (tipo 8080) è pronta a ricevere traffico*;

      * Sono a conoscenza di almeno un caso in Zalando in cui ciò non è avvenuto, ovvero readinessProbe ha controllato la porta 'management', ma il server non è mai partito a causa di problemi di caricamento della cache.

    • aggiornare la readiness probe su una porta separata può portare al fatto che il sovraccarico sulla porta principale non venga riflesso nel controllo di salute (cioè il pool di thread sul server è pieno, ma il controllo di salute continua a mostrare che tutto va bene).
  3. Assicurati che la readiness probe includa l'inizializzazione/migrazione del database;
    • il modo più semplice per farlo è chiamare il server HTTP solo dopo che l'inizializzazione è completata (ad esempio, la migrazione del DB con Flyway ecc.); cioè, invece di modificare lo stato del controllo di salute, non avviare semplicemente il server web fino al completamento della migrazione del DB*.

      * È possibile anche eseguire migrazioni del database da contenitori init al di fuori del pod. Rimango un sostenitore delle applicazioni indipendenti, ovvero quelle in cui il contenitore dell'applicazione sa come portare il database nello stato desiderato senza coordinamento esterno.

  4. Usa httpGet per i controlli di readiness tramite endpoint tipici dei health check (ad esempio, /health).
  5. Familiarizzate con i parametri di controllo predefiniti (interval: 10s, timeout: 1s, successThreshold: 1, failureThreshold: 3):
    • i parametri predefiniti significano che il pod diventerà not-ready dopo circa 30 secondi (3 controlli di salute non riusciti).
  6. Utilizzare una porta separata per «admin» o «management», se il stack tecnologico (ad esempio, Java/Spring) lo consente, per separare la gestione della «salute» e delle metriche dal traffico normale:
    • ma non dimenticate il punto 2.
  7. Se necessario, il readiness probe può essere utilizzato per il preriscaldamento/caricamento della cache e restituire il codice di stato 503 finché il contenitore non è «pronto»:

Avvertenze

  1. Non fare affidamento su dipendenze esterne (come i database) durante i test di readiness/liveness — questo potrebbe causare fallimenti a cascata:
    • prendiamo come esempio un servizio stateful REST con 10 pod che dipendono da un singolo database Postgres: quando il controllo dipende da una connessione funzionante al database, tutti e 10 i pod possono cadere se si verifica un ritardo nella rete/o sul lato del database — di solito tutto ciò finisce peggio di quanto potrebbe;
    • si noti che Spring Data controlla la connessione al database per impostazione predefinita*;

      * Questo è il comportamento predefinito di Spring Data Redis (almeno era così quando ho controllato l'ultima volta), che ha portato a un «fallimento catastrofico»: quando Redis è stato momentaneamente non disponibile, tutti i pod sono «caduti».

    • «esterno» in questo senso può anche significare altri pod della stessa applicazione, ovvero idealmente il controllo non dovrebbe dipendere dallo stato di altri pod dello stesso cluster per prevenire cadute a cascata:
      • i risultati possono variare per applicazioni con stato distribuito (ad esempio, caching in memoria nei pod).
  2. Non utilizzare il liveness probe per i pod (fanno eccezione i casi in cui sono realmente necessari e sei completamente consapevole delle specifiche e delle conseguenze del loro utilizzo):
    • il liveness probe può aiutare a ripristinare i contenitori "bloccati", ma, poiché hai il controllo totale sulla tua applicazione, cose come i processi "bloccati" e i deadlock non dovrebbero idealmente verificarsi: la migliore alternativa è un arresto intenzionale dell'applicazione e il suo ripristino a uno stato stabile precedente;
    • un liveness probe fallito porterà al riavvio del contenitore, potenzialmente aggravando le conseguenze degli errori legati al caricamento: il riavvio del contenitore comporterà un'interruzione (almeno durante il tempo di avvio dell'applicazione, diciamo, per più di 30 secondi), causando nuovi errori, aumentando il carico su altri contenitori e aumentando la probabilità che anche questi vadano in errore, ecc.;
    • i liveness probe abbinati a una dipendenza esterna costituiscono la peggiore delle combinazioni possibili, causando fallimenti a cascata: un piccolo ritardo lato DB porterà al riavvio di tutti i tuoi contenitori!
  3. I parametri dei liveness e readiness probe devono essere diversi:
    • puoi usare il liveness probe con lo stesso controllo di salute, ma con una soglia di attivazione più alta (failureThreshold), ad esempio, assegnare uno stato not-ready dopo 3 tentativi e considerare che il liveness probe sia fallito dopo 10 tentativi;
  4. Non utilizzare controlli exec, poiché presentano problemi noti che portano alla comparsa di processi zombie:

Riepilogo

  • Utilizza i readiness probes per determinare quando un pod è pronto per ricevere traffico.
  • Utilizza i liveness probes solo quando sono realmente necessari.
  • Un uso errato dei readiness/liveness probes può portare a una diminuzione della disponibilità e a fallimenti a cascata.

Le verifiche di liveness in Kubernetes possono essere pericolose

Ulteriori materiali sull'argomento

Aggiornamento n. 1 del 29-09-2019

Sugli init-container per la migrazione del DB: nota aggiunta.

EJ mi ha ricordato il PDB: una delle difficoltà dei liveness probe è la mancanza di coordinamento tra i pod. In Kubernetes ci sono Pod Disruption Budgets (PDB) per limitare il numero di guasti parallelamente che un'applicazione può subire, tuttavia i controlli non considerano il PDB. Idealmente, possiamo istruire K8s: «Riavvia un pod se il suo controllo fallisce, ma non riavviarli tutti, per non peggiorare ulteriormente la situazione».

Bryan ha formulato benissimo: «Utilizza il liveness probing quando sei sicuro che la cosa migliore da fare sia 'uccidere' l'applicazione» (anche in questo caso, non esagerare).

Le verifiche di liveness in Kubernetes possono essere pericolose

Aggiornamento n. 2 del 2019-09-29

Per quanto riguarda la lettura della documentazione prima dell'uso: ho creato una richiesta corrispondente (richiesta di funzione) per integrare la documentazione sui liveness probes.

P.S. dal traduttore

Leggi anche nel nostro blog:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS 🔥 Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS - ProHoster