تنظيم النشر إلى بيئات k8s متعددة باستخدام helmfile

هيلمفيل - المجمع ل خوذة، والذي يسمح لك بوصف العديد من إصدارات الدفة في مكان واحد، وتحديد معلمات مخططاتها للعديد من البيئات، وكذلك تعيين ترتيب نشرها.

يمكنك أن تقرأ عن helmfile نفسه وأمثلة على استخدامه في التمهيدي и دليل أفضل الممارسات.

سوف نتعرف على طرق غير واضحة لوصف الإصدارات في helmfile

لنفترض أن لدينا حزمة من مخططات الدفة (على سبيل المثال، postgres وبعض تطبيقات الواجهة الخلفية) والعديد من البيئات (العديد من مجموعات 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

لقد انتهى بنا الأمر ببيئتين: تطوير, إنتاج - يحتوي كل منها على قيمه الخاصة لمخططات إصدار الدفة. سننشر لهم مثل هذا:

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

إصدارات مختلفة من المخططات الدفة في بيئات مختلفة

ماذا لو كنا بحاجة إلى طرح إصدارات مختلفة من الواجهة الخلفية لبيئات مختلفة؟ كيفية تحديد معلمة نسخة الإصدار؟ القيم البيئية المتاحة من خلال {{ .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، لأننا نعلم أننا لسنا بحاجة إلى دفع قاعدة البيانات إلى k8s وللبيع لدينا مجموعة 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، لكننا لا نريد تكوينه افتراضيًا في المخططات نفسها، والتي يتم تخزينها في اللفت.

في هذه الحالة، لكل إصدار يمكننا تحديد ملفين بقيم: الأول بالقيم الافتراضية، والتي ستحدد قيم المخطط نفسه، والثاني بقيم البيئة، والتي بدورها ستتجاوز تلك الافتراضية.

    .
    ├── 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، بحيث يعرف helmfile أنه يجب تشغيله من خلال محرك القالب.

    .
    ├── 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 في helmfile، والتي، حتى لو كانت .Values.secrets لن يكون موجودًا، ولن يلقي خطأً، ولكنه سيسمح بالنتيجة باستخدام الوظيفة default استبدال القيمة الافتراضية

اختتام

تبدو الأشياء الموصوفة واضحة تمامًا، لكن المعلومات حول الوصف المناسب للنشر في العديد من البيئات باستخدام helmfile نادرة جدًا، وأنا أحب IaC (البنية التحتية كرمز) وأريد الحصول على وصف واضح لحالة النشر.

في الختام، أود أن أضيف أن متغيرات البيئة الافتراضية يمكن، بدورها، تحديد معلماتها مع متغيرات البيئة الخاصة بنظام التشغيل لمشغل معين سيتم إطلاق النشر منه، وبالتالي الحصول على بيئات ديناميكية

helmfile.yaml

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

المصدر: www.habr.com

إضافة تعليق