Erstellen Sie Pakete für Kubernetes mit Helm: Diagrammstruktur und Vorlagen



Wir haben in einem früheren Artikel über Helm gesprochen und „allgemein“ damit gearbeitet. Gehen wir nun die Praxis von der anderen Seite an - aus der Sicht des Erstellers der Diagramme (d. H. Pakete für Helm). Und obwohl dieser Artikel aus der Welt der Ausbeutung stammte, stellte sich heraus, dass er Materialien über Programmiersprachen ähnlicher war - so ist das Schicksal der Autoren der Charts. Ein Diagramm ist also eine Sammlung von Dateien ...

Diagrammdateien können in zwei Gruppen unterteilt werden:

  1. Dateien, die zum Generieren von Kubernetes-Ressourcenmanifesten erforderlich sind. Dazu gehören Vorlagen aus dem templates und Dateien mit Werten (Standardwerte werden in values.yaml gespeichert). In dieser Gruppe befinden sich auch die Datei require.yaml und das charts - all dies wird zum Organisieren verschachtelter Diagramme verwendet.
  2. Begleitdateien mit Informationen, die hilfreich sein können, um Diagramme zu finden, sie kennenzulernen und zu verwenden. Die meisten Dateien in dieser Gruppe sind optional.

Weitere Informationen zu den Dateien beider Gruppen:

  • Chart.yaml - Datei mit Informationen zum Diagramm;
  • LICENSE - eine optionale Textdatei mit einer Kartenlizenz;
  • README.md - eine optionale Datei mit Dokumentation;
  • requirements.yaml - eine optionale Datei mit einer Liste von Abhängigkeitsdiagrammen;
  • values.yaml - Datei mit Standardwerten für Vorlagen;
  • charts/ - ein optionales Verzeichnis mit verschachtelten Diagrammen;
  • templates/ - Verzeichnis mit Kubernetes Ressourcenmanifestvorlagen;
  • templates/NOTES.txt - Eine optionale Textdatei mit einem Hinweis, der dem Benutzer während der Installation und Aktualisierung angezeigt wird.

Um den Inhalt dieser Dateien besser zu verstehen, können Sie sich auf das offizielle Handbuch für Diagrammentwickler beziehen oder im offiziellen Repository nach relevanten Beispielen suchen.

Beim Erstellen eines Diagramms im Großen und Ganzen kommt es darauf an, einen ordnungsgemäß gestalteten Satz von Dateien zu organisieren. Die Hauptschwierigkeit bei diesem „Design“ ist die Verwendung eines ziemlich fortschrittlichen Vorlagensystems, um das gewünschte Ergebnis zu erzielen. Zum Rendern von Kubernetes-Ressourcenmanifesten wird eine Standard- Go-Vorlagen-Engine verwendet , die um Helm-Funktionen erweitert wird .

Erinnerung : Helm-Entwickler kündigten an, dass in der nächsten Hauptversion des Projekts - Helm 3 - Lua-Skripte unterstützt werden, die gleichzeitig mit Go-Vorlagen verwendet werden können. Ich werde auf diesen Punkt nicht näher eingehen - dies (und andere Änderungen in Helm 3) können hier gelesen werden .

So sieht Helm 2 beispielsweise aus wie die Kubernetes-Manifestvorlage der Bereitstellung für ein WordPress-Blog aus einem früheren Artikel :

deploy.yaml
 apiVersion: extensions/v1beta1 kind: Deployment metadata: name: {{ template "fullname" . }} labels: app: {{ template "fullname" . }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" spec: replicas: {{ .Values.replicaCount }} template: metadata: labels: app: {{ template "fullname" . }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" spec: {{- if .Values.image.pullSecrets }} imagePullSecrets: {{- range .Values.image.pullSecrets }} - name: {{ . }} {{- end}} {{- end }} containers: - name: {{ template "fullname" . }} image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy | quote }} env: - name: ALLOW_EMPTY_PASSWORD {{- if .Values.allowEmptyPassword }} value: "yes" {{- else }} value: "no" {{- end }} - name: MARIADB_HOST {{- if .Values.mariadb.enabled }} value: {{ template "mariadb.fullname" . }} {{- else }} value: {{ .Values.externalDatabase.host | quote }} {{- end }} - name: MARIADB_PORT_NUMBER {{- if .Values.mariadb.enabled }} value: "3306" {{- else }} value: {{ .Values.externalDatabase.port | quote }} {{- end }} - name: WORDPRESS_DATABASE_NAME {{- if .Values.mariadb.enabled }} value: {{ .Values.mariadb.db.name | quote }} {{- else }} value: {{ .Values.externalDatabase.database | quote }} {{- end }} - name: WORDPRESS_DATABASE_USER {{- if .Values.mariadb.enabled }} value: {{ .Values.mariadb.db.user | quote }} {{- else }} value: {{ .Values.externalDatabase.user | quote }} {{- end }} - name: WORDPRESS_DATABASE_PASSWORD valueFrom: secretKeyRef: {{- if .Values.mariadb.enabled }} name: {{ template "mariadb.fullname" . }} key: mariadb-password {{- else }} name: {{ printf "%s-%s" .Release.Name "externaldb" }} key: db-password {{- end }} - name: WORDPRESS_USERNAME value: {{ .Values.wordpressUsername | quote }} - name: WORDPRESS_PASSWORD valueFrom: secretKeyRef: name: {{ template "fullname" . }} key: wordpress-password - name: WORDPRESS_EMAIL value: {{ .Values.wordpressEmail | quote }} - name: WORDPRESS_FIRST_NAME value: {{ .Values.wordpressFirstName | quote }} - name: WORDPRESS_LAST_NAME value: {{ .Values.wordpressLastName | quote }} - name: WORDPRESS_BLOG_NAME value: {{ .Values.wordpressBlogName | quote }} - name: WORDPRESS_TABLE_PREFIX value: {{ .Values.wordpressTablePrefix | quote }} - name: SMTP_HOST value: {{ .Values.smtpHost | quote }} - name: SMTP_PORT value: {{ .Values.smtpPort | quote }} - name: SMTP_USER value: {{ .Values.smtpUser | quote }} - name: SMTP_PASSWORD valueFrom: secretKeyRef: name: {{ template "fullname" . }} key: smtp-password - name: SMTP_USERNAME value: {{ .Values.smtpUsername | quote }} - name: SMTP_PROTOCOL value: {{ .Values.smtpProtocol | quote }} ports: - name: http containerPort: 80 - name: https containerPort: 443 livenessProbe: httpGet: path: /wp-login.php {{- if not .Values.healthcheckHttps }} port: http {{- else }} port: https scheme: HTTPS {{- end }} {{ toYaml .Values.livenessProbe | indent 10 }} readinessProbe: httpGet: path: /wp-login.php {{- if not .Values.healthcheckHttps }} port: http {{- else }} port: https scheme: HTTPS {{- end }} {{ toYaml .Values.readinessProbe | indent 10 }} volumeMounts: - mountPath: /bitnami/apache name: wordpress-data subPath: apache - mountPath: /bitnami/wordpress name: wordpress-data subPath: wordpress - mountPath: /bitnami/php name: wordpress-data subPath: php resources: {{ toYaml .Values.resources | indent 10 }} volumes: - name: wordpress-data {{- if .Values.persistence.enabled }} persistentVolumeClaim: claimName: {{ .Values.persistence.existingClaim | default (include "fullname" .) }} {{- else }} emptyDir: {} {{ end }} {{- if .Values.nodeSelector }} nodeSelector: {{ toYaml .Values.nodeSelector | indent 8 }} {{- end -}} {{- with .Values.affinity }} affinity: {{ toYaml . | indent 8 }} {{- end }} {{- with .Values.tolerations }} tolerations: {{ toYaml . | indent 8 }} {{- end }} 

Nun zu den Grundprinzipien und Merkmalen der Standardisierung in Helm. Die meisten der folgenden Beispiele stammen aus den Diagrammen des offiziellen Repositorys .

Vorlagen


Vorlagen: {{ }}


Alles, was mit Vorlagen zu tun hat, ist in doppelte geschweifte Klammern gewickelt. Text außerhalb der geschweiften Klammern bleibt beim Rendern unverändert.

Kontextwert:.


Beim Rendern einer Datei oder eines Teils (weitere Informationen zum Wiederverwenden von Vorlagen finden Sie in den nächsten Abschnitten des Artikels) wird der Wert ausgelöst, auf den intern über die Kontextvariable zugegriffen werden kann. Bei Übergabe als Argument an eine Struktur wird der Punkt verwendet, um auf die Felder und Methoden dieser Struktur zuzugreifen.

Der Wert der Variablen ändert sich während des Rendervorgangs abhängig vom Kontext, in dem sie verwendet wird. Die meisten Blockanweisungen überschreiben die Kontextvariable im Hauptblock. Die Hauptoperatoren und ihre Funktionen werden nachstehend nach Kenntnis der grundlegenden Helmstruktur erläutert.

Die Grundstruktur von Helm


Beim Rendern von Manifesten wird eine Struktur mit den folgenden Feldern in die Vorlagen geworfen:

  • Feld .Values - für den Zugriff auf die Parameter, die während der Installation und Aktualisierung der Version festgelegt werden. Dazu gehören die Werte der Optionen --set , --set-string und --set-file sowie die Parameter von Dateien mit Werten, die Datei values.yaml und die Dateien, die den Werten der Optionen --values :

     containers: - name: main image: "{{ .Values.image }}:{{ .Values.imageTag }}" imagePullPolicy: {{ .Values.imagePullPolicy }} 
  • .Release - um Release-Daten zu Rollout, Installation oder Aktualisierung, Release-Name, Namespace und den Werten mehrerer weiterer Felder zu verwenden, die beim Generieren von Manifesten hilfreich sein können:

     metadata: labels: heritage: "{{ .Release.Service }}" release: "{{ .Release.Name }}" subjects: - namespace: {{ .Release.Namespace }} 
  • .Chart - um auf Diagramminformationen zuzugreifen. Die Felder entsprechen dem Inhalt der Datei Chart.yaml :

     labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 
  • Struktur .Files - zum Arbeiten mit Dateien, die im Diagrammverzeichnis gespeichert sind; Die Struktur und die verfügbaren Methoden finden Sie hier . Beispiele:

     data: openssl.conf: | {{ .Files.Get "config/openssl.conf" | indent 4 }} 

     data: {{ (.Files.Glob "files/docker-entrypoint-initdb.d/*").AsConfig | indent 2 }} 
  • .Capabilities - um auf Informationen zu dem Cluster zuzugreifen, in dem der .Capabilities wird:

     {{- if .Capabilities.APIVersions.Has "apps/v1beta2" }} apiVersion: apps/v1beta2 {{- else }} apiVersion: extensions/v1beta1 {{- end }} 

     {{- if semverCompare "^1.9-0" .Capabilities.KubeVersion.GitVersion }} apiVersion: apps/v1 {{- else }} 

Betreiber


Wir beginnen natürlich mit den else if , else if und else :

 {{- if .Values.agent.image.tag }} image: "{{ .Values.agent.image.repository }}:{{ .Values.agent.image.tag }}" {{- else }} image: "{{ .Values.agent.image.repository }}:v{{ .Chart.AppVersion }}" {{- end }} 

Der range ist für die Arbeit mit Arrays und Karten ausgelegt. Wenn ein Array als Argument übergeben wird und Elemente enthält, wird für jedes Element ein Block nacheinander ausgeführt (in diesem Fall wird der Wert innerhalb des Blocks über die Kontextvariable verfügbar):

 {{- range .Values.ports }} - name: {{ .name }} port: {{ .containerPort }} targetPort: {{ .containerPort}} {{- else }} ... {{- end}} 

 {{ range .Values.tolerations -}} - {{ toYaml . | indent 8 | trim }} {{ end }} 

Um mit Maps zu arbeiten, wird eine Syntax mit Variablen bereitgestellt:

 {{- range $key, $value := .Values.credentials.secretContents }} {{ $key }}: {{ $value | b64enc | quote }} {{- end }} 

Ein ähnliches Verhalten tritt with Operator: auf: Wenn das übergebene Argument vorhanden ist, wird der Block ausgeführt und die Kontextvariable im Block entspricht dem Wert des Arguments. Zum Beispiel:

 {{- with .config }} config: {{- with .region }} region: {{ . }} {{- end }} {{- with .s3ForcePathStyle }} s3ForcePathStyle: {{ . }} {{- end }} {{- with .s3Url }} s3Url: {{ . }} {{- end }} {{- with .kmsKeyId }} kmsKeyId: {{ . }} {{- end }} {{- end }} 

Um die Vorlagen wiederzuverwenden, kann ein Bundle aus define [name] und template [name] [variable] verwendet werden, wobei der übergebene Wert über die Kontextvariable im define Block verfügbar gemacht wird:

 apiVersion: v1 kind: ServiceAccount metadata: name: {{ template "kiam.serviceAccountName.agent" . }} ... {{- define "kiam.serviceAccountName.agent" -}} {{- if .Values.serviceAccounts.agent.create -}} {{ default (include "kiam.agent.fullname" .) .Values.serviceAccounts.agent.name }} {{- else -}} {{ default "default" .Values.serviceAccounts.agent.name }} {{- end -}} {{- end -}} 

Einige Funktionen, die bei der Verwendung von define oder einfacher partiell berücksichtigt werden müssen:

  • Teilweise deklariert sind global und können in allen Dateien des templates .
  • Das Hauptdiagramm wird zusammen mit den abhängigen Diagrammen kompiliert. Wenn also zwei Teilteilnamen des gleichen Typs vorhanden sind, wird der zuletzt geladene verwendet. Wenn Sie einen Teil benennen, ist es üblich, einen Diagrammnamen hinzuzufügen, um solche Konflikte zu vermeiden: define "chart_name.partial_name" . define "chart_name.partial_name" .

Variablen: $


Zusätzlich zur Arbeit mit dem Kontext können Sie Daten mithilfe von Variablen speichern, ändern und wiederverwenden:

 {{ $provider := .Values.configuration.backupStorageProvider.name }} ... {{ if eq $provider "azure" }} envFrom: - secretRef: name: {{ template "ark.secretName" . }} {{ end }} 

Beim Rendern einer Datei oder eines Teils hat $ dieselbe Bedeutung wie der Punkt. Im Gegensatz zur Kontextvariablen (Punkt) ändert sich der Wert von $ im Kontext von Blockanweisungen nicht, sodass Sie gleichzeitig mit dem Kontextwert der Blockanweisung und der grundlegenden Helmstruktur arbeiten können (oder mit dem Wert, der an partiell übergeben wird, wenn wir über die Verwendung von $ innerhalb partiell'a sprechen). . Unterschied Illustration:

 context: {{ . }} dollar: {{ $ }} with: {{- with .Chart }} context: {{ . }} dollar: {{ $ }} {{- end }} template: {{- template "flant" .Chart -}} {{ define "flant" }} context: {{ . }} dollar: {{ $ }} with: {{- with .Name }} context: {{ . }} dollar: {{ $ }} {{- end }} {{- end -}} 

Als Ergebnis der Verarbeitung dieser Vorlage stellt sich Folgendes heraus (der Übersichtlichkeit halber werden in der Ausgabe der Struktur die entsprechenden Pseudonamen ersetzt):

 context: #  helm dollar: #  helm with: context: #.Chart dollar: #  helm template: context: #.Chart dollar: #.Chart with: context: habr dollar: #.Chart 

Und hier ist ein echtes Beispiel für die Verwendung dieser Funktion:

 {{- if .Values.ingress.enabled -}} {{- range .Values.ingress.hosts }} apiVersion: extensions/v1beta1 kind: Ingress metadata: name: {{ template "nats.fullname" $ }}-monitoring labels: app: "{{ template "nats.name" $ }}" chart: "{{ template "nats.chart" $ }}" release: {{ $.Release.Name | quote }} heritage: {{ $.Release.Service | quote }} annotations: {{- if .tls }} ingress.kubernetes.io/secure-backends: "true" {{- end }} {{- range $key, $value := .annotations }} {{ $key }}: {{ $value | quote }} {{- end }} spec: rules: - host: {{ .name }} http: paths: - path: {{ default "/" .path }} backend: serviceName: {{ template "nats.fullname" $ }}-monitoring servicePort: monitoring {{- if .tls }} tls: - hosts: - {{ .name }} secretName: {{ .tlsSecret }} {{- end }} --- {{- end }} {{- end }} 

Einrückung


Bei der Entwicklung von Vorlagen können zusätzliche Ränder verbleiben: Leerzeichen, Tabulatoren, Zeilenvorschübe. Mit ihnen sieht die Datei einfach besser lesbar aus. Sie können sie entweder aufgeben oder eine spezielle Syntax verwenden, um Einrückungen um die verwendeten Muster zu entfernen:

  • {{- variable }} schneidet vorherige Leerzeichen ab;
  • {{ variable -}} schneidet nachfolgende Leerzeichen ab;
  • {{- variable -}} sind beide Optionen.

Ein Beispiel für eine Datei, deren Verarbeitung der Line habr flant helm :

 habr {{- " flant " -}} helm 

Eingebaute Funktionen


Alle in die Vorlage integrierten Funktionen finden Sie unter folgendem Link . Hier werde ich nur über einige von ihnen erzählen.

Die index dient zum Zugriff auf Elemente eines Arrays oder von Maps:

 definitions.json: | { "users": [ { "name": "{{ index .Values "rabbitmq-ha" "rabbitmqUsername" }}", "password": "{{ index .Values "rabbitmq-ha" "rabbitmqPassword" }}", "tags": "administrator" } ] } 

Die Funktion verwendet eine beliebige Anzahl von Argumenten, mit denen Sie mit verschachtelten Elementen arbeiten können:

$map["key1"]["key2"]["key3"] => index $map "key1" "key2" "key3"

Zum Beispiel:

 httpGet: {{- if (index .Values "pushgateway" "extraArgs" "web.route-prefix") }} path: /{{ index .Values "pushgateway" "extraArgs" "web.route-prefix" }}/#/status {{- end }} 

Boolesche Operationen werden in der Template-Engine als Funktionen (und nicht als Operatoren) implementiert. Alle Argumente für sie werden beim Bestehen ausgewertet:

 {{ if and (index .Values field) (eq (len .Values.field) 10) }} ... {{ end }} 

Wenn kein Feld vorhanden field schlägt das Rendern field Vorlage fehl ( error calling len: len of untyped nil ): Die zweite Bedingung wird überprüft, obwohl die erste nicht erfüllt wurde. Es lohnt sich, eine Notiz zu machen und solche Fragen zu lösen, indem Sie sie in mehrere Prüfungen aufteilen:

 {{ if index . field }} {{ if eq (len .field) 10 }} ... {{ end }} {{ end }} 

Pipeline ist eine einzigartige Funktion von Go-Vorlagen, mit der Sie Ausdrücke deklarieren können, die wie eine Pipeline in einer Shell ausgeführt werden. Formal ist die Pipeline eine Befehlskette, die durch das Symbol | . Ein Befehl kann ein einfacher Wert oder ein Funktionsaufruf sein . Das Ergebnis jedes Befehls wird als letztes Argument an den nächsten Befehl übergeben , und das Ergebnis des letzten Befehls in der Pipeline ist der Wert der gesamten Pipeline. Beispiele:

 data: openssl.conf: | {{ .Files.Get "config/openssl.conf" | indent 4 }} 

 data: db-password: {{ .Values.externalDatabase.password | b64enc | quote }} 

Zusätzliche Funktionen


Sprig ist eine Bibliothek mit 70 nützlichen Funktionen zur Lösung einer Vielzahl von Aufgaben. Aus Sicherheitsgründen schließt Helm die Funktionen env und expandenv aus, die den Zugriff auf Tiller-Umgebungsvariablen ermöglichen.

Die include Funktion wird wie die Standardvorlagenfunktion zum Wiederverwenden von Vorlagen verwendet. Im Gegensatz zur template kann die Funktion in der Pipeline verwendet werden, d.h. Übergeben Sie das Ergebnis an eine andere Funktion:

 metadata: labels: {{ include "labels.standard" . | indent 4 }} {{- define "labels.standard" -}} app: {{ include "hlf-couchdb.name" . }} heritage: {{ .Release.Service | quote }} release: {{ .Release.Name | quote }} chart: {{ include "hlf-couchdb.chart" . }} {{- end -}} 

Die required Funktion gibt Entwicklern die Möglichkeit, die zum Rendern der Vorlage erforderlichen Werte zu deklarieren: Wenn der Wert vorhanden ist, wird er beim Rendern der Vorlage verwendet, andernfalls endet das Rendern mit der vom Entwickler angegebenen Fehlermeldung:

 sftp-user: {{ required "Please specify the SFTP user name at .Values.sftp.user" .Values.sftp.user | b64enc | quote }} sftp-password: {{ required "Please specify the SFTP user password at .Values.sftp.password" .Values.sftp.password | b64enc | quote }} {{- end }} {{- if .Values.svn.enabled }} svn-user: {{ required "Please specify the SVN user name at .Values.svn.user" .Values.svn.user | b64enc | quote }} svn-password: {{ required "Please specify the SVN user password at .Values.svn.password" .Values.svn.password | b64enc | quote }} {{- end }} {{- if .Values.webdav.enabled }} webdav-user: {{ required "Please specify the WebDAV user name at .Values.webdav.user" .Values.webdav.user | b64enc | quote }} webdav-password: {{ required "Please specify the WebDAV user password at .Values.webdav.password" .Values.webdav.password | b64enc | quote }} {{- end }} 

Mit der Funktion tpl können Sie eine Zeichenfolge als Vorlage rendern. Im Gegensatz zu template und include können Sie mit dieser Funktion Vorlagen ausführen, die in Variablen übergeben werden, sowie Vorlagen rendern, die nicht nur im templates gespeichert sind. Wie sieht es aus?

Ausführen von Vorlagen aus Variablen:

 containers: {{- with .Values.keycloak.extraContainers }} {{ tpl . $ | indent 2 }} {{- end }} 

... und in values.yaml wir folgenden Wert:

 keycloak: extraContainers: | - name: cloudsql-proxy image: gcr.io/cloudsql-docker/gce-proxy:1.11 command: - /cloud_sql_proxy args: - -instances={{ .Values.cloudsql.project }}:{{ .Values.cloudsql.region }}:{{ .Values.cloudsql.instance }}=tcp:5432 - -credential_file=/secrets/cloudsql/credentials.json volumeMounts: - name: cloudsql-creds mountPath: /secrets/cloudsql readOnly: true 

Rendern einer Datei, die außerhalb des templates gespeichert ist:

 apiVersion: batch/v1 kind: Job metadata: name: {{ template "mysqldump.fullname" . }} labels: app: {{ template "mysqldump.name" . }} chart: {{ template "mysqldump.chart" . }} release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" spec: backoffLimit: 1 template: {{ $file := .Files.Get "files/job.tpl" }} {{ tpl $file . | indent 4 }} 

... im Diagramm befindet sich entlang des Pfads files/job.tpl die folgende Vorlage:

 spec: containers: - name: xtrabackup image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy | quote }} command: ["/bin/bash", "/scripts/backup.sh"] envFrom: - configMapRef: name: "{{ template "mysqldump.fullname" . }}" - secretRef: name: "{{ template "mysqldump.fullname" . }}" volumeMounts: - name: backups mountPath: /backup - name: xtrabackup-script mountPath: /scripts restartPolicy: Never volumes: - name: backups {{- if .Values.persistentVolumeClaim }} persistentVolumeClaim: claimName: {{ .Values.persistentVolumeClaim }} {{- else -}} {{- if .Values.persistence.enabled }} persistentVolumeClaim: claimName: {{ template "mysqldump.fullname" . }} {{- else }} emptyDir: {} {{- end }} {{- end }} - name: xtrabackup-script configMap: name: {{ template "mysqldump.fullname" . }}-script 

Hier endete die Einführung in die Grundlagen der Standardisierung in Helm ...

Fazit


Der Artikel beschreibt die Struktur von Helm-Diagrammen und untersucht im Detail die Hauptschwierigkeiten bei ihrer Erstellung - Vorlage: Grundprinzipien, Syntax, Funktionen und Go-Template-Operatoren, zusätzliche Funktionen.

Wie fange ich an, mit all dem zu arbeiten? Da Helm bereits ein ganzes Ökosystem ist, können Sie sich immer Beispiele für Diagramme für ähnliche Pakete ansehen. Wenn Sie beispielsweise eine neue Nachrichtenwarteschlange packen möchten, sehen Sie sich das öffentliche RabbitMQ-Diagramm an . Natürlich verspricht Ihnen niemand ideale Implementierungen in vorhandenen Paketen, aber sie sind als Ausgangspunkt perfekt. Der Rest kommt mit Übung, in der die Befehle zum --dry-run der --dry-run und zum Debuggen von Helmflusen Ihnen helfen und die Installation mit der Option --dry-run .

Für ein umfassenderes Verständnis der Entwicklung von Helm-Diagrammen, Best Practices und verwendeten Technologien empfehle ich, dass Sie sich unter den folgenden Links (alle in englischer Sprache) mit den Materialien vertraut machen:


Und am Ende des nächsten Helm-Materials füge ich eine Umfrage bei, die hilft, besser zu verstehen, auf welche anderen Artikel über Helm die Habr-Leser warten (oder nicht warten?). Vielen Dank für Ihre Aufmerksamkeit!

PS


Lesen Sie auch in unserem Blog:

Source: https://habr.com/ru/post/de423239/


All Articles