Postavite aplikacije na više Kubernetes klastera pomoću Helm-a

Kako Dailymotion koristi Kubernetes: implementacija aplikacije

Mi u Dailymotionu smo počeli koristiti Kubernetes u proizvodnji prije 3 godine. Ali implementacija aplikacija u više klastera je zabavna, tako da u posljednjih nekoliko godina pokušavamo poboljšati naše alate i tokove rada.

Gdje je počelo

Ovdje ćemo pokriti kako implementiramo naše aplikacije u više Kubernetes klastera širom svijeta.

Za implementaciju više Kubernetes objekata odjednom, koristimo kormilo, a svi naši grafikoni su pohranjeni u jednom git spremištu. Da bismo implementirali potpuni stog aplikacija iz nekoliko servisa, koristimo takozvani sažetak grafikona. U suštini, ovo je grafikon koji deklarira zavisnosti i omogućava vam da inicijalizirate API i njegove usluge jednom naredbom.

Napisali smo i malu Python skriptu na vrhu Helm-a za provjeru, kreiranje grafikona, dodavanje tajni i postavljanje aplikacija. Svi ovi zadaci se izvode na centralnoj CI platformi koristeći docker sliku.

Hajdemo na stvar.

Bilješka. Dok čitate ovo, prvi kandidat za izdanje za Helm 3 je već najavljen. Glavna verzija sadrži čitav niz poboljšanja za rješavanje nekih problema s kojima smo se susreli u prošlosti.

Radni tok razvoja grafikona

Za aplikacije koristimo grananje, a isti pristup smo odlučili primijeniti i na grafikone.

  • Filijala dev koristi se za kreiranje grafikona koji će se testirati na razvojnim klasterima.
  • Kada se podnese zahtjev za povlačenje majstor, provjeravaju se u fazi.
  • Konačno, kreiramo zahtjev za povlačenjem za urezivanje promjena na grani prod i primijeniti ih u proizvodnji.

Svako okruženje ima svoje privatno spremište koje pohranjuje naše grafikone i koje mi koristimo Chartmuseum sa vrlo korisnim API-jima. Na ovaj način osiguravamo strogu izolaciju između okruženja i testiranja dijagrama u stvarnom svijetu prije njihove upotrebe u proizvodnji.

Spremišta grafikona u različitim okruženjima

Vrijedi napomenuti da kada programeri gurnu dev granu, verzija njihovog grafikona se automatski gura u dev Chartmuseum. Dakle, svi programeri koriste isto dev spremište, a vi morate pažljivo odrediti svoju verziju grafikona kako slučajno ne biste koristili tuđe promjene.

Štaviše, naša mala Python skripta potvrđuje Kubernetes objekte u odnosu na Kubernetes OpenAPI specifikacije koristeći Kubeval, prije objavljivanja na Chartmusemu.

Opšti opis toka rada razvoja grafikona

  1. Postavljanje zadataka cjevovoda prema specifikaciji gazr.io za kontrolu kvaliteta (lint, unit-test).
  2. Guranje docker slike pomoću Python alata koji implementiraju naše aplikacije.
  3. Podešavanje okruženja po imenu grane.
  4. Provjera valjanosti Kubernetes yaml datoteka koristeći Kubeval.
  5. Automatski povećajte verziju grafikona i njegovih nadređenih grafikona (grafikoni koji zavise od grafikona koji se mijenja).
  6. Slanje grafikona u Chartmuseum koji odgovara njegovom okruženju

Upravljanje razlikama među klasterima

Federacija klastera

Bilo je vremena kada smo koristili federacija Kubernetes klastera, gdje se Kubernetes objekti mogu deklarirati iz jedne API krajnje točke. Ali su se pojavili problemi. Na primjer, neki Kubernetes objekti nisu mogli biti kreirani u krajnjoj točki federacije, što otežava održavanje federalnih objekata i drugih objekata za pojedinačne klastere.

Da bismo riješili problem, počeli smo samostalno upravljati klasterima, što je uvelike pojednostavilo proces (koristili smo prvu verziju federacije, u drugoj se možda nešto promijenilo).

Geo-distribuirana platforma

Naša platforma je trenutno distribuirana u 6 regija - 3 lokalno i 3 u oblaku.


Distributed Deployment

Global Helm vrijednosti

4 globalne vrijednosti Helm-a omogućuju vam da identificirate razlike između klastera. Svi naši grafikoni imaju zadane minimalne vrijednosti.

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

Globalne vrijednosti

Ove vrijednosti pomažu u definiranju konteksta za naše aplikacije i koriste se u različite svrhe: praćenje, praćenje, evidentiranje, upućivanje vanjskih poziva, skaliranje, itd.

  • "oblak": Imamo hibridnu Kubernetes platformu. Na primjer, naš API je raspoređen u GCP zonama i u našim podatkovnim centrima.
  • "env": Neke vrijednosti se mogu promijeniti za neproizvodna okruženja. Na primjer, definicije resursa i konfiguracije automatskog skaliranja.
  • "regija": Ove informacije pomažu u određivanju lokacije klastera i mogu se koristiti za određivanje obližnjih krajnjih tačaka za vanjske usluge.
  • "clusterName": ako i kada želimo definirati vrijednost za pojedinačni klaster.

Evo konkretnog primjera:

{{/* 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 -}}

Primjer šablona za kormilo

Ova logika je definirana u pomoćnom predlošku kako bi se izbjeglo zatrpavanje Kubernetes YAML-a.

Najava prijave

Naši alati za implementaciju zasnovani su na više YAML datoteka. Ispod je primjer kako deklariramo uslugu i njenu topologiju skaliranja (broj replika) u klasteru.

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

Definicija usluge

Ovo je pregled svih koraka koji definiraju naš radni tok implementacije. Posljednji korak postavlja aplikaciju na više klastera radnika istovremeno.


Koraci postavljanja Jenkinsa

Šta je sa tajnama?

Što se tiče sigurnosti, pratimo sve tajne sa različitih mjesta i čuvamo ih u jedinstvenom trezoru svod u parizu.

Naši alati za implementaciju izvlače tajne vrijednosti iz Vaulta i, kada dođe vrijeme implementacije, ubacuju ih u Helm.

Da bismo to učinili, definirali smo mapiranje između tajni u Vaultu i tajni koje su potrebne našim aplikacijama:

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"

  • Definirali smo opća pravila koja treba slijediti prilikom snimanja tajni u Vaultu.
  • Ako se tajna odnosi određenom kontekstu ili klasteru, morate dodati određeni unos. (Ovdje kontekst cluster1 ima vlastitu vrijednost za tajnu lozinku-aplikacija-passworda).
  • U suprotnom se koristi vrijednost po defaultu.
  • Za svaku stavku na ovoj listi u Kubernetes tajna umetnut je par ključ/vrijednost. Stoga je tajni predložak u našim grafikonima vrlo jednostavan.

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

Problemi i ograničenja

Rad sa više repozitorija

Sada razdvajamo razvoj grafikona i aplikacija. To znači da programeri moraju raditi u dva git spremišta: jedno za aplikaciju, a jedno za definiranje njene implementacije u Kubernetes. 2 git repozitorija znače 2 toka posla, a početnicima je lako da se zbune.

Upravljanje generaliziranim grafikonima je gnjavaža

Kao što smo već rekli, generički grafikoni su vrlo korisni za identifikaciju zavisnosti i brzo postavljanje više aplikacija. Ali mi koristimo --reuse-valueskako bismo izbjegli prosljeđivanje svih vrijednosti svaki put kada implementiramo aplikaciju koja je dio ovog generaliziranog grafikona.

U kontinuiranom toku rada isporuke imamo samo dvije vrijednosti koje se redovno mijenjaju: broj replika i oznaku slike (verzija). Ostale, stabilnije vrijednosti se mijenjaju ručno, a to je prilično teško. Štaviše, jedna greška u primeni generalizovanog grafikona može dovesti do ozbiljnih neuspeha, kao što smo videli iz sopstvenog iskustva.

Ažuriranje više konfiguracijskih datoteka

Kada programer dodaje novu aplikaciju, mora promijeniti nekoliko datoteka: deklaraciju aplikacije, listu tajni, dodavanje aplikacije kao ovisnosti ako je uključena u generalizirani grafikon.

Jenkinsove dozvole su previše proširene u Vaultu

Sada imamo jednu AppRole, koji čita sve tajne iz Trezora.

Proces vraćanja nije automatiziran

Da biste se vratili, morate pokrenuti naredbu na nekoliko klastera, a to je prepuno grešaka. Ovu operaciju izvodimo ručno kako bismo osigurali da je naveden ispravan ID verzije.

Idemo prema GitOps-u

Naš cilj

Želimo vratiti grafikon u spremište aplikacije koju implementira.

Tok posla će biti isti kao i za razvoj. Na primjer, kada je grana gurnuta na master, implementacija će se automatski pokrenuti. Glavna razlika između ovog pristupa i trenutnog toka rada bi bila u tome sve će se upravljati u git-u (sama aplikacija i način na koji se postavlja u Kubernetes).

Postoji nekoliko prednosti:

  • Mnogo jasnije za programera. Lakše je naučiti kako primijeniti promjene na lokalnom grafikonu.
  • Definicija postavljanja usluge može se specificirati na istom mjestu kao kod usluga.
  • Upravljanje uklanjanjem generaliziranih grafikona. Usluga će imati vlastito izdanje Helm-a. Ovo će vam omogućiti da upravljate životnim ciklusom aplikacije (povratak, nadogradnja) na najmanjem nivou, kako ne biste uticali na druge usluge.
  • Prednosti git-a za upravljanje grafikonom: poništite promjene, evidenciju revizije, itd. Ako trebate poništiti promjenu grafikona, to možete učiniti koristeći git. Postavljanje počinje automatski.
  • Možda razmislite o poboljšanju vašeg razvojnog toka rada pomoću alata kao što su Skaffold, s kojim programeri mogu testirati promjene u kontekstu bliskom produkcijskom.

Migracija u dva koraka

Naši programeri koriste ovaj tok rada već 2 godine, tako da želimo da migracija bude što bezbolnija. Stoga smo odlučili dodati međukorak na putu do cilja.
Prva faza je jednostavna:

  • Zadržavamo sličnu strukturu za postavljanje implementacije aplikacije, ali u jednom objektu koji se zove 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 izdanje po aplikaciji (bez generalizovanih grafikona).
  • Grafikoni u git spremištu aplikacije.

Razgovarali smo sa svim programerima, tako da je proces migracije već počeo. Prva faza se još uvijek kontrolira pomoću CI platforme. Uskoro ću napisati još jedan post o drugoj fazi: kako smo prešli na GitOps radni tok Tok. Reći ću vam kako smo sve postavili i na kakve smo poteškoće naišli (više repozitorija, tajni itd.). Pratite vijesti.

Ovdje smo pokušali opisati naš napredak u toku rada implementacije aplikacija tokom proteklih godina, što je dovelo do razmišljanja o GitOps pristupu. Još nismo došli do cilja i izvještavaćemo o rezultatima, ali sada smo uvjereni da smo postupili ispravno kada smo odlučili sve pojednostaviti i približiti navikama programera.

izvor: www.habr.com

Dodajte komentar