Cinc faltes en desplegar la primera aplicació a Kubernetes

Cinc faltes en desplegar la primera aplicació a KubernetesFalla d'Aris-Dreamer

Molta gent creu que n'hi ha prou amb migrar l'aplicació a Kubernetes (ja sigui amb Helm o manualment) i estaran contents. Però no és tan senzill.

Equip Mail.ru Solucions al núvol va traduir un article de l'enginyer de DevOps Julian Gindi. Comparteix quines trampes va trobar la seva empresa durant el procés de migració perquè no trepitgis el mateix rastell.

Primer pas: Configuració de sol·licituds i límits de pod

Comencem configurant un entorn net en el qual funcionaran els nostres pods. Kubernetes fa un gran treball a l'hora de programar pods i gestionar les condicions de fallada. Però va resultar que el planificador de vegades no pot col·locar un pod si és difícil estimar quants recursos necessita per funcionar correctament. Aquí és on sorgeixen les peticions de recursos i límits. Hi ha molt de debat sobre el millor enfocament per establir peticions i límits. De vegades realment sembla que és més art que ciència. Aquí teniu el nostre enfocament.

Sol·licituds de pods - Aquest és el valor principal utilitzat pel planificador per col·locar de manera òptima el pod.

D' Documentació de Kubernetes: El pas de filtratge determina el conjunt de nodes on es pot programar el pod. Per exemple, el filtre PodFitsResources comprova si un node té prou recursos per satisfer les sol·licituds de recursos específiques d'un pod.

Utilitzem sol·licituds d'aplicacions perquè es puguin utilitzar per estimar quants recursos de fet L'aplicació necessita que funcioni correctament. D'aquesta manera, el planificador pot col·locar nodes de manera realista. Inicialment volíem establir sol·licituds amb marge per assegurar-nos que cada pod tingués un nombre suficient de recursos, però ens vam adonar que els temps de programació augmentaven significativament i alguns pods no estaven mai programats del tot, com si no s'hagués rebut cap sol·licitud de recursos per a ells.

En aquest cas, el planificador sovint expulsava pods i no podia reprogramar-los perquè el pla de control no tenia ni idea de quants recursos requeriria l'aplicació, un component clau de l'algorisme de programació.

Límits de pods - aquest és un límit més clar per a la beina. Representa la quantitat màxima de recursos que el clúster assignarà al contenidor.

De nou, des de documentació oficial: si un contenidor té un límit de memòria de 4 GiB establert, el kubelet (i el temps d'execució del contenidor) ho farà complir. El temps d'execució no permet que el contenidor utilitzi més del límit de recursos especificat. Per exemple, quan un procés d'un contenidor intenta utilitzar més de la quantitat de memòria permesa, el nucli del sistema finalitza el procés amb un error "fora de memòria" (OOM).

Un contenidor sempre pot utilitzar més recursos dels que s'especifica a la sol·licitud de recursos, però mai pot utilitzar més dels especificats al límit. Aquest valor és difícil d'establir correctament, però és molt important.

Idealment, volem que els requisits de recursos d'un pod canviïn al llarg del cicle de vida d'un procés sense interferir amb altres processos del sistema; aquest és l'objectiu d'establir límits.

Malauradament, no puc donar instruccions específiques sobre quins valors cal establir, però nosaltres mateixos ens adherim a les regles següents:

  1. Mitjançant una eina de prova de càrrega, simulem un nivell bàsic de trànsit i supervisem l'ús dels recursos del pod (memòria i processador).
  2. Establem les sol·licituds de pod en un valor arbitràriament baix (amb un límit de recursos d'unes 5 vegades el valor de les sol·licituds) i observem. Quan les sol·licituds són massa baixes, el procés no s'inicia i sovint provoca errors misteriosos en temps d'execució de Go.

Tingueu en compte que els límits de recursos més alts fan que la programació sigui més difícil perquè el pod necessita un node objectiu amb prou recursos disponibles.

Imagineu una situació en què tingueu un servidor web lleuger amb un límit de recursos molt elevat, per exemple 4 GB de memòria. És probable que aquest procés hagi d'escalar horitzontalment i cada mòdul nou s'haurà de programar en un node amb almenys 4 GB de memòria disponible. Si no existeix aquest node, el clúster ha d'introduir un nou node per processar aquest pod, cosa que pot trigar una mica. És important mantenir la diferència entre les sol·licituds de recursos i els límits al mínim per garantir un escalat ràpid i suau.

Segon pas: configurar les proves de Liveness i Readiness

Aquest és un altre tema subtil que sovint es parla a la comunitat de Kubernetes. És important tenir una bona comprensió de les proves de Liveness i Readiness, ja que proporcionen un mecanisme perquè el programari funcioni sense problemes i minimitzi el temps d'inactivitat. No obstant això, poden causar un greu rendiment de l'aplicació si no es configura correctament. A continuació es mostra un resum de com són les dues mostres.

Vida mostra si el contenidor s'està executant. Si falla, el kubelet mata el contenidor i s'habilita una política de reinici. Si el contenidor no està equipat amb una sonda Liveness, l'estat predeterminat serà correcte; això és el que diu Documentació de Kubernetes.

Les sondes de vivacitat haurien de ser barates, és a dir, no haurien de consumir molts recursos, perquè s'executen amb freqüència i han d'informar Kubernetes que l'aplicació s'està executant.

Si configureu l'opció perquè s'executi cada segon, això afegirà 1 sol·licitud per segon, així que tingueu en compte que es necessitaran recursos addicionals per gestionar aquest trànsit.

A la nostra empresa, les proves de Liveness comproven els components bàsics d'una aplicació, fins i tot si les dades (per exemple, d'una base de dades remota o una memòria cau) no són totalment accessibles.

Hem configurat les aplicacions amb un punt final de "salut" que simplement retorna un codi de resposta de 200. Això és una indicació que el procés s'està executant i que és capaç de processar sol·licituds (però encara no el trànsit).

Mostra Preparació indica si el contenidor està preparat per atendre sol·licituds. Si la sonda de preparació falla, el controlador del punt final elimina l'adreça IP del pod dels punts finals de tots els serveis corresponents al pod. Això també s'indica a la documentació de Kubernetes.

Les sondes de preparació consumeixen més recursos perquè s'han d'enviar al backend d'una manera que indiqui que l'aplicació està preparada per acceptar sol·licituds.

Hi ha molt debat a la comunitat sobre si s'ha d'accedir directament a la base de dades. Donada la sobrecàrrega (les comprovacions es realitzen amb freqüència, però es poden ajustar), vam decidir que, per a algunes aplicacions, la disposició per atendre el trànsit només es comptabilitza després de verificar que els registres es retornen des de la base de dades. Les proves de preparació ben dissenyades van assegurar nivells més alts de disponibilitat i van eliminar el temps d'inactivitat durant el desplegament.

Si decidiu consultar la base de dades per provar la preparació de la vostra aplicació, assegureu-vos que sigui el més barata possible. Prenem aquesta petició:

SELECT small_item FROM table LIMIT 1

Aquí teniu un exemple de com configurem aquests dos valors a Kubernetes:

livenessProbe: 
 httpGet:   
   path: /api/liveness    
   port: http 
readinessProbe:  
 httpGet:    
   path: /api/readiness    
   port: http  periodSeconds: 2

Podeu afegir algunes opcions de configuració addicionals:

  • initialDelaySeconds — Quants segons passaran entre el llançament del contenidor i l'inici de les mostres.
  • periodSeconds — Interval d'espera entre tirades de mostres.
  • timeoutSeconds — el nombre de segons després dels quals la unitat es considera una emergència. Temps d'espera habitual.
  • failureThreshold — el nombre d'errors de prova abans que s'enviï un senyal de reinici al pod.
  • successThreshold — el nombre de sondes reeixides abans que el pod entri a l'estat llest (després d'un error, quan el pod s'inicia o es recupera).

Pas tres: configurar les polítiques de xarxa predeterminades per al pod

Kubernetes té una topografia de xarxa "plana"; per defecte, tots els pods es comuniquen directament entre ells. En alguns casos això no és desitjable.

Un possible problema de seguretat és que un atacant podria utilitzar una única aplicació vulnerable per enviar trànsit a tots els pods de la xarxa. Com passa amb moltes àrees de seguretat, aquí s'aplica el principi del mínim privilegi. Idealment, les polítiques de xarxa haurien d'especificar explícitament quines connexions entre pods estan permeses i quines no.

Per exemple, a continuació es mostra una política senzilla que nega tot el trànsit entrant per a un espai de noms específic:

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:  
 name: default-deny-ingress
spec:  
 podSelector: {}  
 policyTypes:  
   - Ingress

Visualització d'aquesta configuració:

Cinc faltes en desplegar la primera aplicació a Kubernetes
(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)
Més detalls aquí.

Pas quatre: comportament personalitzat amb ganxos i contenidors d'inici

Un dels nostres objectius principals era oferir desplegaments a Kubernetes sense temps d'inactivitat per als desenvolupadors. Això és difícil perquè hi ha moltes opcions per tancar les aplicacions i alliberar els recursos que utilitzaven.

Van sorgir dificultats particulars amb Nginx. Ens vam adonar que quan aquests pods es van desplegar de manera seqüencial, les connexions actives es van eliminar abans de la finalització correcta.

Després d'una àmplia investigació en línia, resulta que Kubernetes no espera que les connexions Nginx s'esgotin abans d'acabar el pod. Amb un ganxo de pre-stop, vam implementar la funcionalitat següent i vam eliminar completament el temps d'inactivitat:

lifecycle: 
 preStop:
   exec:
     command: ["/usr/local/bin/nginx-killer.sh"]

Sinó nginx-killer.sh:

#!/bin/bash
sleep 3
PID=$(cat /run/nginx.pid)
nginx -s quit
while [ -d /proc/$PID ]; do
   echo "Waiting while shutting down nginx..."
   sleep 10
done

Un altre paradigma extremadament útil és l'ús de contenidors init per gestionar l'inici d'aplicacions específiques. Això és especialment útil si teniu un procés de migració de bases de dades que requereix molts recursos que s'ha d'executar abans que s'iniciï l'aplicació. També podeu especificar un límit de recursos més alt per a aquest procés sense establir aquest límit per a l'aplicació principal.

Un altre esquema comú és accedir als secrets en un contenidor d'inici que proporciona aquestes credencials al mòdul principal, cosa que impedeix l'accés no autoritzat als secrets des del mateix mòdul de l'aplicació principal.

Com és habitual, citar de la documentació: Els contenidors d'inici executen de manera segura codi personalitzat o utilitats que, d'altra manera, reduirien la seguretat de la imatge del contenidor de l'aplicació. Si manteniu les eines innecessàries separades, limiteu la superfície d'atac de la imatge del contenidor de l'aplicació.

Cinque pas: Configuració del nucli

Finalment, parlem d'una tècnica més avançada.

Kubernetes és una plataforma extremadament flexible que us permet executar les càrregues de treball de la manera que us convingui. Tenim una sèrie d'aplicacions d'alt rendiment que consumeixen molt recursos. Després de realitzar proves de càrrega exhaustives, vam descobrir que una aplicació tenia problemes per gestionar la càrrega de trànsit esperada quan la configuració predeterminada de Kubernetes estava en vigor.

Tanmateix, Kubernetes us permet executar un contenidor privilegiat que només canvia els paràmetres del nucli per a un pod específic. Això és el que hem utilitzat per canviar el nombre màxim de connexions obertes:

initContainers:
  - name: sysctl
     image: alpine:3.10
     securityContext:
         privileged: true
      command: ['sh', '-c', "sysctl -w net.core.somaxconn=32768"]

Aquesta és una tècnica més avançada que sovint no es necessita. Però si la vostra aplicació té dificultats per fer front a una càrrega pesada, podeu provar d'ajustar algunes d'aquestes configuracions. Més detalls sobre aquest procés i la configuració de diferents valors, com sempre a la documentació oficial.

en conclusió

Tot i que Kubernetes pot semblar una solució ja feta fora de la caixa, hi ha alguns passos clau que heu de seguir per mantenir les vostres aplicacions funcionant sense problemes.

Al llarg de la vostra migració a Kubernetes, és important seguir el "cicle de proves de càrrega": inicieu l'aplicació, proveu-la de càrrega, observeu mètriques i comportament d'escalat, ajusteu la configuració en funció d'aquestes dades i torneu a repetir el cicle.

Sigueu realistes sobre el trànsit previst i intenteu anar més enllà per veure quins components es trenquen primer. Amb aquest enfocament iteratiu, només algunes de les recomanacions enumerades poden ser suficients per aconseguir l'èxit. O pot requerir una personalització més profunda.

Fes-te sempre aquestes preguntes:

  1. Quants recursos consumeixen les aplicacions i com canviarà aquest volum?
  2. Quins són els requisits reals d'escala? Quant trànsit gestionarà l'aplicació de mitjana? Què passa amb el trànsit punta?
  3. Amb quina freqüència el servei haurà d'escalar horitzontalment? Amb quina rapidesa s'han de posar nous pods en línia per rebre trànsit?
  4. Com s'apaguen correctament les beines? Això és necessari en absolut? És possible aconseguir el desplegament sense temps d'inactivitat?
  5. Com podeu minimitzar els riscos de seguretat i limitar els danys de qualsevol beina compromesa? Hi ha algun servei que tingui permisos o accés que no requereixi?

Kubernetes ofereix una plataforma increïble que us permet aprofitar les millors pràctiques per desplegar milers de serveis en un clúster. Tanmateix, cada aplicació és diferent. De vegades, la implementació requereix una mica més de treball.

Afortunadament, Kubernetes proporciona la configuració necessària per assolir tots els objectius tècnics. Mitjançant una combinació de sol·licituds i límits de recursos, sondes de vivacitat i preparació, contenidors d'inici, polítiques de xarxa i ajustament personalitzat del nucli, podeu aconseguir un alt rendiment juntament amb una tolerància a errors i una escalabilitat ràpida.

Què més cal llegir:

  1. Bones pràctiques i bones pràctiques per executar contenidors i Kubernetes en entorns de producció.
  2. Més de 90 eines útils per a Kubernetes: desplegament, gestió, supervisió, seguretat i molt més.
  3. El nostre canal Al voltant de Kubernetes a Telegram.

Font: www.habr.com

Afegeix comentari