Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

8. april på konferencen Saint HighLoad++ 2019, som en del af "DevOps and Operations"-sektionen, blev der givet en rapport "Expanding and complementing Kubernetes", i hvilken tre ansatte i Flant-virksomheden deltog. I den taler vi om adskillige situationer, hvor vi ønskede at udvide og supplere Kubernetes' muligheder, men hvor vi ikke fandt en færdiglavet og enkel løsning. Vi har de nødvendige løsninger i form af Open Source-projekter, og denne tale er også dedikeret til dem.

Af tradition er vi glade for at kunne præsentere video af rapporten (50 minutter, meget mere informativ end artiklen) og hovedresuméet i tekstform. Gå!

Kerne og tilføjelser i K8'er

Kubernetes ændrer industrien og tilgange til administration, som længe har været etableret:

  • Tak til ham abstraktioner, vi arbejder ikke længere med begreber som opsætning af en config eller kørsel af en kommando (Chef, Ansible...), men bruger gruppering af containere, services mv.
  • Vi kan udarbejde ansøgninger uden at tænke på nuancerne i bestemt websted, hvorpå det vil blive lanceret: bart metal, sky fra en af ​​udbyderne osv.
  • Med K8s har du aldrig været mere tilgængelig bedste praksis om organisering af infrastruktur: skaleringsteknikker, selvhelbredelse, fejltolerance mv.

Men selvfølgelig er alt ikke så glat: Kubernetes bragte også sine egne nye udfordringer.

Kubernetes nej er en mejetærsker, der løser alle problemer for alle brugere. Kernen Kubernetes er kun ansvarlig for et sæt af de minimum nødvendige funktioner, der er til stede i hver klynge:

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Kubernetes-kernen definerer et grundlæggende sæt af primitiver til gruppering af containere, styring af trafik og så videre. Vi talte om dem mere detaljeret i rapport for 2 år siden.

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Til gengæld giver K8s store muligheder for at udvide de tilgængelige funktioner, som er med til at lukke andre - bestemt - brugernes behov. Tilføjelser til Kubernetes er ansvaret for klyngeadministratorer, som skal installere og konfigurere alt, hvad der er nødvendigt for at få deres klynge "i den rigtige form" [for at løse deres specifikke problemer]. Hvilken slags tilføjelser er der tale om? Lad os se på nogle eksempler.

Eksempler på tilføjelser

Efter at have installeret Kubernetes kan vi blive overrasket over, at det netværk, der er så nødvendigt for interaktionen mellem pods både inden for en node og mellem noder, ikke fungerer alene. Kubernetes-kernen garanterer ikke de nødvendige forbindelser; i stedet bestemmer den netværket grænseflade (CNI) for tredjeparts tilføjelser. Vi skal installere en af ​​disse tilføjelser, som vil være ansvarlig for netværkskonfigurationen.

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Et nærliggende eksempel er datalagringsløsninger (lokal disk, netværksblokenhed, Ceph...). Til at begynde med var de i kernen, men med fremkomsten CSI situationen ændres til noget, der ligner det, der allerede er beskrevet: grænsefladen er i Kubernetes, og dens implementering er i tredjepartsmoduler.

Andre eksempler omfatter:

  • Ingress-controllere (se deres anmeldelse i vores seneste artikel).
  • cert-manager:

    Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

  • operatører er en hel klasse af tilføjelser (som inkluderer den nævnte cert-manager), de definerer primitive(r) og controller(er). Logikken i deres arbejde er kun begrænset af vores fantasi og giver os mulighed for at omdanne færdige infrastrukturkomponenter (for eksempel et DBMS) til primitiver, som er meget nemmere at arbejde med (end med et sæt containere og deres indstillinger). Et stort antal operatører er blevet skrevet - selvom mange af dem endnu ikke er klar til produktion, er det kun et spørgsmål om tid:

    Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

  • Metrics - endnu en illustration af, hvordan Kubernetes adskilte grænsefladen (Metrics API) fra implementeringen (tredjeparts tilføjelser såsom Prometheus adapter, Datadog cluster agent...).
  • for overvågning og statistik, hvor der i praksis ikke kun er brug for Prometheus og Grafana, men også kube-state-metrics, node-exporter osv.

Og dette er ikke en komplet liste over tilføjelser... For eksempel hos Flant-firmaet, vi installerer i øjeblikket 29 tilføjelser (som alle skaber i alt 249 Kubernetes-objekter). Kort sagt kan vi ikke se livet i en klynge uden tilføjelser.

Automation

Operatører er designet til at automatisere rutineoperationer, som vi møder hver dag. Her er eksempler fra det virkelige liv, hvor det ville være en glimrende løsning at skrive en operatør:

  1. Der er et privat (dvs. kræver et login) register med billeder til applikationen. Det antages, at hver pod er tildelt en særlig hemmelighed, der tillader godkendelse i registreringsdatabasen. Vores opgave er at sikre, at denne hemmelighed findes i navnerummet, så pods kan downloade billeder. Der kan være mange applikationer (som hver især har brug for en hemmelighed), og det er nyttigt at opdatere selve hemmelighederne regelmæssigt, så muligheden for at udlægge hemmeligheder i hånden er elimineret. Det er her, operatøren kommer til undsætning: Vi opretter en controller, der venter på, at navneområdet vises, og baseret på denne hændelse vil tilføje en hemmelighed til navneområdet.
  2. Tillad som standard adgang fra pods til internettet er forbudt. Men nogle gange kan det være påkrævet: Det er logisk, at adgangstilladelsesmekanismen fungerer enkelt, uden at det kræver specifikke færdigheder, for eksempel ved tilstedeværelsen af ​​en bestemt etiket i navnerummet. Hvordan kan operatøren hjælpe os her? Der oprettes en controller, der venter på, at etiketten vises i navneområdet og tilføjer den relevante politik for internetadgang.
  3. En lignende situation: antag, at vi skulle tilføje en bestemt plettet, hvis den har en lignende etiket (med en form for præfiks). Handlingerne med operatøren er indlysende...

I enhver klynge skal rutineopgaver løses, og korrekt dette kan gøres ved hjælp af operatører.

Ved at opsummere alle de beskrevne historier kom vi til den konklusion, at for behageligt arbejde i Kubernetes, du har brug for: A) installere tilføjelser, b) udvikle operatører (til at løse daglige admin opgaver).

Hvordan skriver man en erklæring til Kubernetes?

Generelt er ordningen enkel:

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

... men så viser det sig at:

  • Kubernetes API er en ret ikke-triviel ting, der tager meget tid at mestre;
  • programmering er heller ikke for alle (Go-sproget blev valgt som det foretrukne sprog, fordi der er en særlig ramme for det - Operatør SDK);
  • Situationen er den samme med selve rammen.

Den nederste linje: at skrive en controller (operatør) skal bruge betydelige ressourcer at studere materiel. Dette ville være berettiget for "store" operatører - f.eks. for MySQL DBMS. Men hvis vi husker eksemplerne beskrevet ovenfor (udfoldelse af hemmeligheder, adgang til pods til internettet...), som vi også ønsker at gøre korrekt, så vil vi forstå, at indsatsen vil opveje det resultat, vi har brug for nu:

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Generelt opstår et dilemma: Brug mange ressourcer og find det rigtige værktøj til at skrive udsagn, eller gør det på den gammeldags måde (men hurtigt). For at løse det - for at finde et kompromis mellem disse yderpunkter - skabte vi vores eget projekt: shell-operatør (se også hans seneste meddelelse på navet).

Shell-operatør

Hvordan arbejder han? Klyngen har en pod, der indeholder en Go binær med en shell-operator. Ved siden af ​​ham er et sæt af kroge (flere detaljer om dem - se nedenfor). Shell-operatøren selv abonnerer på visse udviklinger i Kubernetes API, hvorefter den lancerer de tilsvarende kroge.

Hvordan ved shell-operatøren, hvilke kroge han skal kalde på hvilke begivenheder? Denne information overføres til shell-operatøren af ​​krogene selv, og de gør det meget enkelt.

En hook er et Bash-script eller enhver anden eksekverbar fil, der accepterer et enkelt argument --config og svarer med JSON. Sidstnævnte bestemmer, hvilke objekter der er af interesse for den, og hvilke begivenheder (for disse objekter) der skal reageres på:

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Jeg vil illustrere implementeringen på shell-operatoren af ​​et af vores eksempler - dekomponerende hemmeligheder til at få adgang til et privat register med applikationsbilleder. Den består af to faser.

Øv: 1. Skriv en krog

Først og fremmest vil vi behandle i krogen --config, hvilket indikerer, at vi er interesserede i navnerum, og specifikt tidspunktet for deres oprettelse:

[[ $1 == "--config" ]] ; then
  cat << EOF
{
  "onKubernetesEvent": [
    {
      "kind": "namespace",
      "event": ["add"]
    }
  ]
}
EOF
…

Hvordan ville logikken se ud? Også ret simpelt:

…
else
  createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
  kubectl create -n ${createdNamespace} -f - << EOF
Kind: Secret
...
EOF
fi

Det første trin er at finde ud af, hvilket navneområde der blev oprettet, og det andet er at oprette det ved hjælp af kubectl hemmelighed for dette navneområde.

Øv: 2. Samling af billedet

Det eneste, der er tilbage, er at videregive den oprettede krog til shell-operatøren - hvordan gør man dette? Selve shell-operatoren kommer som et Docker-billede, så vores opgave er at tilføje krogen til en speciel mappe i dette billede:

FROM flant/shell-operator:v1.0.0-beta.1
ADD my-handler.sh /hooks

Det eneste, der er tilbage, er at samle det og skubbe det:

$ docker build -t registry.example.com/my-operator:v1 .
$ docker push registry.example.com/my-operator:v1

Den sidste touch er at implementere billedet til klyngen. For at gøre dette, lad os skrive Deployment:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-operator
spec:
  template:
    spec:
      containers:
      - name: my-operator
        image: registry.example.com/my-operator:v1 # 1
      serviceAccountName: my-operator              # 2

Der er to punkter at være opmærksom på:

  1. indikation af det nyoprettede billede;
  2. Dette er en systemkomponent, der (som minimum) har brug for rettigheder til at abonnere på begivenheder i Kubernetes og til at tildele hemmeligheder til navneområder, så vi opretter en ServiceAccount (og et sæt regler) til hook.

Resultat - vi løste vores problem pårørende for Kubernetes på en måde, der skaber en operatør til at nedbryde hemmeligheder.

Andre shell-operator funktioner

For at begrænse objekterne af din valgte type, som krogen vil arbejde med, de kan filtreres, vælge i henhold til bestemte etiketter (eller bruge matchExpressions):

"onKubernetesEvent": [
  {
    "selector": {
      "matchLabels": {
        "foo": "bar",
       },
       "matchExpressions": [
         {
           "key": "allow",
           "operation": "In",
           "values": ["wan", "warehouse"],
         },
       ],
     }
     …
  }
]

Stillet til rådighed deduplikationsmekanisme, som - ved hjælp af et jq-filter - giver dig mulighed for at konvertere store JSON-objekter til små, hvor kun de parametre tilbage, som vi ønsker at overvåge for ændringer.

Når en krog kaldes, passerer shell-operatøren den objektdata, som kan bruges til ethvert behov.

De hændelser, der udløser hooks, er ikke begrænset til Kubernetes-begivenheder: shell-operatøren yder support til kalder kroge efter tid (ligner crontab i en traditionel skemalægger), samt en særlig begivenhed ved opstart. Alle disse begivenheder kan kombineres og tildeles den samme krog.

Og yderligere to funktioner i shell-operatoren:

  1. Det virker asynkront. Siden en Kubernetes-begivenhed (såsom et objekt, der oprettes) blev modtaget, kunne andre hændelser (såsom det samme objekt, der blev slettet) have fundet sted i klyngen, og hooks skal tage højde for dette. Hvis krogen blev udført med en fejl, vil den som standard være det minde om indtil vellykket afslutning (denne adfærd kan ændres).
  2. Det eksporterer målinger for Prometheus, som du kan forstå, om shell-operatoren fungerer med, find ud af antallet af fejl for hver krog og den aktuelle køstørrelse.

For at opsummere denne del af rapporten:

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Installation af tilføjelser

For komfortabelt arbejde med Kubernetes blev behovet for at installere tilføjelser også nævnt. Jeg vil fortælle dig om det ved at bruge eksemplet på vores virksomheds vej til, hvordan vi gør det nu.

Vi begyndte at arbejde med Kubernetes med flere klynger, hvor den eneste tilføjelse var Ingress. Det skulle installeres forskelligt i hver klynge, og vi lavede flere YAML-konfigurationer til forskellige miljøer: bart metal, AWS...

Da der var flere klynger, var der flere konfigurationer. Derudover forbedrede vi selv disse konfigurationer, som et resultat af, at de blev ret heterogene:

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

For at bringe alt i orden startede vi med et script (install-ingress.sh), som tog den type klynge, som vi vil implementere til, som argument, genererede den nødvendige YAML-konfiguration og rullede den ud til Kubernetes.

Kort sagt var vores videre vej og ræsonnementet forbundet med det som følger:

  • for at arbejde med YAML-konfigurationer kræves en skabelonmotor (i de første trin er dette simpelt sed);
  • med stigningen i antallet af klynger kom behovet for automatisk opdatering (den tidligste løsning var at sætte scriptet i Git, opdatere det ved hjælp af cron og køre det);
  • et lignende script var påkrævet til Prometheus (install-prometheus.sh), men det er bemærkelsesværdigt for det faktum, at det kræver meget flere inputdata, såvel som deres lagring (på en god måde - centraliseret og i en klynge), og nogle data (adgangskoder) kunne genereres automatisk:

    Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

  • risikoen for at udrulle noget forkert til et stigende antal klynger voksede konstant, så vi indså, at installatører (dvs. to scripts: for Ingress og Prometheus) iscenesættelse var nødvendig (flere grene i Git, flere crons for at opdatere dem i den tilsvarende: stabile eller testklynger);
  • с kubectl apply det er blevet svært at arbejde med, fordi det ikke er deklarativt og kun kan oprette objekter, men ikke træffe beslutninger om deres status/slette dem;
  • Vi manglede nogle funktioner, som vi slet ikke havde implementeret på det tidspunkt:
    • fuld kontrol over resultatet af klyngeopdateringer,
    • automatisk bestemmelse af nogle parametre (input til installationsscripts) baseret på data, der kan hentes fra klyngen (opdagelse),
    • dens logiske udvikling i form af kontinuerlig opdagelse.

Vi implementerede al denne akkumulerede erfaring inden for rammerne af vores andet projekt - addon-operatør.

Addon-operatør

Den er baseret på den allerede nævnte shell-operator. Hele systemet ser således ud:

Følgende er tilføjet til shell-operatorkrogene:

  • værdiopbevaring,
  • Hjelm diagram,
  • komponent, der overvåger værdilageret og - i tilfælde af ændringer - beder Helm om at rulle diagrammet igen.

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Således kan vi reagere på en begivenhed i Kubernetes, lancere en hook, og fra denne hook kan vi foretage ændringer i lageret, hvorefter diagrammet vil blive downloadet igen. I det resulterende diagram adskiller vi krogesættet og diagrammet i en komponent, som vi kalder modul:

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Der kan være mange moduler, og til dem tilføjer vi globale hooks, en global værdibutik og en komponent, der overvåger denne globale butik.

Nu, når der sker noget i Kubernetes, kan vi reagere på det ved hjælp af en global hook og ændre noget i den globale butik. Denne ændring vil blive bemærket og vil medføre, at alle moduler i klyngen udrulles:

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Denne ordning opfylder alle kravene til installation af tilføjelser, der blev anført ovenfor:

  • Helm er ansvarlig for skabeloner og deklarativitet.
  • Problemet med automatisk opdatering blev løst ved hjælp af en global hook, som går til registreringsdatabasen efter en tidsplan, og hvis den ser et nyt systembillede der, ruller det ud (dvs. "sig selv").
  • Lagring af indstillinger i klyngen implementeres vha ConfigMap, som indeholder de primære data for lagrene (ved opstart indlæses de i lagrene).
  • Problemer med adgangskodegenerering, opdagelse og kontinuerlig opdagelse blev løst ved hjælp af kroge.
  • Iscenesættelse opnås takket være tags, som Docker understøtter ud af boksen.
  • Resultatet overvåges ved hjælp af metrics, hvormed vi kan forstå status.

Hele dette system er implementeret i form af en enkelt binær i Go, som kaldes addon-operator. Dette får diagrammet til at se enklere ud:

Udvidelse og udvidelse af Kubernetes (oversigt og videorapport)

Hovedkomponenten i dette diagram er et sæt moduler (fremhævet med gråt nedenfor). Nu kan vi skrive et modul til den nødvendige tilføjelse med en lille indsats og være sikker på, at den vil blive installeret i hver klynge, vil blive opdateret og reagere på de begivenheder, den har brug for i klyngen.

"Flant" bruger addon-operatør på 70+ Kubernetes-klynger. Nuværende status - alfa version. Nu er vi ved at forberede dokumentation for at frigive betaen, men foreløbig i repository tilgængelige eksempler, på grundlag af hvilket du kan oprette din egen tilføjelse.

Hvor kan jeg få modulerne til addon-operator? Udgivelsen af ​​vores bibliotek er den næste fase for os; vi planlægger at gøre dette til sommeren.

Videoer og dias

Video fra forestillingen (~50 minutter):

Præsentation af rapporten:

PS

Andre rapporter på vores blog:

Du kan også være interesseret i følgende publikationer:

Kilde: www.habr.com

Tilføj en kommentar