Distribuere applikasjoner til flere Kubernetes-klynger med Helm

Hvordan Dailymotion bruker Kubernetes: Application Deployment

Vi i Dailymotion begynte å bruke Kubernetes i produksjon for 3 år siden. Men det er morsomt å distribuere applikasjoner på tvers av flere klynger, så i løpet av de siste årene har vi prøvd å forbedre verktøyene og arbeidsflytene våre.

Hvor begynte det

Her skal vi dekke hvordan vi distribuerer applikasjonene våre på tvers av flere Kubernetes-klynger rundt om i verden.

For å distribuere flere Kubernetes-objekter samtidig, bruker vi Helm, og alle våre diagrammer er lagret i ett git-lager. For å distribuere en full applikasjonsstabel fra flere tjenester, bruker vi det såkalte oppsummeringsdiagrammet. I hovedsak er dette et diagram som erklærer avhengigheter og lar deg initialisere APIen og dens tjenester med én kommando.

Vi skrev også et lite Python-skript på toppen av Helm for å sjekke, lage diagrammer, legge til hemmeligheter og distribuere applikasjoner. Alle disse oppgavene utføres på en sentral CI-plattform ved hjelp av et docker-bilde.

La oss komme til poenget.

Merk. Mens du leser dette, er den første utgivelseskandidaten for Helm 3 allerede kunngjort. Hovedversjonen inneholder en hel rekke forbedringer for å løse noen av problemene vi har støtt på tidligere.

Arbeidsflyt for diagramutvikling

Vi bruker forgrening for applikasjoner, og vi bestemte oss for å bruke samme tilnærming til diagrammer.

  • gren dev brukes til å lage diagrammer som vil bli testet på utviklingsklynger.
  • Når en pull-forespørsel sendes til Master, er de sjekket inn i oppsetning.
  • Til slutt oppretter vi en pull-forespørsel for å forplikte endringene til filialen prod og bruke dem i produksjonen.

Hvert miljø har sitt eget private depot som lagrer våre kart, og vi bruker Kartmuseum med svært nyttige APIer. På denne måten sikrer vi streng isolasjon mellom miljøer og testing av diagrammer i den virkelige verden før de brukes i produksjon.

Kartlagre i ulike miljøer

Det er verdt å merke seg at når utviklere skyver en dev-gren, blir en versjon av diagrammet deres automatisk sendt til dev Chartmuseum. Dermed bruker alle utviklere det samme dev-lageret, og du må spesifisere din versjon av diagrammet nøye for ikke å bruke noen andres endringer ved et uhell.

Dessuten validerer vårt lille Python-skript Kubernetes-objekter mot Kubernetes OpenAPI-spesifikasjoner ved å bruke Kubeval, før du publiserer dem på Chartmusem.

Generell beskrivelse av arbeidsflyten for diagramutvikling

  1. Sette opp rørledningsoppgaver i henhold til spesifikasjon gazr.io for kvalitetskontroll (lo, enhetstest).
  2. Skyve et docker-bilde med Python-verktøy som distribuerer applikasjonene våre.
  3. Sette opp miljøet etter filialnavn.
  4. Validering av Kubernetes yaml-filer ved hjelp av Kubeval.
  5. Øk automatisk versjonen av et diagram og dets overordnede diagrammer (diagrammer som avhenger av diagrammet som endres).
  6. Sende inn et kart til et kartmuseum som samsvarer med miljøet

Håndtere forskjeller på tvers av klynger

Forbundet av klynger

Det var en tid da vi brukte føderasjon av Kubernetes-klynger, der Kubernetes-objekter kunne deklareres fra et enkelt API-endepunkt. Men det oppsto problemer. Noen Kubernetes-objekter kunne for eksempel ikke opprettes i føderasjonsendepunktet, noe som gjør det vanskelig å vedlikeholde forente objekter og andre objekter for individuelle klynger.

For å løse problemet begynte vi å administrere klyngene uavhengig, noe som i stor grad forenklet prosessen (vi brukte den første versjonen av føderasjon; noe kan ha endret seg i den andre).

Geo-distribuert plattform

Plattformen vår er for tiden distribuert over 6 regioner - 3 lokalt og 3 i skyen.


Distribuert distribusjon

Globale Helm-verdier

4 globale Helm-verdier lar deg identifisere forskjeller mellom klynger. Alle våre diagrammer har standard minimumsverdier.

global:
  cloud: True
  env: staging
  region: us-central1
  clusterName: staging-us-central1

Globale verdier

Disse verdiene er med på å definere konteksten for applikasjonene våre og brukes til ulike formål: overvåking, sporing, logging, foreta eksterne anrop, skalering, etc.

  • "cloud": Vi har en hybrid Kubernetes-plattform. For eksempel er API-en vår distribuert i GCP-soner og i datasentrene våre.
  • "env": Noen verdier kan endres for ikke-produksjonsmiljøer. For eksempel ressursdefinisjoner og autoskaleringskonfigurasjoner.
  • "region": Denne informasjonen hjelper til med å bestemme plasseringen av klyngen og kan brukes til å bestemme nærliggende endepunkter for eksterne tjenester.
  • "clusterName": hvis og når vi ønsker å definere en verdi for en individuell klynge.

Her er et spesifikt eksempel:

{{/* Returns Horizontal Pod Autoscaler replicas for GraphQL*/}}
{{- define "graphql.hpaReplicas" -}}
{{- if eq .Values.global.env "prod" }}
{{- if eq .Values.global.region "europe-west1" }}
minReplicas: 40
{{- else }}
minReplicas: 150
{{- end }}
maxReplicas: 1400
{{- else }}
minReplicas: 4
maxReplicas: 20
{{- end }}
{{- end -}}

Eksempel på rormal

Denne logikken er definert i en hjelpemal for å unngå rot i Kubernetes YAML.

Søknadskunngjøring

Implementeringsverktøyene våre er basert på flere YAML-filer. Nedenfor er et eksempel på hvordan vi deklarerer en tjeneste og dens skaleringstopologi (antall replikaer) i en klynge.

releases:
  - foo.world

foo.world:                # Release name
  services:               # List of dailymotion's apps/projects
    foobar:
      chart_name: foo-foobar
      repo: [email protected]:dailymotion/foobar
      contexts:
        prod-europe-west1:
          deployments:
            - name: foo-bar-baz
              replicas: 18
            - name: another-deployment
              replicas: 3

Tjenestedefinisjon

Dette er en oversikt over alle trinnene som definerer arbeidsflyten vår for distribusjon. Det siste trinnet distribuerer applikasjonen til flere arbeidsklynger samtidig.


Jenkins Deployment Steps

Hva med hemmeligheter?

Når det gjelder sikkerhet, sporer vi alle hemmeligheter fra forskjellige steder og lagrer dem i et unikt hvelv Vault i Paris.

Distribusjonsverktøyene våre trekker ut hemmelige verdier fra Vault, og sett dem inn i Helm når utrullingstiden kommer.

For å gjøre dette definerte vi en kartlegging mellom hemmelighetene i Vault og hemmelighetene som applikasjonene våre trenger:

secrets:                                                                                                                                                                                                        
     - secret_id: "stack1-app1-password"                                                                                                                                                                                  
       contexts:                                                                                                                                                                                                   
         - name: "default"                                                                                                                                                                                         
           vaultPath: "/kv/dev/stack1/app1/test"                                                                                                                                                               
           vaultKey: "password"                                                                                                                                                                                    
         - name: "cluster1"                                                                                                                                                                           
           vaultPath: "/kv/dev/stack1/app1/test"                                                                                                                                                               
           vaultKey: "password"

  • Vi har definert generelle regler som skal følges når du registrerer hemmeligheter i Vault.
  • Hvis hemmeligheten gjelder til en bestemt kontekst eller klynge, må du legge til en spesifikk oppføring. (Her har kontekstcluster1 sin egen verdi for det hemmelige stack-app1-passordet).
  • Ellers brukes verdien som standard.
  • For hvert element i denne listen i Kubernetes hemmelighet et nøkkelverdi-par er satt inn. Derfor er den hemmelige malen i våre diagrammer veldig enkel.

apiVersion: v1
data:
{{- range $key,$value := .Values.secrets }}
  {{ $key }}: {{ $value | b64enc | quote }}
{{ end }}
kind: Secret
metadata:
  name: "{{ .Chart.Name }}"
  labels:
    chartVersion: "{{ .Chart.Version }}"
    tillerVersion: "{{ .Capabilities.TillerVersion.SemVer }}"
type: Opaque

Problemer og begrensninger

Arbeider med flere depoter

Nå skiller vi utviklingen av diagrammer og applikasjoner. Dette betyr at utviklere må jobbe i to git-repositorier: ett for applikasjonen og ett for å definere distribusjonen til Kubernetes. 2 git-repositories betyr 2 arbeidsflyter, og det er lett for en nybegynner å bli forvirret.

Å administrere generaliserte diagrammer er et problem

Som vi allerede har sagt, er generiske diagrammer svært nyttige for å identifisere avhengigheter og raskt distribuere flere applikasjoner. Men vi bruker --reuse-valuesfor å unngå å sende alle verdiene hver gang vi distribuerer en applikasjon som er en del av dette generaliserte diagrammet.

I en kontinuerlig leveringsarbeidsflyt har vi bare to verdier som endres regelmessig: antall replikaer og bildekoden (versjon). Andre, mer stabile verdier endres manuelt, og dette er ganske vanskelig. Dessuten kan en feil ved å distribuere et generalisert diagram føre til alvorlige feil, som vi har sett fra vår egen erfaring.

Oppdatering av flere konfigurasjonsfiler

Når en utvikler legger til en ny applikasjon, må han endre flere filer: applikasjonserklæringen, listen over hemmeligheter, legge til applikasjonen som en avhengighet hvis den er inkludert i det generaliserte diagrammet.

Jenkins tillatelser er for utvidet i Vault

Vi har en nå AppRole, som leser alle hemmelighetene fra hvelvet.

Tilbakeføringsprosessen er ikke automatisert

For å rulle tilbake, må du kjøre kommandoen på flere klynger, og dette er full av feil. Vi utfører denne operasjonen manuelt for å sikre at riktig versjons-ID er spesifisert.

Vi beveger oss mot GitOps

Vårt mål

Vi ønsker å returnere diagrammet til depotet til applikasjonen den distribuerer.

Arbeidsflyten vil være den samme som for utvikling. For eksempel, når en gren blir presset til master, vil distribusjonen utløses automatisk. Hovedforskjellen mellom denne tilnærmingen og den nåværende arbeidsflyten vil være at alt vil bli administrert i git (selve applikasjonen og måten den er distribuert på i Kubernetes).

Det er flere fordeler:

  • Mye klarere for utbygger. Det er lettere å lære hvordan du bruker endringer i et lokalt diagram.
  • Tjenestedistribusjonsdefinisjonen kan spesifiseres samme sted som koden service.
  • Håndtere fjerning av generaliserte diagrammer. Tjenesten vil ha sin egen Helm-utgivelse. Dette vil tillate deg å administrere applikasjonens livssyklus (tilbakeføring, oppgradering) på det minste nivået, for ikke å påvirke andre tjenester.
  • Fordeler med git for diagramadministrasjon: angre endringer, revisjonslogg osv. Hvis du trenger å angre en endring i et diagram, kan du gjøre dette ved å bruke git. Utrullingen starter automatisk.
  • Du kan vurdere å forbedre utviklingsarbeidsflyten din med verktøy som Skaffold, som utviklere kan teste endringer med i en kontekst nær produksjon.

To-trinns migrasjon

Utviklerne våre har brukt denne arbeidsflyten i 2 år nå, så vi ønsker at migreringen skal være så smertefri som mulig. Derfor bestemte vi oss for å legge til et mellomtrinn på veien mot målet.
Den første fasen er enkel:

  • Vi har en lignende struktur for å sette opp applikasjonsdistribusjon, men i et enkelt objekt kalt DailymotionRelease.

apiVersion: "v1"
kind: "DailymotionRelease"
metadata:
  name: "app1.ns1"
  environment: "dev"
  branch: "mybranch"
spec:
  slack_channel: "#admin"
  chart_name: "app1"
  scaling:
    - context: "dev-us-central1-0"
      replicas:
        - name: "hermes"
          count: 2
    - context: "dev-europe-west1-0"
      replicas:
        - name: "app1-deploy"
          count: 2
  secrets:
    - secret_id: "app1"
      contexts:
        - name: "default"
          vaultPath: "/kv/dev/ns1/app1/test"
          vaultKey: "password"
        - name: "dev-europe-west1-0"
          vaultPath: "/kv/dev/ns1/app1/test"
          vaultKey: "password"

  • 1 utgivelse per applikasjon (uten generaliserte diagrammer).
  • Diagrammer i applikasjonens git-repository.

Vi har snakket med alle utviklerne, så migreringsprosessen har allerede begynt. Det første trinnet styres fortsatt ved hjelp av CI-plattformen. Jeg skal snart skrive et nytt innlegg om fase to: hvordan vi gikk over til en GitOps-arbeidsflyt med Flux. Jeg skal fortelle deg hvordan vi setter opp alt og hvilke vanskeligheter vi møtte (flere depoter, hemmeligheter, etc.). Følg med på nyhetene.

Her har vi forsøkt å beskrive fremgangen vår i arbeidsflyten for applikasjonsdistribusjon de siste årene, noe som førte til tanker om GitOps-tilnærmingen. Vi har ennå ikke nådd målet og vil rapportere om resultatene, men nå er vi overbevist om at vi gjorde det rette da vi bestemte oss for å forenkle alt og bringe det nærmere utviklernes vaner.

Kilde: www.habr.com

Legg til en kommentar