Οργάνωση ανάπτυξης σε πολλαπλά περιβάλλοντα k8s χρησιμοποιώντας helmfile

Αρχειοθήκη - περιτύλιγμα για τιμόνι, που σας επιτρέπει να περιγράφετε πολλές εκδόσεις πηδαλίου σε ένα μέρος, να παραμετροποιείτε τα γραφήματα τους για πολλά περιβάλλοντα και επίσης να ορίζετε τη σειρά ανάπτυξής τους.

Μπορείτε να διαβάσετε για το ίδιο το helmfile και παραδείγματα χρήσης του στο readme и οδηγός βέλτιστων πρακτικών.

Θα εξοικειωθούμε με μη προφανείς τρόπους περιγραφής των κυκλοφοριών στο helmfile

Ας υποθέσουμε ότι έχουμε ένα πακέτο γραφημάτων πηδαλίου (για παράδειγμα, ας πούμε postgres και κάποια εφαρμογή backend) και πολλά περιβάλλοντα (αρκετά συμπλέγματα kubernetes, αρκετοί χώροι ονομάτων ή πολλά από τα δύο). Παίρνουμε το κράνος, διαβάζουμε την τεκμηρίωση και αρχίζουμε να περιγράφουμε τα περιβάλλοντα και τις εκδόσεις μας:

    .
    ├── 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

Καταλήξαμε σε 2 περιβάλλοντα: αναπτύσσω, παραγωγή — το καθένα περιέχει τις δικές του τιμές για τα διαγράμματα απελευθέρωσης τιμονιού. Θα τους αναπτύξουμε ως εξής:

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

Διαφορετικές εκδόσεις διαγραμμάτων τιμονιού σε διαφορετικά περιβάλλοντα

Τι γίνεται αν χρειαστεί να διαθέσουμε διαφορετικές εκδόσεις του backend σε διαφορετικά περιβάλλοντα; Πώς να παραμετροποιήσετε την έκδοση έκδοσης; Οι περιβαλλοντικές αξίες που είναι διαθέσιμες μέσω {{ .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 }}
...

Διαφορετικό σύνολο εφαρμογών σε διαφορετικά περιβάλλοντα

Ωραία, αλλά τι γίνεται αν δεν χρειάζεται production αναπτύξτε τα postgres, επειδή γνωρίζουμε ότι δεν χρειάζεται να ωθήσουμε τη βάση δεδομένων σε k8 και προς πώληση έχουμε ένα υπέροχο ξεχωριστό σύμπλεγμα postgres; Για να λύσουμε αυτό το πρόβλημα έχουμε ετικέτες

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

Αυτό είναι υπέροχο, αλλά προσωπικά προτιμώ να περιγράφω ποιες εφαρμογές θα αναπτύξω στο περιβάλλον όχι χρησιμοποιώντας ορίσματα εκκίνησης, αλλά στην περιγραφή των ίδιων των περιβαλλόντων. Τι να κάνω? Μπορείτε να τοποθετήσετε τις περιγραφές εκδόσεων σε ξεχωριστό φάκελο, να δημιουργήσετε μια λίστα με τις απαραίτητες εκδόσεις στην περιγραφή περιβάλλοντος και να «σηκώσετε» μόνο τις απαραίτητες εκδόσεις, αγνοώντας τις υπόλοιπες

    .
    ├── 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

Το σημείωμα

Όταν χρησιμοποιείτε το bases: είναι απαραίτητο να χρησιμοποιήσετε διαχωριστικό yaml ---, ώστε να μπορείτε να κάνετε πρότυπα εκδόσεων (και άλλα μέρη, όπως helmDefaults) με τιμές από περιβάλλοντα

Σε αυτήν την περίπτωση, η έκδοση postgres δεν θα περιλαμβάνεται καν στην περιγραφή για παραγωγή. Πολύ άνετα!

Ανεκτίμητες παγκόσμιες αξίες για εκδόσεις

Φυσικά, είναι υπέροχο που μπορείτε να ορίσετε τιμές για χάρτες πηδαλίου για κάθε περιβάλλον, αλλά τι γίνεται αν έχουμε πολλά περιβάλλοντα που περιγράφονται και θέλουμε, για παράδειγμα, να ορίσουμε το ίδιο για όλα affinity, αλλά δεν θέλουμε να το διαμορφώσουμε από προεπιλογή στα ίδια τα γραφήματα, τα οποία είναι αποθηκευμένα σε γογγύλια.

Σε αυτήν την περίπτωση, για κάθε έκδοση θα μπορούσαμε να καθορίσουμε 2 αρχεία με τιμές: το πρώτο με προεπιλεγμένες τιμές, που θα καθορίσουν τις τιμές του ίδιου του γραφήματος και το δεύτερο με τιμές για το περιβάλλον, το οποίο με τη σειρά του θα αντικαταστήσει το προεπιλεγμένα.

    .
    ├── 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"

Καθορισμός παγκόσμιων τιμών για πίνακες χειρισμού όλων των εκδόσεων σε επίπεδο περιβάλλοντος

Ας υποθέσουμε ότι δημιουργούμε πολλές εισόδους σε πολλές εκδόσεις - θα μπορούσαμε να ορίσουμε χειροκίνητα για κάθε γράφημα hosts:, αλλά στην περίπτωσή μας ο τομέας είναι ο ίδιος, οπότε γιατί να μην τον τοποθετήσετε σε κάποια καθολική μεταβλητή και απλώς να αντικαταστήσετε την τιμή του στα γραφήματα; Για να γίνει αυτό, αυτά τα αρχεία με τιμές που θέλουμε να παραμετροποιήσουμε θα πρέπει να έχουν την επέκταση .gotmpl, ώστε το αρχείο κεφαλής να γνωρίζει ότι πρέπει να εκτελεστεί μέσω του κινητήρα προτύπου.

    .
    ├── 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 }}

Το σημείωμα

Προφανώς, η είσοδος στο γράφημα postgres είναι κάτι εξαιρετικά αμφίβολο, επομένως αυτό το άρθρο δίνεται απλώς ως σφαιρικό παράδειγμα στο κενό και για να μην εισαχθεί κάποια νέα κυκλοφορία στο άρθρο μόνο και μόνο για λόγους περιγραφής της εισόδου

Αντικατάσταση μυστικών από περιβαλλοντικές αξίες

Κατ' αναλογία με το παραπάνω παράδειγμα, μπορείτε να αντικαταστήσετε κρυπτογραφημένα χρησιμοποιώντας μυστικά του τιμονιού νοήματα. Αντί να δημιουργήσουμε το δικό μας αρχείο μυστικών για κάθε έκδοση, στο οποίο μπορούμε να ορίσουμε κρυπτογραφημένες τιμές για το γράφημα, μπορούμε απλώς να ορίσουμε στην έκδοση default.yaml.gotmpl τις τιμές που θα ληφθούν από τις μεταβλητές που ορίζονται στο επίπεδο περιβάλλοντος. Και οι τιμές που δεν χρειάζεται να κρύψουμε από κανέναν μπορούν εύκολα να επαναπροσδιοριστούν στις τιμές έκδοσης σε ένα συγκεκριμένο περιβάλλον.

    .
    ├── 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

Το σημείωμα

παρεμπιπτόντως, getOrNil - μια ειδική λειτουργία για go templates στο helmfile, η οποία, ακόμα κι αν .Values.secrets δεν θα υπάρχει, δεν θα εκπέμψει σφάλμα, αλλά θα επιτρέψει το αποτέλεσμα χρησιμοποιώντας τη συνάρτηση default υποκατάστατη προεπιλεγμένη τιμή

Συμπέρασμα

Τα πράγματα που περιγράφονται φαίνονται αρκετά προφανή, αλλά οι πληροφορίες σχετικά με μια βολική περιγραφή της ανάπτυξης σε διάφορα περιβάλλοντα με χρήση του helmfile είναι πολύ σπάνιες και μου αρέσει το IaC (Infrastructure-as-Code) και θέλω να έχω μια σαφή περιγραφή της κατάστασης ανάπτυξης.

Εν κατακλείδι, θα ήθελα να προσθέσω ότι οι μεταβλητές για το προεπιλεγμένο περιβάλλον μπορούν, με τη σειρά τους, να παραμετροποιηθούν με τις μεταβλητές περιβάλλοντος του λειτουργικού συστήματος ενός συγκεκριμένου δρομέα από τον οποίο θα εκκινηθεί η ανάπτυξη, και έτσι να ληφθούν δυναμικά περιβάλλοντα

helmfile.yaml

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

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο