Jak Dailymotion využívá Kubernetes: nasazení aplikací
V Dailymotion jsme začali používat Kubernetes v produkci před 3 lety. Ale nasazení aplikací na několika clusterech je obtížné, takže během posledních několika let jsme se snažili zlepšit naše nástroje a pracovní postupy.
Jak to začalo
Zde popíšeme, jak nasazujeme naše aplikace na několika clusterech Kubernetes po celém světě.
Pro hromadné nasazení několika objektů Kubernetes používáme , a všechny naše chartové soubory uchováváme v jednom repozitáři git. Pro nasazení kompletního stacku aplikace složeného z několika servisů používáme takzvaný agregovaný chart. V podstatě se jedná o chart, který deklaruje závislosti a umožňuje inicializaci API a jeho servisů jedním příkazem.
Také jsme napsali malý Python skript nad Helm, abychom prováděli kontroly, vytvářeli chartové soubory, přidávali tajemství a nasazovali aplikace. Všechny tyto úkoly se provádějí na centrální CI platformě za použití docker obrazu.
Přejděme k jádru.
Poznámka: Když toto čtete, první release candidate Helm 3 již byl oznámen. Hlavní verze obsahuje celou řadu vylepšení určených k řešení některých problémů, se kterými jsme se v minulosti potýkali.
Pracovní postup vývoje chartů
Pro aplikace používáme větvení a stejný přístup jsme se rozhodli aplikovat na chartové soubory.
- Větev dev se používá pro vytváření chartů, které budou testovány na vývojových clusterech.
- Když je pull request odeslán do master, je testován na stagingu.
- Nakonec vytvoříme pull request, abychom předali změny do větve prod a aplikovali je v produkci.
Každé prostředí má svůj vlastní soukromý repozitář, který uchovává naše chartové soubory, a používáme s velmi užitečným API. Tímto způsobem zajišťujeme přísnou izolaci mezi prostředími a kontrolu chartů v reálných podmínkách, než je použijeme v produkci.
Repozitáře chartů v různých prostředích
Je třeba poznamenat, že když vývojáři odesílají větev dev, verze jejich chartu je automaticky odeslána do dev Chartmuseum. Takto všichni vývojáři používají jeden dev repozitář a musí si pečlivě uvědomovat verzi svého chartu, aby náhodou nepoužili změny někoho jiného.
Navíc, náš malý skript v Pythonu kontroluje objekty Kubernetes podle specifikací Kubernetes OpenAPI pomocí , než je zveřejní v Chartmusem.
Obecný popis pracovního postupu pro vývoj grafu
- Nastavení úloh pipeline podle specifikace pro kontrolu kvality (lint, unit-test).
- Odeslání docker obrazu s nástroji Python, které nasazují naše aplikace.
- Nastavení prostředí podle názvu větve.
- Kontrola yaml souborů Kubernetes pomocí Kubeval.
- Automatické zvýšení verze grafu a jeho parent grafů (grafů, které závisí na měněném grafu).
- Odeslání grafu do Chartmuseum, které odpovídá jeho prostředí
Správa rozdílů v clusterech
Federace clusterů
Byla doba, kdy jsme používali , kde bylo možné deklarovat objekty Kubernetes z jednoho API endpointu. Ale objevily se problémy. Například některé objekty Kubernetes nebylo možné vytvořit na federovaném endpointu, takže bylo obtížné udržovat sloučené objekty a další objekty pro jednotlivé clustery.
Abychom tento problém vyřešili, začali jsme spravovat clustry nezávisle, což výrazně zjednodušilo proces (používali jsme první verzi federace; ve druhé se mohlo něco změnit).
Geograficky distribuovaná platforma
Naše platforma je nyní distribuována do 6 regionů – 3 lokálně a 3 v cloudu.
Distribuované nasazení
Globální hodnoty Helm
4 globální hodnoty Helm umožňují určit rozdíly mezi clustery. Pro všechny naše grafy existují minimální výchozí hodnoty.
global:
cloud: True
env: staging
region: us-central1
clusterName: staging-us-central1Globální hodnoty
Tyto hodnoty pomáhají určit kontext pro naše aplikace a používají se pro různé úkoly: monitorování, trasování, logování, provádění externích volání, škálování atd.
- "cloud": máme hybridní platformu Kubernetes. Například náš API se nasazuje v oblastech GCP a v našich datových centrech.
- "env": některé hodnoty se mohou měnit pro nepracovní prostředí. Například definice zdrojů a konfigurace automatického škálování.
- "region": tyto informace pomáhají určit umístění clusteru a mohou být použity k určení nejbližších endpointů pro externí služby.
- "clusterName": pokud a kdy chceme určit hodnotu pro jednotlivý cluster.
Toto je konkrétní příklad:
{{
/* Vrací horizontální autoscaler repliku pro 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 Helm
Tato logika je definována v pomocné šabloně, aby nedocházelo k znečištění Kubernetes YAML.
Oznámení aplikace
Naše nasazovací nástroje jsou založeny na několika souborech YAML. Níže je příklad toho, jak oznamujeme službu a její topologii škálování (počet replik) v klastru.
releases:
- foo.world
foo.world: # Název vydání
services: # Seznam aplikací/projektů dailymotion
foobar:
chart_name: foo-foobar
repo: git@github.com:dailymotion/foobar
contexts:
prod-europe-west1:
deployments:
- name: foo-bar-baz
replicas: 18
- name: another-deployment
replicas: 3Definice služby
Toto je schéma všech kroků, které definují náš pracovní postup nasazení. Poslední krok nasazuje aplikaci současně na několika pracovních klastrech.
Kroky nasazení v Jenkins
A co tajemství?
Pokud jde o bezpečnost, sledujeme všechna tajemství z různých zdrojů a ukládáme je v unikátním úložišti v Paříži.
Naše nasazovací nástroje načítají hodnoty tajemství z Vault a, když nastane čas nasazení, vkládají je do Helm.
K tomu jsme definovali mapování mezi tajemstvími ve Vault 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"- Stanovili jsme obecná pravidla, kterými se musíme řídit při zapisování tajemství do Vaultu.
- Pokud se tajemství vztahuje k určitému kontextu nebo clusteru, je nutné přidat konkrétní záznam. (Zde má kontext cluster1 vlastní hodnotu pro tajemství stack-app1-password).
- V opačném případě se používá hodnota ve výchozím nastavení.
- Pro každý bod v tomto seznamu je tajemství Kubernetes vložen pár klíč-hodnota. Proto je šablona tajemství v našich chartech 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: OpaqueProblémy a omezení
Práce s více repozitáři
Momentálně oddělujeme vývoj chartů a aplikací. To znamená, že vývojáři musí pracovat ve dvou git repozitářích: jednom pro aplikaci a druhém pro definici jejího nasazení v Kubernetes. Dva git repozitáře znamenají dva pracovní postupy a nováček se může snadno zmást.
Správa generických chartů je pracná
Jak jsme již zmínili, generické chartové soubory jsou velmi pohodlné pro definování závislostí a rychlé nasazení několika aplikací. Ale používáme --reuse-values, abychom se vyhnuli předávání všech hodnot pokaždé, když nasazujeme aplikaci patřící do tohoto generického chartu.
V pracovním procesu kontinuální dodávky máme pouze dvě hodnoty, které se pravidelně mění: počet replik a tag obrazu (verze). Ostatní, stabilnější hodnoty, se mění ručně, což je poměrně složité. Navíc jedna chyba při nasazení generického chartu může vést k vážným problémům, jak jsme zjistili na vlastní kůži.
Aktualizace několika konfiguračních souborů
Když vývojář přidá novou aplikaci, musí změnit několik souborů: příslušnost aplikace, seznam tajností, přidání aplikace do závislostí, pokud je součástí generického chartu.
Oprávnění Jenkins jsou příliš rozšířena ve Vault
Momentálně máme jednu , která čte všechna tajemství z Vault.
Proces rollbacku není automatizován
Pro rollback je třeba vykonat příkaz na několika clusterech, což je náchylné k chybám. Tento úkon provádíme ručně, abychom mohli určit správný identifikátor verze.
Směřujeme k GitOps
Naším cílem
Chceme vrátit chart do repozitáře aplikace, kterou nasazuje.
Pracovní postup bude stejný jako pro vývoj. Například, když je větev odeslána do master, nasazení se spustí automaticky. Hlavní rozdíl mezi tímto přístupem a současným pracovním postupem bude v tom, že všechno bude řízeno v gitu (jak aplikace, tak způsob jejího nasazení v Kubernetes).
Je několik výhod:
- Daleko jasnější pro vývojáře. Snazší naučit se aplikovat změny v místním chartu.
- Definice nasazení služby může být uvedena tam, kde je kód služby.
- Správa odstraňování generických chartů. Služba bude mít svůj vlastní Helm release. To umožní řídit životní cyklus aplikace (rollback, upgrade) na nejnižší úrovni, aby se nedotýkala jiných služeb.
- Výhody gitu pro správu chartů: zrušení změn, protokol auditu atd. Pokud je potřeba zrušit změnu chartu, lze to udělat pomocí gitu. Nasazení se spustí automaticky.
- Můžeme uvažovat o zlepšení pracovního postupu vývoje pomocí takových nástrojů, jako je Skaffold, se kterým mohou vývojáři testovat změny v kontextu blízkém produkci.
Dvoufázová migrace
Naši vývojáři používají tento pracovní proces již 2 roky, takže potřebujeme co nejméně bolestivou migraci. Proto jsme se rozhodli přidat mezičlánek na cestě k cíli.
První krok je jednoduchý:
- Zachováváme podobnou strukturu pro nastavení nasazení aplikací, ale v jednom 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 release na aplikaci (bez obecných chartů).
- Chartu v git repozitáři aplikace.
Povídali jsme si se všemi vývojáři, takže proces migrace již začal. První fáze se přesto stále kontroluje pomocí CI platformy. Brzy napíšu další příspěvek o druhé fázi: jak jsme přešli na pracovní postup GitOps s . Řeknu, jak jsme všechno nastavili a s jakými obtížemi jsme se potýkali (několik repozitářů, tajemství atd.). Sledujte novinky.
Zde jsme se pokusili popsat náš pokrok v pracovnímu postupu nasazení aplikací za poslední roky, který vedl k myšlenkám na přístup GitOps. Ještě jsme nedosáhli cíle a budeme informovat o výsledcích, ale nyní jsme přesvědčeni, že jsme udělali správnou věc, když jsme se rozhodli všechno zjednodušit a přiblížit se zvyklostem vývojářů.
Zdroj: habr.com
