Nasazení aplikací do více clusterů Kubernetes pomocí Helm

Jak Dailymotion používá Kubernetes: Application Deployment

My v Dailymotion jsme začali používat Kubernetes v produkci před 3 lety. Nasazování aplikací do více clusterů je ale zábavné, takže se v posledních několika letech snažíme naše nástroje a pracovní postupy vylepšovat.

Kde to začalo

Zde se budeme zabývat tím, jak nasazujeme naše aplikace v několika clusterech Kubernetes po celém světě.

K nasazení více objektů Kubernetes najednou používáme Kormidloa všechny naše grafy jsou uloženy v jednom gitovém úložišti. Pro nasazení plného aplikačního zásobníku z více služeb používáme tzv. souhrnný graf. V podstatě se jedná o graf, který deklaruje závislosti a umožňuje inicializovat API a jeho služby jedním příkazem.

Napsali jsme také malý skript v Pythonu nad Helm, abychom mohli provádět kontroly, vytvářet grafy, přidávat tajná tajemství a nasazovat aplikace. Všechny tyto úkoly se provádějí na centrální platformě CI pomocí obrazu dockeru.

Pojďme k věci.

Poznámka. Zatímco toto čtete, první kandidát na vydání Helm 3 již byl oznámen. Hlavní verze obsahuje celou řadu vylepšení, která řeší některé problémy, se kterými jsme se v minulosti setkali.

Pracovní postup vývoje grafu

Pro aplikace používáme větvení a stejný přístup jsme se rozhodli aplikovat i na grafy.

  • Větev dev slouží k vytváření grafů, které budou testovány na vývojových clusterech.
  • Když je odeslán požadavek na stažení na mistr, jsou kontrolovány ve stagingu.
  • Nakonec vytvoříme požadavek na stažení pro potvrzení změn do větve prod a aplikovat je ve výrobě.

Každé prostředí má své vlastní soukromé úložiště, které ukládá naše grafy a které používáme Chartmuseum s velmi užitečnými API. Tímto způsobem zajišťujeme přísnou izolaci mezi prostředími a reálné testování grafů před jejich použitím ve výrobě.

Úložiště grafů v různých prostředích

Stojí za zmínku, že když vývojáři vloží větev do vývojového prostředí, verze jejich grafu se automaticky přesune do dev Chartmuseum. Všichni vývojáři tedy používají stejné úložiště pro vývojáře a musíte pečlivě specifikovat svou verzi grafu, abyste náhodně nepoužili změny někoho jiného.

Náš malý skript Python navíc ověřuje objekty Kubernetes proti specifikacím Kubernetes OpenAPI pomocí Kubeval, před jejich zveřejněním na Chartmusem.

Obecný popis pracovního postupu vývoje grafu

  1. Nastavení potrubních úloh podle specifikace gazr.io pro kontrolu kvality (vláknění, unit-test).
  2. Vložení obrazu dockeru pomocí nástrojů Pythonu, které nasazují naše aplikace.
  3. Nastavení prostředí podle názvu pobočky.
  4. Ověřování souborů yaml Kubernetes pomocí Kubeval.
  5. Automaticky zvětšit verzi grafu a jeho nadřazených grafů (grafy, které závisí na grafu, který se mění).
  6. Odeslání grafu do Chartmusea, který odpovídá jeho prostředí

Zvládání rozdílů mezi klastry

Federace klastrů

Byly doby, kdy jsme používali federace clusterů Kubernetes, kde lze objekty Kubernetes deklarovat z jednoho koncového bodu API. Problémy se ale objevily. Například některé objekty Kubernetes nebylo možné vytvořit v koncovém bodu federace, což ztěžuje údržbu federovaných objektů a dalších objektů pro jednotlivé clustery.

Abychom problém vyřešili, začali jsme clustery spravovat samostatně, což celý proces značně zjednodušilo (použili jsme první verzi federace, ve druhé se mohlo něco změnit).

Geo-distribuovaná platforma

Naše platforma je aktuálně distribuována v 6 regionech – 3 lokálně a 3 v cloudu.


Distribuované nasazení

Globální hodnoty Helm

4 globální hodnoty Helm ​​umožňují identifikovat rozdíly mezi clustery. Všechny naše grafy mají výchozí minimální hodnoty.

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

Globální hodnoty

Tyto hodnoty pomáhají definovat kontext pro naše aplikace a používají se pro různé účely: monitorování, trasování, protokolování, provádění externích hovorů, škálování atd.

  • "cloud": Máme hybridní platformu Kubernetes. Naše API je například nasazeno v zónách GCP a v našich datových centrech.
  • "env": Některé hodnoty se mohou pro neprodukční prostředí změnit. Například definice prostředků a konfigurace automatického škálování.
  • "region": Tyto informace pomáhají určit umístění clusteru a lze je použít k určení blízkých koncových bodů pro externí služby.
  • "clusterName": pokud a kdy chceme definovat hodnotu pro jednotlivý cluster.

Zde je konkrétní příklad:

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

Příklad šablony kormidla

Tato logika je definována v pomocné šabloně, aby se zabránilo nepřehlednému Kubernetes YAML.

Oznámení aplikace

Naše nástroje pro nasazení jsou založeny na několika souborech YAML. Níže je uveden příklad, jak deklarujeme službu a její škálovací topologii (počet replik) v clusteru.

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

Definice služby

Toto je nástin všech kroků, které definují náš pracovní postup nasazení. Posledním krokem je nasazení aplikace do více pracovních clusterů současně.


Kroky nasazení Jenkinse

A co tajemství?

Pokud jde o bezpečnost, sledujeme všechna tajemství z různých míst a ukládáme je do jedinečného trezoru Klenba v Paříži.

Naše nástroje pro nasazení extrahují tajné hodnoty z Vaultu, a když přijde čas nasazení, vloží je do Helm.

Za tímto účelem jsme definovali mapování mezi tajemstvími ve Vaultu a tajemstvími, která naše aplikace potřebují:

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"

  • Definovali jsme obecná pravidla, která je třeba dodržovat při zaznamenávání tajných informací do Vaultu.
  • Pokud platí tajemství do konkrétního kontextu nebo shluku, musíte přidat konkrétní záznam. (Zde má kontext cluster1 svou vlastní hodnotu pro tajný zásobník-app1-heslo).
  • Jinak se použije hodnota ve výchozím nastavení.
  • Pro každou položku v tomto seznamu v Kubernetesovo tajemství je vložen pár klíč–hodnota. Proto je tajná šablona v našich grafech velmi jednoduchá.

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

Problémy a omezení

Práce s více repozitáři

Nyní oddělíme vývoj grafů a aplikací. To znamená, že vývojáři musí pracovat ve dvou git repozitářích: jedno pro aplikaci a druhé pro definování jejího nasazení do Kubernetes. 2 git repozitáře znamenají 2 pracovní postupy a nováček se může snadno zmást.

Správa zobecněných grafů je obtížná

Jak jsme již řekli, obecné grafy jsou velmi užitečné pro identifikaci závislostí a rychlé nasazení více aplikací. Ale používáme --reuse-valuesabychom se vyhnuli předávání všech hodnot pokaždé, když nasadíme aplikaci, která je součástí tohoto zobecněného grafu.

V nepřetržitém pracovním postupu doručování máme pouze dvě hodnoty, které se pravidelně mění: počet replik a značku obrázku (verze). Jiné, stabilnější hodnoty se mění ručně, a to je docela obtížné. Navíc jedna chyba při nasazení zobecněného grafu může vést k vážným selháním, jak jsme viděli z vlastní zkušenosti.

Aktualizace více konfiguračních souborů

Když vývojář přidá novou aplikaci, musí změnit několik souborů: deklaraci aplikace, seznam tajemství, přidání aplikace jako závislosti, pokud je zahrnuta do zobecněné tabulky.

Jenkinsova oprávnění jsou ve Vaultu příliš rozšířena

Teď jeden máme AppRole, která čte všechna tajemství z Vaultu.

Proces vrácení zpět není automatizovaný

Chcete-li vrátit zpět, musíte příkaz spustit na několika clusterech, což je plné chyb. Tuto operaci provádíme ručně, abychom zajistili, že je zadáno správné ID verze.

Posouváme se směrem ke GitOps

Náš cíl

Chceme vrátit graf do úložiště aplikace, kterou nasazuje.

Pracovní postup bude stejný jako u vývoje. Například, když je větev posunuta na master, nasazení se spustí automaticky. Hlavní rozdíl mezi tímto přístupem a současným pracovním postupem by byl v tom vše bude spravováno v git (samotná aplikace a způsob jejího nasazení v Kubernetes).

Existuje několik výhod:

  • Hodně jasnější pro vývojáře. Je snazší se naučit, jak aplikovat změny v místním grafu.
  • Lze zadat definici nasazení služby stejné místo jako kód servis.
  • Správa odstraňování zobecněných grafů. Služba bude mít vlastní verzi Helm. To vám umožní řídit životní cyklus aplikace (rollback, upgrade) na nejmenší úrovni, abyste neovlivnili ostatní služby.
  • Výhody git pro správu grafů: vrátit změny, protokol auditu atd. Pokud potřebujete vrátit zpět změnu v grafu, můžete to udělat pomocí git. Nasazení se spustí automaticky.
  • Můžete zvážit vylepšení svého pracovního postupu vývoje pomocí nástrojů jako Skaffold, pomocí kterého mohou vývojáři testovat změny v kontextu blízkém produkci.

Dvoustupňová migrace

Naši vývojáři používají tento pracovní postup již 2 roky, takže chceme, aby migrace byla co nejméně bolestivá. Proto jsme se rozhodli přidat mezikrok na cestě k cíli.
První fáze je jednoduchá:

  • Zachováváme podobnou strukturu pro nastavení nasazení aplikací, ale v jediném objektu s názvem 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 vydání na aplikaci (bez zobecněných grafů).
  • Grafy v úložišti git aplikace.

Mluvili jsme se všemi vývojáři, takže proces migrace již začal. První stupeň je stále řízen pomocí platformy CI. Brzy napíšu další příspěvek o fázi dvě: jak jsme přešli na pracovní postup GitOps Proudění. Řeknu vám, jak jsme vše nastavili a na jaké potíže jsme narazili (více úložišť, tajemství atd.). Sledujte novinky.

Zde jsme se pokusili popsat náš pokrok v pracovním postupu nasazování aplikací za poslední roky, což vedlo k úvahám o přístupu GitOps. Ještě jsme nedosáhli cíle a o výsledcích budeme referovat, ale nyní jsme přesvědčeni, že jsme udělali správně, když jsme se rozhodli vše zjednodušit a přiblížit zvyklostem vývojářů.

Zdroj: www.habr.com

Přidat komentář