Hur Dailymotion anvÀnder Kubernetes: distribution av applikationer
Vi pÄ Dailymotion började anvÀnda Kubernetes i produktion för tre Är sedan. Men att distribuera applikationer pÄ flera kluster Àr en utmaning, sÄ under de senaste Ären har vi försökt förbÀttra vÄra verktyg och arbetsflöden.
Hur det började
HÀr berÀttar vi hur vi distribuerar vÄra applikationer pÄ flera Kubernetes-kluster runt om i vÀrlden.
För att distribuera flera Kubernetes-objekt samtidigt anvÀnder vi , och alla vÄra chartar lagras i ett enda git-repositorium. För att distribuera en fullstÀndig applikationsstack bestÄende av flera tjÀnster, anvÀnder vi en sÄ kallad övergripande chart. I grund och botten Àr det en chart som deklarerar beroenden och gör det möjligt att initiera API:er och deras tjÀnster med ett enda kommando.
Vi har ocksÄ skrivit ett litet Python-skript ovanpÄ Helm för att göra kontroller, skapa chartar, lÀgga till hemligheter och distribuera applikationer. Alla dessa uppgifter utförs pÄ en central CI-plattform med hjÀlp av en docker-image.
LÄt oss gÄ till kÀrnan.
Obs. NÀr du lÀser detta har den första releasekandidaten för Helm 3 redan tillkÀnnagivits. Huvudversionen innehÄller en hel uppsÀttning förbÀttringar som syftar till att lösa vissa problem vi har stött pÄ tidigare.
Utvecklingsarbetsflöde för chartar
För applikationer anvÀnder vi grenar, och vi bestÀmde oss för att tillÀmpa denna metod Àven pÄ chartarna.
- Grenen dev anvÀnds för att skapa chartar som kommer att testas pÄ utvecklingskluster.
- NÀr en pull-begÀran överförs till master, de testas i staging.
- Slutligen skapar vi en pull-begÀran för att överföra Àndringar till grenen prod och tillÀmpa dem i produktion.
Varje miljö har sitt eget privata repositorium som lagrar vÄra chartar, och vi anvÀnder med mycket anvÀndbara API:er. PÄ sÄ sÀtt sÀkerstÀller vi strikt isolering mellan miljöerna och testning av chartarna under verkliga förhÄllanden innan vi anvÀnder dem i produktion.
Repositorier för chartar i olika miljöer
Det Àr vÀrt att notera att nÀr utvecklare skickar en dev-gren, skickas versionen av deras chart automatiskt till dev Chartmuseum. SÄledes anvÀnder alla utvecklare ett gemensamt dev-repositorium, och det Àr viktigt att noggrant ange sin chart-version för att inte av misstag anvÀnda nÄgon annans Àndringar.
Dessutom kontrollerar vÄrt lilla Python-skript Kubernetes-objekt mot specifikationerna för Kubernetes OpenAPI med hjÀlp av , innan de publiceras i Chartmuseum.
Ăversikt över arbetsflödet för chartutveckling
- InstÀllning av pipeline-uppgifter enligt specifikationen för kvalitetskontroll (lint, enhetstest).
- Skicka dockerbilden med Python-verktyg som distribuerar vÄra applikationer.
- Konfigurera miljön efter grenens namn.
- Kontrollera Kubernetes yaml-filer med hjÀlp av Kubeval.
- Automatisk ökning av versionen pÄ chartet och dess förÀldrarchart (de chart som beror pÄ det Àndrade chartet).
- Skicka chartet till Chartmuseum som motsvarar dess miljö
Hantera skillnader mellan kluster
Federering av kluster
Det var en tid nÀr vi anvÀnde , dÀr man kunde deklarera Kubernetes-objekt frÄn en API-slutpunkt. Men det uppstod problem. Till exempel kunde vissa Kubernetes-objekt inte skapas vid federationsslutpunkten, vilket gjorde det svÄrt att underhÄlla sammanstÀllda objekt och andra objekt för individuella kluster.
För att lösa problemet började vi hantera kluster oberoende, vilket avsevÀrt förenklade processen (vi anvÀnde den första versionen av federation; i den andra kunde nÄgot ha Àndrats).
Geodistribuerad plattform
Nu Ă€r vĂ„r plattform distribuerad över 6 regioner â 3 lokalt och 3 i molnet.
Distribuerad distribution
Globala vÀrden för Helm
4 globala vÀrden för Helm gör det möjligt att definiera skillnader mellan kluster. För alla vÄra chart finns det minimivÀrden som standard.
global:
cloud: True
env: staging
region: us-central1
clusterName: staging-us-central1Globala vÀrden
Dessa vÀrden hjÀlper till att definiera kontexten för vÄra applikationer och anvÀnds för olika uppgifter: övervakning, spÄrning, loggning, externa anrop, automatisering och sÄ vidare.
- "cloud": vi har en hybrid Kubernetes-plattform. Till exempel distribueras vÄrt API i GCP-zoner och i vÄra datacenter.
- "env": vissa vÀrden kan variera för icke-produktionsmiljöer. Till exempel resursdefinitioner och konfigurationer för automatisk skalning.
- "region": denna information hjÀlper till att definiera klustrets lÀge och kan anvÀndas för att faststÀlla nÀrmaste slutpunkter för externa tjÀnster.
- "clusterName": om och nÀr vi vill definiera ett vÀrde för ett enskilt kluster.
HÀr Àr ett konkret exempel:
{{
/* Returnerar Horizontal Pod Autoscaler-replikat för GraphQL*/}}
{{- definiera "graphql.hpaReplicas" -}}
{{- om eq .Values.global.env "prod" }}
{{- om eq .Values.global.region "europe-west1" }}
minReplicas: 40
{{- annars }}
minReplicas: 150
{{- slut }}
maxReplicas: 1400
{{- annars }}
minReplicas: 4
maxReplicas: 20
{{- slut }}
{{- slut -}}Exempel pÄ en Helm-mall
Denna logik definieras i en hjÀlpmall för att inte överbelasta Kubernetes YAML.
Applikationsdeklaration
VÄra distributionsverktyg baseras pÄ flera YAML-filer. Nedan Àr ett exempel pÄ hur vi deklarerar en tjÀnst och dess skalningstopologi (antal replikat) i klustret.
releases:
- foo.world
foo.world: # Namn pÄ releasen
services: # Lista över dailymotion's appar/projekt
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: 3TjÀnstedeklaration
Detta Àr en översikt av alla steg som definierar vÄr distributionsarbetsflöde. Det sista steget distribuerar applikationen samtidigt i flera arbetskluster.
Distributionssteg i Jenkins
Och hemligheterna?
Vad gÀller sÀkerhet sÄ följer vi alla hemligheter frÄn olika platser och lagrar dem i ett unikt förrÄd i Paris.
VÄra distributionsverktyg hÀmtar hemligheternas vÀrden frÄn Vault och, nÀr det Àr dags för distribution, infogar dem i Helm.
För detta har vi definierat en mappning mellan hemligheterna i Vault och de hemligheter som vÄra applikationer behöver:
hemligheter:
- secret_id: "stack1-app1-password"
kontexter:
- namn: "default"
vaultPath: "\/kv\/dev\/stack1\/app1\/test"
vaultKey: "password"
- namn: "cluster1"
vaultPath: "\/kv\/dev\/stack1\/app1\/test"
vaultKey: "password"- Vi har faststÀllt allmÀnna regler som mÄste följas vid inspelning av hemligheter i Vault.
- Om hemligheten hör till en viss kontext eller kluster, mÄste en specifik post lÀggas till. (HÀr har kontexten cluster1 sitt eget vÀrde för hemligheten stack-app1-password).
- Annars anvÀnds vÀrdet standard.
- För varje punkt i denna lista i Kubernetes-hemligheten infogas ett nyckel-vÀrde-par. DÀrför Àr mallen för hemligheten i vÄra diagram mycket 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 }}"
typ: OpaqueProblem och begrÀnsningar
Arbeta med flera lager
Just nu delar vi utvecklingen av diagram och applikationer. Det innebÀr att utvecklarna mÄste arbeta i tvÄ git-repositorier: ett för applikationen och ett annat för att definiera dess distribution i Kubernetes. 2 git-repositorier innebÀr 2 arbetsflöden, och det Àr lÀtt för en nybörjare att bli förvirrad.
Att hantera generiska diagram Àr besvÀrligt
Som redan nÀmnts Àr generiska diagram mycket anvÀndbara för att definiera beroenden och snabbt distribuera flera applikationer. Men vi anvÀnder --reuse-values, för att undvika att skicka vidare alla vÀrden varje gÄng vi distribuerar en applikation som ingÄr i det generiska diagrammet.
I den kontinuerliga leveransprocessen har vi bara tvÄ vÀrden som Àndras regelbundet: antalet repliker och bildtaggen (version). Andra, mer stabila vÀrden Àndras manuellt, vilket Àr ganska svÄrt. Dessutom kan ett enda fel i distributionen av en generell chart leda till allvarliga fel, som vi har sett av egen erfarenhet.
Uppdatering av flera konfigurationsfiler
NÀr en utvecklare lÀgger till en ny applikation mÄste han Àndra flera filer: applikationsdeklarationen, listan över hemligheter och lÀgga till applikationen i beroendena om den ingÄr i den generella charten.
Jenkins-behörigheter Àr för omfattande i Vault
Nu har vi en , som lÀser alla hemligheter frÄn Vault.
Rollback-processen Àr inte automatiserad
För rollback mÄste man köra kommandot pÄ flera kluster, vilket kan leda till fel. Vi utför denna operation manuellt för att sÀkerstÀlla att rÀtt versionsidentifierare anges.
Vi rör oss mot GitOps
VÄrt mÄl
Vi vill föra tillbaka charten till applikationsrepositoryt som den distribuerar.
Arbetsflödet kommer att vara detsamma som för utveckling. Till exempel, nÀr en gren skickas till master, kommer distributionen att starta automatiskt. Den huvudsakliga skillnaden mellan detta tillvÀgagÄngssÀtt och det nuvarande arbetsflödet Àr att allt kommer att hanteras i git (sjÀlva applikationen och hur den distribueras i Kubernetes).
Det finns flera fördelar:
- Mycket mer begripligt för utvecklaren. Det Àr enklare att lÀra sig tillÀmpa Àndringar i den lokala charten.
- Definitionen av distributionen av tjÀnsten kan anges dÀr dÀr koden för tjÀnsten.
- Hantering av borttagning av generella charts. TjÀnsten kommer att ha sin egen Helm-release. Detta kommer att möjliggöra hantering av applikationens livscykel (rollback, uppgradering) pÄ den minsta nivÄn, sÄ att andra tjÀnster inte pÄverkas.
- Fördelar med git för hantering av charts: ÀndringsÄterkallelse, revisionslogg osv. Om en Àndring av charten mÄste Äterkallas kan detta göras med hjÀlp av git. Distributionen startar automatiskt.
- Man kan övervÀga att förbÀttra utvecklingsarbetsflödet med hjÀlp av sÄdana verktyg som Skaffold, dÀr utvecklare kan testa Àndringar i en kontext som liknar produktionsmiljön.
TvÄstegs migrering
VÄra utvecklare har anvÀnt denna arbetsprocess i 2 Är, sÄ vi behöver en sÄ smidig migrering som möjligt. DÀrför beslutade vi att lÀgga till ett mellanliggande steg pÄ vÀgen mot mÄlet.
Det första steget Àr enkelt:
- Vi behÄller en liknande struktur för att konfigurera distributionen av applikationer, men i ett objekt med namnet 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 per applikation (utan allmÀnna diagram).
- Diagram i applikations Git-förvaret.
Vi har pratat med alla utvecklare, sÄ migrationsprocessen har redan pÄbörjats. Det första steget kontrolleras fortfarande med hjÀlp av CI-plattformen. Snart kommer jag att skriva ett inlÀgg om det andra steget: hur vi gick över till arbetsprocessen GitOps med . Jag kommer att berÀtta hur vi konfigurerade allt och vilka svÄrigheter vi stötte pÄ (flera förvar, hemligheter osv.). HÄll dig uppdaterad.
HÀr har vi försökt beskriva vÄra framsteg inom distributionsprocessen av applikationer de senaste Ären, vilket har lett till tankar om GitOps-ansatsen. Vi har Ànnu inte nÄtt mÄlet och kommer att rapportera om resultaten, men vi Àr nu övertygade om att vi gjorde rÀtt nÀr vi beslutade att förenkla allt och anpassa det till utvecklarnas vanor.
KĂ€lla: habr.com
