Organizi deplojon al pluraj k8s-medioj uzante helmfile

Helmfile - envolvaĵo por helmo, kiu ebligas al vi priskribi multajn helm-eldonojn en unu loko, parametrigi iliajn leterojn por pluraj medioj, kaj ankaŭ agordi la ordon de ilia deplojo.

Vi povas legi pri helmfile mem kaj ekzemploj de ĝia uzo en README и gvidilo pri plej bonaj praktikoj.

Ni konatiĝos kun neevidentaj manieroj priskribi eldonojn en helmfile

Ni diru, ke ni havas pakon da helm-diagramoj (ekzemple, ni diru postgres kaj iu backend aplikaĵo) kaj plurajn mediojn (pluraj kubernetes aretoj, pluraj nomspacoj, aŭ pluraj el ambaŭ). Ni prenas la helmdosieron, legas la dokumentaron kaj komencas priskribi niajn mediojn kaj eldonojn:

    .
    ├── envs
    │   ├── devel
    │   │   └── values
    │   │       ├── backend.yaml
    │   │       └── postgres.yaml
    │   └── production
    │       └── values
    │           ├── backend.yaml
    │           └── postgres.yaml
    └── helmfile.yaml

helmfile.yaml

environments:
  devel:
  production:

releases:
  - name: postgres
    labels:
      app: postgres
    wait: true
    chart: stable/postgresql
    version: 8.4.0
    values:
      - envs/{{ .Environment.Name }}/values/postgres.yaml
  - name: backend
    labels:
      app: backend
    wait: true
    chart: private-helm-repo/backend
    version: 1.0.5
    needs:
      - postgres
    values:
      - envs/{{ .Environment.Name }}/values/backend.yaml

Ni finis kun 2 medioj: disvolvi, produktado - ĉiu enhavas siajn proprajn valorojn por la eldontabloj de stirilo. Ni deplojos al ili tiel:

helmfile -n <namespace> -e <env> apply

Malsamaj versioj de stirilaj leteroj en malsamaj medioj

Kio se ni bezonas elŝuti malsamajn versiojn de la backend al malsamaj medioj? Kiel parametrigi la eldonan version? La mediaj valoroj disponeblaj tra {{ .Values }}

helmfile.yaml

environments:
  devel:
+   values:
+   - charts:
+       versions:
+         backend: 1.1.0
  production:
+   values:
+   - charts:
+       versions:
+         backend: 1.0.5
...
  - name: backend
    labels:
      app: backend
    wait: true
    chart: private-helm-repo/backend
-   version: 1.0.5
+   version: {{ .Values.charts.versions.backend }}
...

Malsama aro de aplikoj en malsamaj medioj

Bonege, sed kio se ni ne bezonas production elŝuti postgres, ĉar ni scias, ke ni ne bezonas puŝi la datumbazon en k8s kaj vendi ni havas mirindan apartan postgres-grupon? Por solvi ĉi tiun problemon ni havas etikedojn

helmfile -n <namespace> -e devel apply
helmfile -n <namespace> -e production -l app=backend apply

Ĉi tio estas bonega, sed persone mi preferas priskribi kiujn aplikaĵojn disfaldi en la medio ne uzante lanĉajn argumentojn, sed en la priskribo de la medioj mem. Kion fari? Vi povas meti la eldonpriskribojn en apartan dosierujon, krei liston de la necesaj eldonoj en la mediopriskribo kaj "repreni" nur la necesajn eldonojn, ignorante la ceterajn.

    .
    ├── envs
    │   ├── devel
    │   │   └── values
    │   │       ├── backend.yaml
    │   │       └── postgres.yaml
    │   └── production
    │       └── values
    │           ├── backend.yaml
    │           └── postgres.yaml
+   ├── releases
+   │   ├── backend.yaml
+   │   └── postgres.yaml
    └── helmfile.yaml

helmfile.yaml


  environments:
    devel:
      values:
      - charts:
          versions:
            backend: 1.1.0
      - apps:
        - postgres
        - backend

    production:
      values:
      - charts:
          versions:
            backend: 1.0.5
      - apps:
        - backend

- releases:
-    - name: postgres
-      labels:
-        app: postgres
-      wait: true
-      chart: stable/postgresql
-      version: 8.4.0
-      values:
-        - envs/{{ .Environment.Name }}/values/postgres.yaml
-    - name: backend
-      labels:
-        app: backend
-      wait: true
-      chart: private-helm-repo/backend
-     version: {{ .Values.charts.versions.backend }}
-     needs:
-       - postgres
-     values:
-       - envs/{{ .Environment.Name }}/values/backend.yaml
+ ---
+ bases:
+ {{- range .Values.apps }}
+   - releases/{{ . }}.yaml
+ {{- end }}

releases/postgres.yaml

releases:
  - name: postgres
    labels:
      app: postgres
    wait: true
    chart: stable/postgresql
    version: 8.4.0
    values:
      - envs/{{ .Environment.Name }}/values/postgres.yaml

releases/backend.yaml

releases:
  - name: backend
    labels:
      app: backend
    wait: true
    chart: private-helm-repo/backend
    version: {{ .Values.charts.versions.backend }}
    needs:
      - postgres
    values:
      - envs/{{ .Environment.Name }}/values/backend.yaml

La noto

Kiam vi uzas bases: necesas uzi yaml apartigilon ---, por ke vi povu ŝabloni eldonojn (kaj aliajn partojn, kiel helmDefaults) kun valoroj de medioj

En ĉi tiu kazo, la postgres-eldono eĉ ne estos inkluzivita en la priskribo por produktado. Tre komforte!

Superregeblaj tutmondaj valoroj por eldonoj

Kompreneble, estas bonege, ke vi povas agordi valorojn por stirilaj leteroj por ĉiu medio, sed kio se ni havas plurajn mediojn priskribitajn, kaj ni volas, ekzemple, agordi la saman por ĉiuj. affinity, sed ni ne volas agordi ĝin defaŭlte en la leteroj mem, kiuj estas konservitaj en napoj.

En ĉi tiu kazo, por ĉiu eldono ni povus specifi 2 dosierojn kun valoroj: la unua kun defaŭltaj valoroj, kiu determinos la valorojn de la diagramo mem, kaj la dua kun valoroj por la medio, kiu siavice superregos la valorojn. defaŭltaj.

    .
    ├── envs
+   │   ├── default
+   │   │   └── values
+   │   │       ├── backend.yaml
+   │   │       └── postgres.yaml
    │   ├── devel
    │   │   └── values
    │   │       ├── backend.yaml
    │   │       └── postgres.yaml
    │   └── production
    │       └── values
    │           ├── backend.yaml
    │           └── postgres.yaml
    ├── releases
    │   ├── backend.yaml
    │   └── postgres.yaml
    └── helmfile.yaml

releases/backend.yaml

releases:
  - name: backend
    labels:
      app: backend
    wait: true
    chart: private-helm-repo/backend
    version: {{ .Values.charts.versions.backend }}
    needs:
      - postgres
    values:
+     - envs/default/values/backend.yaml
      - envs/{{ .Environment.Name }}/values/backend.yaml

envs/default/values/backend.yaml

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 1
      podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: app.kubernetes.io/name
            operator: In
            values:
            - backend
        topologyKey: "kubernetes.io/hostname"

Difinante tutmondajn valorojn por stirilaj leteroj de ĉiuj eldonoj sur la media nivelo

Ni diru, ke ni kreas plurajn enirojn en pluraj eldonoj - ni povus permane difini por ĉiu diagramo hosts:, sed en nia kazo la domajno estas la sama, do kial ne meti ĝin en iun tutmondan variablon kaj simple anstataŭigi ĝian valoron en la leterojn? Por fari tion, tiuj dosieroj kun valoroj, kiujn ni volas parametrigi, devos havi la etendon .gotmpl, por ke helmfile sciu ke ĝi devas esti rulita tra la ŝablona motoro.

    .
    ├── envs
    │   ├── default
    │   │   └── values
-   │   │       ├── backend.yaml
-   │   │       ├── postgres.yaml
+   │   │       ├── backend.yaml.gotmpl
+   │   │       └── postgres.yaml.gotmpl
    │   ├── devel
    │   │   └── values
    │   │       ├── backend.yaml
    │   │       └── postgres.yaml
    │   └── production
    │       └── values
    │           ├── backend.yaml
    │           └── postgres.yaml
    ├── releases
    │   ├── backend.yaml
    │   └── postgres.yaml
    └── helmfile.yaml

helmfile.yaml

  environments:
    devel:
      values:
      - charts:
          versions:
            backend: 1.1.0
      - apps:
        - postgres
        - backend
+     - global:
+         ingressDomain: k8s.devel.domain

    production:
      values:
      - charts:
          versions:
            backend: 1.0.5
      - apps:
        - backend
+     - global:
+         ingressDomain: production.domain
  ---
  bases:
  {{- range .Values.apps }}
    - releases/{{ . }}.yaml
  {{- end }}

envs/default/values/backend.yaml.gotmpl

ingress:
  enabled: true
  paths:
    - /api
  hosts:
    - {{ .Values.global.ingressDomain }}

envs/default/values/postgres.yaml.gotmpl

ingress:
  enabled: true
  paths:
    - /
  hosts:
    - postgres.{{ .Values.global.ingressDomain }}

La noto

Evidente, eniro en la postgresa diagramo estas io ege dubinda, do ĉi tiu artikolo estas donita simple kiel sfera ekzemplo en vakuo kaj por ne enkonduki iun novan eldonon en la artikolon nur por priskribi eniron.

Anstataŭigante sekretojn de mediaj valoroj

Analogie kun la supra ekzemplo, vi povas anstataŭigi ĉifritajn uzante helmaj sekretoj signifoj. Anstataŭ krei nian propran sekretan dosieron por ĉiu eldono, en kiu ni povas difini ĉifritajn valorojn por la diagramo, ni povas simple difini en la eldono default.yaml.gotmpl la valorojn kiuj estos prenitaj el la variabloj difinitaj ĉe la media nivelo. Kaj la valoroj, kiujn ni ne bezonas kaŝi de iu ajn, povas esti facile redifinitaj en la eldonvaloroj en specifa medio.

    .
    ├── envs
    │   ├── default
    │   │   └── values
    │   │       ├── backend.yaml
    │   │       └── postgres.yaml
    │   ├── devel
    │   │   ├── values
    │   │   │   ├── backend.yaml
    │   │   │   └── postgres.yaml
+   │   │   └── secrets.yaml
    │   └── production
    │       ├── values
    │       │   ├── backend.yaml
    │       │   └── postgres.yaml
+   │       └── secrets.yaml
    ├── releases
    │   ├── backend.yaml
    │   └── postgres.yaml
    └── helmfile.yaml

helmfile.yaml

  environments:
    devel:
      values:
      - charts:
          versions:
            backend: 1.1.0
      - apps:
        - postgres
        - backend
      - global:
          ingressDomain: k8s.devel.domain
+     secrets:
+       - envs/devel/secrets.yaml

    production:
      values:
      - charts:
          versions:
            backend: 1.0.5
      - apps:
        - backend
      - global:
          ingressDomain: production.domain
+     secrets:
+       - envs/production/secrets.yaml
  ---
  bases:
  {{- range .Values.apps }}
    - releases/{{ . }}.yaml
  {{- end }}

envs/devel/secrets.yaml

secrets:
    elastic:
        password: ENC[AES256_GCM,data:hjCB,iv:Z1P6/6xBJgJoKLJ0UUVfqZ80o4L84jvZfM+uH9gBelc=,tag:dGqQlCZnLdRAGoJSj63rBQ==,type:int]
...

envs/production/secrets.yaml

secrets:
    elastic:
        password: ENC[AES256_GCM,data:ZB/VpTFk8f0=,iv:EA//oT1Cb5wNFigTDOz3nA80qD9UwTjK5cpUwLnEXjs=,tag:hMdIUaqLRA8zuFBd82bz6A==,type:str]
...

envs/default/values/backend.yaml.gotmpl

elasticsearch:
  host: elasticsearch
  port: 9200
  password: {{ .Values | getOrNil "secrets.elastic.password" | default "password" }}

envs/devel/values/backend.yaml

elasticsearch:
  host: elastic-0.devel.domain

envs/production/values/backend.yaml

elasticsearch:
  host: elastic-0.production.domain

La noto

Por iu, getOrNil - speciala funkcio por go-ŝablonoj en helmfile, kiu, eĉ se .Values.secrets ne ekzistos, ne ĵetos eraron, sed permesos la rezulton uzante la funkcion default anstataŭa defaŭlta valoro

konkludo

La priskribitaj aferoj ŝajnas sufiĉe evidentaj, sed informoj pri oportuna priskribo de deplojo al pluraj medioj uzantaj helmfile estas tre malabundaj, kaj mi amas IaC (Infrastructure-as-Code) kaj volas havi klaran priskribon de la deploja stato.

Konklude, mi ŝatus aldoni, ke la variabloj por la defaŭlta medio povas, siavice, esti parametrizitaj kun la mediaj variabloj de la OS de certa kuristo de kiu la deplojo estos lanĉita, kaj tiel akiri dinamikajn mediojn.

helmfile.yaml

environments:
  default:
    values:
    - global:
        clusterDomain: {{ env "CLUSTER_DOMAIN" | default "cluster.local" }}
        ingressDomain: {{ env "INGRESS_DOMAIN" }}

fonto: www.habr.com

Aldoni komenton