Hoe Dailymotion Kubernetes gebruikt: applicatiedeployments
Bij Dailymotion zijn we drie jaar geleden begonnen met het gebruik van Kubernetes in productie. Maar het is geen gemakkelijke taak om applicaties op meerdere clusters te deployen, dus hebben we de afgelopen jaren geprobeerd onze tools en workflows te verbeteren.
Waar het mee begon
Hier vertellen we hoe we onze applicaties op meerdere Kubernetes-clusters over de hele wereld implementeren.
Om meerdere Kubernetes-objecten in één keer te implementeren, gebruiken we , en al onze charts worden in één git-repository opgeslagen. Om een volledige applicatiestack van meerdere services te implementeren, gebruiken we een zogenaamde aggregator chart. Dit is in wezen een chart die afhankelijkheden declareert en het mogelijk maakt om de API en zijn services met één commando te initialiseren.
Daarnaast hebben we een kleine Python-script bovenop Helm geschreven om controles uit te voeren, charts te creëren, geheimen toe te voegen en applicaties te implementeren. Al deze taken worden uitgevoerd op een centraal CI-platform met behulp van een Docker-image.
Laten we naar de kern gaan.
Opmerking. Wanneer je dit leest, is de eerste releasecandidate van Helm 3 al aangekondigd. De belangrijkste versie bevat een hele reeks verbeteringen die zijn ontworpen om enkele problemen aan te pakken waarmee we in het verleden te maken hadden.
Workflow voor het ontwikkelen van charts
Voor applicaties gebruiken we branching, en we hebben besloten dezelfde aanpak op charts toe te passen.
- De tak , maar volgt geen wijzigingen), gebruikmakend van een andere configuratie. wordt gebruikt voor het creëren van charts die op ontwikkelingsclusters worden getest.
- Wanneer een pull request wordt ingediend in master, worden ze in de staging getest.
- Ten slotte maken we een pull request om de wijzigingen naar de tak te brengen prod en deze toe te passen in productie.
Elke omgeving heeft zijn eigen privérepository waarin onze charts worden opgeslagen, en we gebruiken met zeer nuttige API's. Dit zorgt ervoor dat we strikte isolatie tussen omgevingen garanderen en charts onder reële omstandigheden testen voordat we ze in productie gebruiken.
Chartrepositories in verschillende omgevingen
Het is vermeldenswaard dat wanneer ontwikkelaars een dev-tak indienen, hun chartversie automatisch naar dev Chartmuseum wordt gestuurd. Zo gebruiken alle ontwikkelaars één dev-repository, en is het belangrijk om de chartversie nauwkeurig op te geven om te voorkomen dat per ongeluk iemand anders' wijzigingen worden gebruikt.
Bovendien controleert ons kleine Python-script Kubernetes-objecten op basis van de Kubernetes OpenAPI-specificaties met behulp van , voordat we ze in Chartmuseum publiceren.
Algemene beschrijving van de chart-ontwikkeling workflow
- Configuratie van pipeline-taken volgens de specificatie voor kwaliteitscontrole (lint, unit-test).
- Verzending van de docker-image met Python-tools die onze applicaties uitrollen.
- Configuratie van de omgeving op basis van de branchnaam.
- Controleren van Kubernetes yaml-bestanden met Kubeval.
- Automatische versie-increment van de chart en zijn oudercharts (charts die afhankelijk zijn van de wijzigende chart).
- Verzending van de chart naar Chartmuseum, die overeenkomt met zijn omgeving
Beheer van verschillen in clusters
Federatie van clusters
Er was een tijd dat we gebruikten , waar we Kubernetes-objecten vanuit één API-eindpunt konden maken. Maar er waren problemen. Bijvoorbeeld, sommige Kubernetes-objecten konden niet worden aangemaakt via het federatie-eindpunt, waardoor het moeilijk was om geaggregeerde objecten en andere objecten voor afzonderlijke clusters te beheren.
Om het probleem op te lossen, zijn we onafhankelijk gaan beheren van clusters, wat het proces aanzienlijk vereenvoudigde (we gebruikten de eerste versie van de federatie; in de tweede kon er iets gewijzigd zijn).
Geodistribueerd platform
Momenteel is ons platform verspreid over 6 regio's—3 lokaal en 3 in de cloud.
Distributed deployment
Globale Helm-waarden
4 globale Helm-waarden maken het mogelijk om verschillen tussen clusters vast te stellen. Voor al onze charts zijn er minimale standaardwaarden.
global:
cloud: True
env: staging
region: us-central1
clusterName: staging-us-central1Globale waarden
Deze waarden helpen om context te bepalen voor onze applicaties en worden gebruikt voor verschillende taken: monitoring, tracing, logging, externe aanroepen, schaling, enzovoorts.
- "cloud": we hebben een hybride Kubernetes-platform. Bijvoorbeeld, onze API wordt uitgerold in GCP-zones en in onze datacenters.
- "env": sommige waarden kunnen variëren voor niet-werkende omgevingen. Bijvoorbeeld, resource-definities en auto-scalingconfiguraties.
- "region": deze informatie helpt het locatie van het cluster te bepalen en kan worden gebruikt om de dichtstbijzijnde eindpunten voor externe services te identificeren.
- "clusterName": als en wanneer we een waarde voor een afzonderlijk cluster willen definiëren.
Hier is een concreet voorbeeld:
{{
/* Retourneert de replicaten van de Horizontal Pod Autoscaler voor 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 -}}Voorbeeld van een Helm-sjabloon
Deze logica is gedefinieerd in een hulpsjabloon om Kubernetes YAML niet te vervuilen.
Applicatieverklaring
Onze implementatietools zijn gebaseerd op verschillende YAML-bestanden. Hieronder staat een voorbeeld van hoe we een service en zijn schaalstructuur (aantal replicaten) in de cluster verklaren.
releases:
- foo.world
foo.world: # Naam van de release
services: # Lijst van dailymotion's apps/projecten
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: 3Servicedefinitie
Dit is een schema van alle stappen die onze implementatieworkflow definiëren. De laatste stap implementeert de applicatie gelijktijdig op meerdere werkklusters.
Implementatiestappen in Jenkins
En de secrets?
Wat betreft beveiliging volgen we alle secrets vanuit verschillende bronnen en bewaren we ze in een unieke opslag. in Parijs.
Onze implementatietools halen de waarden van secrets uit Vault en voegen, wanneer het tijd is om te implementeren, deze toe aan Helm.
Hiervoor hebben we een mapping gedefinieerd tussen de secrets in Vault en de secrets die onze applicaties nodig hebben:
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"- We hebben algemene regels vastgesteld die moeten worden gevolgd bij het opslaan van geheimen in de Vault.
- Als een geheim hoort bij een bepaalde context of cluster, moet er een specifieke vermelding worden toegevoegd. (Hier heeft de context cluster1 een eigen waarde voor het geheim stack-app1-password).
- In andere gevallen wordt de waarde gebruikt. standaard.
- Voor elk item in deze lijst wordt er in de Kubernetes geheim een sleutel-waarde paar ingevoegd. Daarom is de sjabloon voor geheimen in onze charts erg eenvoudig.
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: OpaqueProblemen en beperkingen
Werken met meerdere repositories
Momenteel splitsen we de ontwikkeling van charts en applicaties. Dit betekent dat ontwikkelaars in twee git-repositories moeten werken: één voor de applicatie en de andere voor het definiëren van de implementatie in Kubernetes. Twee git-repositories betekent twee werkprocessen, en het is gemakkelijk voor een nieuwkomer om in de war te raken.
Het beheren van generieke charts is omslachtig
Zoals we al zeiden, zijn generieke charts zeer handig voor het definiëren van afhankelijkheden en het snel implementeren van meerdere applicaties. Maar we gebruiken --reuse-values, om te voorkomen dat we elke keer weer alle waarden overdragen wanneer we een applicatie implementeren die deel uitmaakt van deze generieke chart.
Binnen het proces van continue levering hebben we slechts twee waarden die regelmatig veranderen: het aantal exemplaren en de afbeeldingstag (versie). Andere, stabielere waarden worden handmatig gewijzigd en dat is behoorlijk ingewikkeld. Bovendien kan één fout in de implementatie van een algemene chart leiden tot ernstige storingen, zoals we uit eigen ervaring hebben geleerd.
Het bijwerken van meerdere configuratiebestanden
Wanneer een ontwikkelaar een nieuwe applicatie toevoegt, moet hij verschillende bestanden aanpassen: de applicatieverklaring, de lijst met geheimen en het toevoegen van de applicatie aan de afhankelijkheden, als het deel uitmaakt van de algemene chart.
De Jenkins-rechten zijn te uitgebreid in Vault
We hebben nu één , die alle geheimen uit Vault leest.
Het terugrolproces is niet geautomatiseerd
Voor een terugrol moet een opdracht op meerdere clusters worden uitgevoerd, wat foutgevoelig is. We voeren deze handeling handmatig uit om ervoor te zorgen dat we de juiste versie-id opgeven.
We bewegen richting GitOps
Ons doel
We willen de chart terugbrengen naar de repository van de applicatie die hij implementeert.
De workflow zal hetzelfde zijn als voor ontwikkeling. Bijvoorbeeld, wanneer de tak naar master wordt gepusht, wordt de implementatie automatisch gestart. Het belangrijkste verschil tussen deze aanpak en de huidige workflow is dat alles in git zal worden beheerd (de applicatie zelf en de manier waarop deze wordt geïmplementeerd in Kubernetes).
Er zijn verschillende voordelen:
- Veel duidelijker voor de ontwikkelaar. Het is gemakkelijker om wijzigingen in de lokale chart toe te passen.
- De definitie van de service-implementatie kan worden opgegeven op dezelfde plaats als de code van de service.
- Beheer van het verwijderen van algemene charts. De service zal zijn eigen Helm-release hebben. Dit stelt ons in staat om de levenscyclus van de applicatie (terugrol, upgrade) op het fijnste niveau te beheren, zodat andere services niet worden beïnvloed.
- Voordelen van git voor het beheren van charts: wijzigingen terugdraaien, auditlog, enz. Als er een wijziging in de chart moet worden teruggedraaid, kan dit met git worden gedaan. De implementatie wordt automatisch gestart.
- Men kan nadenken over het verbeteren van de ontwikkelingsworkflow met behulp van tools zoals Skaffold, waarmee ontwikkelaars wijzigingen kunnen testen in een omgeving die dicht bij productie ligt.
Twee-fasen migratie
Onze ontwikkelaars gebruiken deze workflow al 2 jaar, dus we hebben een zo soepel mogelijke migratie nodig. Daarom hebben we besloten om een tussentijdse stap in ons proces toe te voegen.
De eerste stap is eenvoudig:
- We behouden een vergelijkbare structuur voor het instellen van de applicatie-implementatie, maar in één object genaamd 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 applicatie (zonder algemene charts).
- Charts in de git-repository van de applicatie.
We hebben met alle ontwikkelaars gesproken, dus het migratieproces is al begonnen. De eerste stap wordt nog steeds gecontroleerd met behulp van het CI-platform. Binnenkort schrijf ik een andere post over de tweede stap: hoe we overgeschakeld zijn naar een GitOps-workflow met . Ik zal vertellen hoe we alles hebben ingesteld en met welke uitdagingen we te maken kregen (meerdere repositories, geheimen, enz.). Blijf op de hoogte.
Hier proberen we onze voortgang in het proces van applicatie-implementatie in de afgelopen jaren te beschrijven, wat heeft geleid tot gedachten over de GitOps-aanpak. We hebben ons doel nog niet bereikt en zullen onze resultaten blijven delen, maar we zijn er nu van overtuigd dat we het juiste hebben gedaan door alles te vereenvoudigen en dichter bij de gewoonten van ontwikkelaars te brengen.
Bron: habr.com
