Ontplooi toepassings na veelvuldige Kubernetes-klusters met Helm

Hoe Dailymotion Kubernetes gebruik: Toepassingsimplementering

Ons by Dailymotion het 3 jaar gelede Kubernetes in produksie begin gebruik. Maar om toepassings oor verskeie groepe te ontplooi, is pret, so die afgelope paar jaar het ons probeer om ons gereedskap en werkvloei te verbeter.

Waar het dit begin

Hier sal ons dek hoe ons ons toepassings oor verskeie Kubernetes-klusters regoor die wêreld ontplooi.

Om veelvuldige Kubernetes-voorwerpe gelyktydig te ontplooi, gebruik ons Helm, en al ons kaarte word in een git-bewaarplek gestoor. Om 'n volledige toepassingstapel van verskeie dienste te ontplooi, gebruik ons ​​die sogenaamde opsommingskaart. In wese is dit 'n grafiek wat afhanklikhede verklaar en u toelaat om die API en sy dienste met een opdrag te inisialiseer.

Ons het ook 'n klein Python-skrif bo-op Helm geskryf om kontrole te doen, kaarte te skep, geheime by te voeg en toepassings te ontplooi. Al hierdie take word uitgevoer op 'n sentrale CI-platform met behulp van 'n docker-beeld.

Kom ons kom by die punt.

Let wel. Soos jy dit lees, is die eerste vrystellingskandidaat vir Helm 3 reeds aangekondig. Die hoofweergawe bevat 'n hele reeks verbeterings om sommige van die probleme wat ons in die verlede teëgekom het aan te spreek.

Grafiekontwikkelingswerkvloei

Ons gebruik vertakking vir toepassings, en ons het besluit om dieselfde benadering op kaarte toe te pas.

  • Tak dev gebruik om kaarte te skep wat op ontwikkelingsklusters getoets sal word.
  • Wanneer 'n trekversoek ingedien word by meester, word hulle in opvoering nagegaan.
  • Laastens skep ons 'n trekversoek om die veranderinge aan die tak te verbind prod en pas dit in produksie toe.

Elke omgewing het sy eie private bewaarplek wat ons kaarte stoor, en ons gebruik Kaartmuseum met baie nuttige API's. Op hierdie manier verseker ons streng isolasie tussen omgewings en werklike toetsing van kaarte voordat dit in produksie gebruik word.

Grafiekbewaarplekke in verskillende omgewings

Dit is opmerklik dat wanneer ontwikkelaars 'n dev-tak stoot, 'n weergawe van hul grafiek outomaties na die dev Chartmuseum gestoot word. Dus, alle ontwikkelaars gebruik dieselfde dev-bewaarplek, en jy moet jou weergawe van die grafiek noukeurig spesifiseer om nie per ongeluk iemand anders se veranderinge te gebruik nie.

Boonop valideer ons klein Python-skrif Kubernetes-voorwerpe teen die Kubernetes OpenAPI-spesifikasies deur Kubeval, voordat dit op Chartmusem gepubliseer word.

Algemene beskrywing van die grafiekontwikkelingswerkvloei

  1. Opstel van pyplyntake volgens spesifikasie gazr.io vir kwaliteitbeheer (pluis, eenheidstoets).
  2. Druk 'n docker-beeld met Python-nutsgoed wat ons toepassings ontplooi.
  3. Die opstel van die omgewing volgens taknaam.
  4. Valideer Kubernetes yaml-lêers met Kubeval.
  5. Vermeerder outomaties die weergawe van 'n grafiek en sy ouerkaarte (kaarte wat afhang van die grafiek wat verander word).
  6. Die indiening van 'n kaart aan 'n Kaartmuseum wat by sy omgewing pas

Bestuur verskille oor groeperings heen

Federasie van Klusters

Daar was 'n tyd toe ons gebruik het federasie van Kubernetes-klusters, waar Kubernetes-objekte vanaf 'n enkele API-eindpunt verklaar kan word. Maar probleme het ontstaan. Sommige Kubernetes-objekte kon byvoorbeeld nie in die federasie-eindpunt geskep word nie, wat dit moeilik maak om gefedereerde voorwerpe en ander voorwerpe vir individuele trosse te onderhou.

Om die probleem op te los, het ons begin om die groepe onafhanklik te bestuur, wat die proses baie vereenvoudig het (ons het die eerste weergawe van federasie gebruik; iets kon dalk in die tweede verander het).

Geo-verspreide platform

Ons platform is tans oor 6 streke versprei - 3 plaaslik en 3 in die wolk.


Verspreide ontplooiing

Globale Helm-waardes

4 globale Helm-waardes laat jou toe om verskille tussen trosse te identifiseer. Al ons kaarte het standaard minimum waardes.

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

Globale waardes

Hierdie waardes help om die konteks vir ons toepassings te definieer en word vir verskeie doeleindes gebruik: monitering, opsporing, aanteken, eksterne oproepe maak, skaal, ens.

  • "wolk": Ons het 'n hibriede Kubernetes-platform. Ons API word byvoorbeeld in GCP-sones en in ons datasentrums ontplooi.
  • "env": Sommige waardes kan verander vir nie-produksie-omgewings. Byvoorbeeld, hulpbrondefinisies en outoskaalkonfigurasies.
  • "streek": Hierdie inligting help om die ligging van die groepering te bepaal en kan gebruik word om nabygeleë eindpunte vir eksterne dienste te bepaal.
  • "clusterName": as en wanneer ons 'n waarde vir 'n individuele cluster wil definieer.

Hier is 'n spesifieke 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 -}}

Roer sjabloon voorbeeld

Hierdie logika word gedefinieer in 'n helpersjabloon om te verhoed dat Kubernetes YAML deurmekaar raak.

Aansoek Aankondiging

Ons ontplooiingsinstrumente is gebaseer op veelvuldige YAML-lêers. Hieronder is 'n voorbeeld van hoe ons 'n diens en sy skaaltopologie (aantal replikas) in 'n groep verklaar.

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

Diensdefinisie

Dit is 'n uiteensetting van al die stappe wat ons implementeringswerkvloei definieer. Die laaste stap ontplooi die toepassing gelyktydig na verskeie werkersklusters.


Jenkins-ontplooiingstappe

Wat van geheime?

Wat sekuriteit betref, spoor ons alle geheime van verskillende plekke af en stoor dit in 'n unieke kluis kluis in Parys.

Ons ontplooiingsnutsgoed onttrek geheime waardes uit Vault en, wanneer ontplooiingstyd aanbreek, plaas dit in Helm.

Om dit te doen, het ons 'n kartering gedefinieer tussen die geheime in Vault en die geheime wat ons toepassings benodig:

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"

  • Ons het algemene reëls gedefinieer om te volg wanneer geheime in Vault opgeneem word.
  • As die geheim van toepassing is na 'n spesifieke konteks of groepering, moet jy 'n spesifieke inskrywing byvoeg. (Hier het die konteksgroep1 sy eie waarde vir die geheime stapel-app1-wagwoord).
  • Andersins word die waarde gebruik by verstek.
  • Vir elke item in hierdie lys in Kubernetes geheim 'n sleutel-waarde-paar word ingevoeg. Daarom is die geheime sjabloon in ons kaarte baie 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

Probleme en beperkings

Werk met veelvuldige bewaarplekke

Nou skei ons die ontwikkeling van kaarte en toepassings. Dit beteken dat ontwikkelaars in twee git-bewaarplekke moet werk: een vir die toepassing en een om die implementering daarvan na Kubernetes te definieer. 2 git-bewaarplekke beteken 2 werkstrome, en dit is maklik vir 'n nuweling om deurmekaar te raak.

Die bestuur van algemene kaarte is 'n gesukkel

Soos ons reeds gesê het, is generiese kaarte baie nuttig om afhanklikhede te identifiseer en om verskeie toepassings vinnig te ontplooi. Maar ons gebruik --reuse-valuesom te verhoed dat al die waardes deurgegee word elke keer as ons 'n toepassing ontplooi wat deel is van hierdie algemene grafiek.

In 'n deurlopende afleweringswerkvloei het ons net twee waardes wat gereeld verander: die aantal replikas en die beeldmerker (weergawe). Ander, meer stabiele waardes word met die hand verander, en dit is nogal moeilik. Boonop kan een fout met die implementering van 'n algemene grafiek lei tot ernstige mislukkings, soos ons uit ons eie ervaring gesien het.

Opdatering van veelvuldige konfigurasielêers

Wanneer 'n ontwikkelaar 'n nuwe toepassing byvoeg, moet hy verskeie lêers verander: die toepassingsverklaring, die lys van geheime, die byvoeging van die toepassing as 'n afhanklikheid as dit in die algemene grafiek ingesluit is.

Jenkins-toestemmings is te uitgebrei in Vault

Nou het ons een AppRole, wat al die geheime van die kluis lees.

Die terugrolproses is nie outomaties nie

Om terug te keer, moet jy die opdrag op verskeie groepe uitvoer, en dit is belaai met foute. Ons voer hierdie bewerking met die hand uit om te verseker dat die korrekte weergawe-ID gespesifiseer is.

Ons beweeg na GitOps

Ons mikpunt

Ons wil die grafiek terugstuur na die bewaarplek van die toepassing wat dit ontplooi.

Die werkvloei sal dieselfde wees as vir ontwikkeling. Byvoorbeeld, wanneer 'n tak gedruk word om te bemeester, sal die ontplooiing outomaties geaktiveer word. Die belangrikste verskil tussen hierdie benadering en die huidige werkvloei sou wees dat alles sal in git bestuur word (die toepassing self en die manier waarop dit in Kubernetes ontplooi word).

Daar is verskeie voordele:

  • Veel duideliker vir die ontwikkelaar. Dit is makliker om te leer hoe om veranderinge in 'n plaaslike grafiek toe te pas.
  • Die diensontplooiingsdefinisie kan gespesifiseer word dieselfde plek as die kode diens.
  • Bestuur van die verwydering van algemene kaarte. Die diens sal sy eie Helm-vrystelling hê. Dit sal jou toelaat om die toepassing lewensiklus (terugrol, opgradering) op die kleinste vlak te bestuur, om nie ander dienste te beïnvloed nie.
  • Voordele van git vir grafiekbestuur: ongedaan maak veranderinge, oudit log, ens. As jy 'n verandering aan 'n grafiek moet ongedaan maak, kan jy dit doen met behulp van git. Die ontplooiing begin outomaties.
  • U kan dit oorweeg om u ontwikkelingswerkvloei te verbeter met gereedskap soos Skaffold, waarmee ontwikkelaars veranderinge in 'n konteks na aan produksie kan toets.

Twee-stap migrasie

Ons ontwikkelaars gebruik hierdie werkstroom nou al vir 2 jaar, so ons wil hê dat die migrasie so pynloos as moontlik moet wees. Daarom het ons besluit om 'n tussenstap by te voeg op pad na die doelwit.
Die eerste fase is eenvoudig:

  • Ons hou 'n soortgelyke struktuur vir die opstel van toepassing-ontplooiing, maar in 'n enkele voorwerp 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 vrystelling per aansoek (sonder algemene kaarte).
  • Grafieke in die toepassing se git-bewaarplek.

Ons het met al die ontwikkelaars gepraat, so die migrasieproses het reeds begin. Die eerste fase word steeds met die CI-platform beheer. Ek sal binnekort nog 'n plasing skryf oor fase twee: hoe ons oorgegaan het na 'n GitOps-werkvloei met Flux. Ek sal jou vertel hoe ons alles opgestel het en watter probleme ons teëgekom het (veelvuldige bewaarplekke, geheime, ens.). Volg die nuus.

Hier het ons probeer om ons vordering in die toepassing-ontplooiingswerkvloei oor die afgelope jare te beskryf, wat tot gedagtes oor die GitOps-benadering gelei het. Ons het nog nie die doel bereik nie en sal oor die resultate verslag doen, maar nou is ons oortuig dat ons die regte ding gedoen het toe ons besluit het om alles te vereenvoudig en dit nader aan die gewoontes van ontwikkelaars te bring.

Bron: will.com

Voeg 'n opmerking