Implementeer applicaties in meerdere Kubernetes-clusters met Helm

Hoe Dailymotion Kubernetes gebruikt: applicatie-implementatie

Wij bij Dailymotion zijn 3 jaar geleden begonnen met het gebruik van Kubernetes in productie. Maar het implementeren van applicaties over meerdere clusters is leuk, dus de afgelopen jaren hebben we geprobeerd onze tools en workflows te verbeteren.

Waar begon het

Hier bespreken we hoe we onze applicaties implementeren in meerdere Kubernetes-clusters over de hele wereld.

Om meerdere Kubernetes-objecten tegelijk in te zetten, gebruiken we Stuurstand, en al onze grafieken worden opgeslagen in één git-repository. Om een ​​volledige applicatiestack uit meerdere diensten in te zetten, gebruiken we het zogenaamde samenvattende diagram. In wezen is dit een diagram dat afhankelijkheden declareert en waarmee u de API en zijn services met één opdracht kunt initialiseren.

We hebben ook een klein Python-script bovenop Helm geschreven om controles uit te voeren, grafieken te maken, 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 ter zake komen.

Opmerking. Terwijl je dit leest, is de eerste release candidate voor Helm 3 al aangekondigd. De hoofdversie bevat een hele reeks verbeteringen om enkele problemen op te lossen die we in het verleden zijn tegengekomen.

Werkstroom voor grafiekontwikkeling

We gebruiken vertakkingen voor toepassingen en we hebben besloten dezelfde aanpak toe te passen op diagrammen.

  • Tak dev gebruikt om grafieken te maken die zullen worden getest op ontwikkelingsclusters.
  • Wanneer een pull-verzoek wordt ingediend bij meester, ze worden in enscenering gecontroleerd.
  • Ten slotte maken we een pull-aanvraag om de wijzigingen in de vertakking door te voeren por en deze toepassen in de productie.

Elke omgeving heeft zijn eigen privérepository waarin onze grafieken worden opgeslagen, en die wij gebruiken Kaartmuseum met zeer nuttige API's. Op deze manier zorgen we voor een strikte isolatie tussen omgevingen en het in de praktijk testen van kaarten voordat we ze in productie gebruiken.

Grafiekopslagplaatsen in verschillende omgevingen

Het is vermeldenswaard dat wanneer ontwikkelaars een dev-branch pushen, een versie van hun diagram automatisch naar het dev Chartmuseum wordt gepusht. Alle ontwikkelaars gebruiken dus dezelfde dev-repository en u moet uw versie van het diagram zorgvuldig specificeren om niet per ongeluk de wijzigingen van iemand anders te gebruiken.

Bovendien valideert ons kleine Python-script Kubernetes-objecten aan de hand van de Kubernetes OpenAPI-specificaties Kubeval, voordat ze op Chartmusem worden gepubliceerd.

Algemene beschrijving van de werkstroom voor het ontwikkelen van diagrammen

  1. Pipelinetaken volgens specificatie opzetten gazr.io voor kwaliteitscontrole (lint, unit-test).
  2. Een docker-image pushen met Python-tools die onze applicaties implementeren.
  3. De omgeving instellen op filiaalnaam.
  4. Valideren van Kubernetes yaml-bestanden met behulp van Kubeval.
  5. Vergroot automatisch de versie van een diagram en de bovenliggende diagrammen (diagrammen die afhankelijk zijn van het diagram dat wordt gewijzigd).
  6. Een kaart indienen bij een kaartenmuseum dat past bij zijn omgeving

Het beheren van verschillen tussen clusters

Federatie van Clusters

Er was een tijd dat we dat gebruikten federatie van Kubernetes-clusters, waarbij Kubernetes-objecten kunnen worden gedeclareerd vanaf één enkel API-eindpunt. Maar er ontstonden problemen. Sommige Kubernetes-objecten konden bijvoorbeeld niet in het federatie-eindpunt worden gemaakt, waardoor het moeilijk werd om federatieve objecten en andere objecten voor individuele clusters te onderhouden.

Om het probleem op te lossen, zijn we de clusters zelfstandig gaan beheren, wat het proces enorm vereenvoudigde (we gebruikten de eerste versie van federatie; in de tweede versie zou er misschien iets veranderd zijn).

Geo-gedistribueerd platform

Ons platform is momenteel verdeeld over 6 regio’s: 3 lokaal en 3 in de cloud.


Gedistribueerde implementatie

Global Helm-waarden

Met 4 globale Helm-waarden kunt u verschillen tussen clusters identificeren. Al onze grafieken hebben standaard minimumwaarden.

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

Mondiale waarden

Deze waarden helpen de context voor onze applicaties te definiëren en worden voor verschillende doeleinden gebruikt: monitoring, tracing, loggen, extern bellen, schalen, etc.

  • "cloud": We hebben een hybride Kubernetes-platform. Onze API wordt bijvoorbeeld ingezet in GCP-zones en in onze datacenters.
  • "env": Sommige waarden kunnen veranderen voor niet-productieomgevingen. Bijvoorbeeld resourcedefinities en configuraties voor automatisch schalen.
  • "regio": deze informatie helpt bij het bepalen van de locatie van het cluster en kan worden gebruikt om nabijgelegen eindpunten voor externe services te bepalen.
  • "clusterName": als en wanneer we een waarde voor een individueel cluster willen definiëren.

Hier is een specifiek voorbeeld:

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

Voorbeeld van een Helm-sjabloon

Deze logica is gedefinieerd in een helpersjabloon om te voorkomen dat Kubernetes YAML rommelig wordt.

Aankondiging van toepassing

Onze implementatietools zijn gebaseerd op meerdere YAML-bestanden. Hieronder ziet u een voorbeeld van hoe we een service en de schaaltopologie ervan (aantal replica's) in een cluster declareren.

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

Dienstdefinitie

Dit is een overzicht van alle stappen die onze implementatieworkflow definiëren. Bij de laatste stap wordt de toepassing tegelijkertijd in meerdere werkclusters geïmplementeerd.


Jenkins-implementatiestappen

Hoe zit het met geheimen?

Wat de veiligheid betreft, volgen we alle geheimen van verschillende plaatsen en slaan ze op in een unieke kluis Gewelf in Parijs.

Onze implementatietools extraheren geheime waarden uit Vault en voegen deze, wanneer de implementatietijd aanbreekt, in Helm in.

Om dit te doen, hebben we een mapping gedefinieerd tussen de geheimen in Vault en de geheimen 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 gedefinieerd die moeten worden gevolgd bij het vastleggen van geheimen in Vault.
  • Als het geheim van toepassing is naar een specifieke context of cluster, moet u een specifiek item toevoegen. (Hier heeft de contextcluster1 zijn eigen waarde voor het geheime stack-app1-wachtwoord).
  • Anders wordt de waarde gebruikt standaard.
  • Voor elk item in deze lijst in Kubernetes-geheim er wordt een sleutelwaardepaar ingevoegd. Daarom is het geheime sjabloon in onze grafieken heel 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: Opaque

Problemen en beperkingen

Werken met meerdere opslagplaatsen

Nu scheiden we de ontwikkeling van grafieken en applicaties. Dit betekent dat ontwikkelaars in twee git-repository's moeten werken: één voor de applicatie en één voor het definiëren van de implementatie ervan in Kubernetes. 2 git-repository's betekenen 2 workflows, en het is gemakkelijk voor een newbie om in de war te raken.

Het beheren van gegeneraliseerde diagrammen is een gedoe

Zoals we al zeiden, zijn generieke grafieken erg handig voor het identificeren van afhankelijkheden en het snel implementeren van meerdere applicaties. Maar wij gebruiken --reuse-valuesom te voorkomen dat alle waarden worden doorgegeven telkens wanneer we een applicatie implementeren die deel uitmaakt van dit algemene diagram.

In een continue leveringsworkflow hebben we slechts twee waarden die regelmatig veranderen: het aantal replica’s en de afbeeldingstag (versie). Andere, stabielere waarden worden handmatig gewijzigd, en dit is behoorlijk moeilijk. Bovendien kan één fout bij het inzetten van een algemene grafiek tot ernstige mislukkingen leiden, zoals we uit eigen ervaring hebben gezien.

Meerdere configuratiebestanden bijwerken

Wanneer een ontwikkelaar een nieuwe applicatie toevoegt, moet hij verschillende bestanden wijzigen: de applicatiedeclaratie, de lijst met geheimen, het toevoegen van de applicatie als afhankelijkheid als deze is opgenomen in het algemene diagram.

Jenkins-machtigingen zijn te uitgebreid in Vault

Nu hebben we er een AppRol, die alle geheimen uit de kluis leest.

Het terugdraaiproces is niet geautomatiseerd

Om terug te draaien, moet u de opdracht op verschillende clusters uitvoeren, en dit zit vol met fouten. We voeren deze bewerking handmatig uit om ervoor te zorgen dat de juiste versie-ID wordt opgegeven.

We gaan richting GitOps

Ons doel

We willen het diagram terugsturen naar de repository van de applicatie die het implementeert.

De workflow zal hetzelfde zijn als voor ontwikkeling. Wanneer een branch bijvoorbeeld naar master wordt gepusht, wordt de implementatie automatisch geactiveerd. Het belangrijkste verschil tussen deze aanpak en de huidige workflow zou hierin liggen alles wordt beheerd in git (de applicatie zelf en de manier waarop deze in Kubernetes wordt ingezet).

Er zijn verschillende voordelen:

  • Veel duidelijker voor de ontwikkelaar. Het is gemakkelijker om te leren hoe u wijzigingen in een lokaal diagram kunt toepassen.
  • De service-implementatiedefinitie kan worden opgegeven dezelfde plaats als de code onderhoud.
  • Beheer van de verwijdering van algemene diagrammen. De service krijgt een eigen Helm-release. Hierdoor kunt u de levenscyclus van applicaties (rollback, upgrade) op het kleinste niveau beheren, om andere services niet te beïnvloeden.
  • Voordelen van git voor diagrambeheer: wijzigingen ongedaan maken, auditlogboek, enz. Als u een wijziging aan een diagram ongedaan wilt maken, kunt u dit doen met git. De implementatie start automatisch.
  • U kunt overwegen uw ontwikkelingsworkflow te verbeteren met tools zoals schavot, waarmee ontwikkelaars veranderingen kunnen testen in een context die dicht bij de productie ligt.

Migratie in twee stappen

Onze ontwikkelaars gebruiken deze workflow nu al twee jaar, dus we willen dat de migratie zo pijnloos mogelijk verloopt. Daarom hebben we besloten een tussenstap toe te voegen op weg naar het doel.
De eerste fase is eenvoudig:

  • We behouden een vergelijkbare structuur voor het opzetten van de applicatie-implementatie, maar dan in één enkel 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 toepassing (zonder algemene grafieken).
  • Grafieken in de Git-repository van de toepassing.

We hebben met alle ontwikkelaars gesproken, dus het migratieproces is al begonnen. De eerste fase wordt nog steeds aangestuurd via het CI-platform. Ik zal binnenkort nog een bericht schrijven over fase twee: hoe we zijn overgestapt naar een GitOps-workflow met Stroom. Ik zal je vertellen hoe we alles hebben opgezet en welke moeilijkheden we tegenkwamen (meerdere opslagplaatsen, geheimen, enz.). Volg het nieuws.

Hier hebben we geprobeerd onze voortgang in de applicatie-implementatieworkflow van de afgelopen jaren te beschrijven, wat leidde tot gedachten over de GitOps-aanpak. We hebben het doel nog niet bereikt en zullen over de resultaten rapporteren, maar nu zijn we ervan overtuigd dat we het juiste hebben gedaan toen we besloten alles te vereenvoudigen en dichter bij de gewoonten van ontwikkelaars te brengen.

Bron: www.habr.com

Voeg een reactie