Liveness probes i Kubernetes kan være farlige

Bem. overs.: Leading engineer from Zalando — Henning Jacobs — has repeatedly noticed issues among Kubernetes users regarding the understanding of the purpose of liveness (and readiness) probes and their correct application. Therefore, he has compiled his thoughts into this concise note, which will become part of the K8s documentation over time.

Liveness probes i Kubernetes kan være farlige

Health checks, known in Kubernetes as liveness probes (i.e., literally, “vitality tests” — ed. note), can be quite dangerous. I recommend avoiding them whenever possible: exceptions are only cases where they are truly necessary and you fully understand the specifics and consequences of their use. This publication will discuss liveness and readiness checks, as well as situations in which står and when not to apply them.

My colleague Sandor recently shared on Twitter the most common mistakes he encounters, including those related to the use of readiness/liveness probes:

Liveness probes i Kubernetes kan være farlige

A misconfigured livenessProbe can aggravate situations with high load (avalanche shutdown + potentially long container/application startup) and lead to other negative consequences such as crashing dependencies (see also my recent article on rate limiting in conjunction with K3s+ACME). Even worse is when a liveness probe combines with a health check for a dependency, where an external database acts as that dependency: a single database failure will restart all your containers!

The general message “Do not use liveness probes” in this case helps little, so let’s consider the purpose of readiness and liveness checks.

Note: much of the test provided below was originally included in the internal documentation for Zalando developers.

Readiness and Liveness Checks

Kubernetes provides two important mechanisms called liveness probes and readiness probes. They periodically perform some action — for example, send an HTTP request, open a TCP connection, or execute a command in the container — to confirm that the application is functioning properly.

Kubernetes uses readiness probes, for at forstå, hvornår en pod er klar til at modtage trafik. En pod anses for klar, hvis alle dens containere er klar. En af anvendelserne af denne mekanisme er at kontrollere, hvilke pods der bruges som backend for Kubernetes-tjenester (og især Ingress).

Liveness probes hjælper Kubernetes med at forstå, hvornår det er tid til at genstarte en container. For eksempel gør en sådan kontrol det muligt at opfange deadlocks, når en applikation "sidder fast". Genstart af containeren i en sådan tilstand hjælper med at få applikationen i gang igen, på trods af fejl, men det kan også føre til kaskadefejl (se nedenfor).

Hvis du forsøger at udrulle en opdatering af applikationen, der fejler liveness/readiness-tjek, vil udrulningen stoppe, da Kubernetes venter på status Klar fra alle pods.

Eksempel

Her er et eksempel på en readiness probe, der kontrollerer stien /health via HTTP med standardindstillinger (interval: 10 sekunder, timeout: 1 sekund, success threshold: 1, failure threshold: 3):

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

Anbefalinger

  1. For mikrotjenester med HTTP-endpoint (REST osv.) skal du altid definere en readiness probe, der kontrollerer, om applikationen (pod) er klar til at modtage trafik.
  2. Sørg for, at readiness probe dækker klarheden af den faktiske webserverport:
    • ved at bruge porte til administrative formål, kaldet "admin" eller "management" (f.eks. 9090), for readinessProbe, skal du sikre dig, at endpointet kun returnerer OK, hvis den primære HTTP-port (f.eks. 8080) er klar til at modtage trafik*;

      * Jeg er bekendt med mindst et tilfælde i Zalando, hvor dette ikke skete, dvs. readinessProbe kontrollerede porten "management", men selve serveren fungerede ikke på grund af problemer med indlæsning af cachen.

    • at knytte readiness probe til en separat port kan føre til, at belastningen på den primære port ikke afspejles i sundhedstjekket (dvs. serverens trådpool er fyldt, men sundhedstjekket viser stadig, at alt er OK).
  3. Sørg for, at readiness probe inkluderer initialisering/migrering af databasen;
    • den nemmeste måde at opnå dette på er at kontakte HTTP-serveren først efter afslutningen af initialiseringen (f.eks. database-migrering med Flyway osv.); det vil sige, i stedet for at ændre status på sundhedstjekket, skal du bare undlade at starte webserveren, indtil database-migreringen er afsluttet*.

      * Det kan også være muligt at køre database-migreringer fra init-containere uden for pod'en. Jeg er stadig fan af selvstændige (self-contained) applikationer, hvilket betyder, at applikationscontaineren, uden ekstern koordinering, ved, hvordan den skal bringe databasen i den rette tilstand.

  4. Brug httpGet til readiness-tjek gennem typiske endpoint-sundhedstjek (for eksempel, /health).
  5. Sæt dig ind i de standardindstillinger, der er angivet for tjek (interval: 10s, timeout: 1s, successThreshold: 1, failureThreshold: 3):
    • de standardindstillinger betyder, at pod'en vil blive not-ready efter cirka 30 sekunder (3 mislykkedes sundhedstjek).
  6. Brug en separat port til "admin" eller "management", hvis teknologi-stakken (for eksempel, Java/Spring) tillader det, for at adskille "sundhed"-styring og metrics fra almindelig trafik:
    • men glem ikke punkt 2.
  7. Hvis nødvendigt, kan readiness probe anvendes til opvarmning/læsning af cache og returnere statuskode 503, indtil containeren er "opvarmet":

Advarsler

  1. Stol ikke på eksterne afhængigheder (såsom datalagre) når du udfører readiness/liveness tests — det kan føre til kaskadefejl:
    • til eksempel, lad os tage en stateful REST-tjeneste med 10 pod'er, der afhænger af én PostgreSQL-database: når tjekket er afhængigt af en aktiv databaseforbindelse, kan alle 10 pod'er falde, hvis der opstår forsinkelse i netværket/eller på databasesiden — som regel ender alt dette værre, end det burde;
    • vær opmærksom på, at Spring Data som standard tjekker databaseforbindelsen*;

      * Dette er den standardadfærd, som Spring Data Redis har (i det mindste var det sådan, da jeg kontrollerede sidst), hvilket førte til en 'katastrofal' nedbrud: da Redis midlertidigt var utilgængelig, 'faldt' alle pod'er.

    • "ekstern" i denne sammenhæng kan også betyde andre pod'er af samme applikation, hvilket betyder, at ideelt set bør tjekket ikke være afhængigt af tilstanden af andre pod'er i samme klynge for at undgå kaskadefejl:
      • resultaterne kan variere for applikationer med distribueret tilstand (for eksempel in-memory caching i pod'er).
  2. Brug ikke liveness probe for pods (exceptions are cases where they are truly necessary, and you fully understand the specifics and consequences of their use):
    • the liveness probe can help recover "hung" containers, but since you have full control over your application, ideally, issues like "hung" processes and deadlocks should not occur: a better alternative is to intentionally crash the application and return it to a previous stable state;
    • a failed liveness probe will cause the container to restart, potentially exacerbating errors associated with loading: restarting the container will lead to downtime (at least while the application launches, say, for more than 30 seconds), causing new failures, increasing the load on other containers and raising the likelihood of their failure, etc.;
    • liveness checks combined with external dependencies are the worst possible combination, threatening cascading failures: a slight delay on the DB side will cause all your containers to restart!
  3. The parameters for liveness and readiness checks must be different:
    • you can use the liveness probe with the same health check but a higher trigger threshold (failureThreshold), for example, assign a status not-ready after 3 attempts and consider the liveness probe failed after 10 attempts;
  4. Do not use exec checks, as they are associated with known issues that lead to zombie processes:

CV

  • Use readiness probes to determine when a pod is ready to accept traffic.
  • Use liveness probes only when they are truly necessary.
  • Incorrect use of readiness/liveness probes can lead to decreased availability and cascading failures.

Liveness probes i Kubernetes kan være farlige

Additional resources on the topic

Update #1 from 2019-09-29

About init containers for DB migration: a footnote has been added.

EJ reminded me about PDB: one of the woes of liveness checks is the lack of coordination between pods. In Kubernetes, there are Pod Disruption Budgets (PDB) for at begrænse antallet af parallelle fejl, som en applikation kan opleve, men tjekningerne tager ikke højde for PDB. Ideelt set kan vi instruere K8s: „Genstart én pod, hvis dens kontrol mislykkes, men genstart ikke alle, så det ikke bliver værre.”

Bryan formulerede det perfekt: „Brug liveness probes, når du ved, at det bedste, du kan gøre, er at „dræbe” applikationen” (men lad os ikke overdrive).

Liveness probes i Kubernetes kan være farlige

Opdatering #2 fra 2019-09-29

Hvad angår at læse dokumentationen før brug: jeg har oprettet en relevant anmodning (feature request) om at tilføje dokumentationen om liveness probes.

P.S. fra oversætteren

Læs også på vores blog:

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster