Chart Entwicklung Tipps und Tricks
Dieses Handbuch bespricht Tipps und Tricks, die Helm Chart Entwickler bei der Entwicklung von produktionsreifen Charts gelernt haben.
Kenne Deine Vorlagenfunktionen
Helm benutzt Go Templates für Vorlagen Ihrer Resourcedateien. Wobei Go schon einige eingebauten Funktionen mitbringt, haben wir noch viele andere hinzugefügt.
Als erstes haben wir alle Funktionen in der Sprig Bibliothek hinzugefügt.
Wir haben auch zwei spezielle Vorlagenfunktionen hinzugefügt: include und required. Die
include Funktion erlaubt Ihnen das Hinzufügen anderer Vorlagen und das Zusammenfügen des
Ergebnisses in einer anderen Vorlagenfunktion.
Zum Beispiel diese Vorlage inkludiert eine Vorlage namens mytpl,
dann wandelt es diese in Kleinschreibung um und quotet diese mit doppelten Anführungszeichen.
value: {{ include "mytpl" . | lower | quote }}
Die required Function erlaubt Ihnen die Deklaration eines Wertes als notwendig für das
Vorlagenrendering. Wenn der Wert leer ist, wird das Vorlagenrendern fehlschlagen und dem
Benutzer eine Fehlermeldung ausgeben.
Das folgende Beispiel der required Funktion deklariert einen Eintrag für
.Values.who, der notwendig ist und gibt einen Fehler aus, wenn dieser fehlt:
value: {{ required "A valid .Values.who entry required!" .Values.who }}
Strings quoten, Integers nicht quoten
Wenn Sie mit Strings arbeiten, sind Sie mit Quoten immer auf der sicheren Seite:
name: {{ .Values.MyName | quote }}
Aber wenn Sie mit Integers arbeiten quoten Sie nicht die Werte. Das kann in vielen Fällen zu Fehlern in Kubernetes führen.
port: {{ .Values.Port }}
Dieser Hinweis gilt nicht für Umgebungsvariablen, die immer als String erwartet werden, auch wenn sie Integers repräsentieren:
env:
  - name: HOST
    value: "http://host"
  - name: PORT
    value: "1234"
Benutzen der 'include' Funktion
Go hat die Möglichkeit über eine eingebaute Funktion template zwei Vorlagen zu
verbinden. Leider kann diese eingebaute Funktion nicht in Go Vorlagen Pipelines
verwendet werden.
Um das zu ermöglichen, eine Vorlage zu inkludieren und die Vorlagenausgabe weiter
zu bearbeiten, hat Helm eine spezielle include Funktion:
{{ include "toYaml" $value | indent 2 }}
Dies inkludiert eine Vorlage namens toYaml, gibt das $value mit und
gibt dann die Ausgabe der Vorlage an die indent Funktion weiter.
Da YAML Einrückungen und Leerzeichen viel Bedeutung zumisst, ist das ein grossartiger Weg um Codeschnippsel zu inkludieren, aber die Einrückungen im relevaten Kontext zu halten.
Benutzung der 'required' Funktion
Go stellt einen Weg zur Verfügung, um Vorlagenoptionen zu setzen und so das
Verhalten zu beeinflussen, wenn eine Map mit einem Schlüssel indiziert wird,
der in der Map nicht vorhanden ist. Das ist typischerweise gesetzt mit
template.Options("missingkey=option"), wobei option default sein kann,
zero oder error. Wenn diese Option zu error gesetzt ist, wird die Ausführung
gestoppt, wennimmer der Wert leer ist. Es gibt Situationen, wenn Chart Entwickler
dieses Verhalten für bestimmte Werte in der values.yaml Datei hervorrufen möchten.
Die required Funktion gibt Entwicklern die Möglichkeit, einen Werteintrag zu
deklarieren, der für das Vorlagenrendern notwendig ist. Wenn der Wert in values.yaml
leer ist, wird die Vorlage nicht gerendert und eine Fehlermeldung wird vom Entwickler
bereitgestellt.
Zum Beispiel:
{{ required "A valid foo is required!" .Values.foo }}
Das oben wird eine Vorlage rendern, wenn .Values.foo definiert ist, aber fehlschlagen,
wenn .Values.foo nicht definiert ist.
Benutzen der 'tpl' Funktion
Die tpl Funktion erlaubt Entwicklern Strings als Vorlagen in Vorlagen zu evaluieren.
Das ist nützlich, um einen Vorlagenstring als Wert zu einem Chart oder zum Rendern
einer externen Konfigurationsdatei zu verwenden. Syntax: {{ tpl TEMPLATE_STRING VALUES }}
Beispiele:
# values
template: "{{ .Values.name }}"
name: "Tom"
# template
{{ tpl .Values.template . }}
# output
Tom
Rendern einer externen Konfigurationsdatei:
# external configuration file conf/app.conf
firstName={{ .Values.firstName }}
lastName={{ .Values.lastName }}
# values
firstName: Peter
lastName: Parker
# template
{{ tpl (.Files.Get "conf/app.conf") . }}
# output
firstName=Peter
lastName=Parker
Erstellen eines Image Pull Secrets
Image Pull Secrets sind eine Kombination aus registry, username und
password.  Sie brauchen sie vielleicht in einer Applikation, die Sie
bereitstellen möchten, aber zum Erstellen brauchen Sie öfters base64.
Wir können eine Hilfsvorlage erstellen, um die Docker Konfigurationsdatei
mit einem Secret Payload zu erstellen. Hier kommt das Beispiel:
Zuerst nehmen wir an, dass die Zugangsdaten in der values.yaml Datei definiert
sind, wie:
imageCredentials:
  registry: quay.io
  username: someone
  password: sillyness
  email: someone@host.com
Wir definieren dann unsere Hilfsvorlage wie folgt:
{{- define "imagePullSecret" }}
{{- with .Values.imageCredentials }}
{{- printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"email\":\"%s\",\"auth\":\"%s\"}}}" .registry .username .password .email (printf "%s:%s" .username .password | b64enc) | b64enc }}
{{- end }}
{{- end }}
Zum Schluss verwenden wir die Hilfsvorlage in einer grösseren Vorlage, um das Secret Manifest zu erstellen:
apiVersion: v1
kind: Secret
metadata:
  name: myregistrykey
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: {{ template "imagePullSecret" . }}
Automatisierte Bereitstellungen
Sehr oft werden ConfigMaps oder Secrets als Konfigurationsdateien in Container injiziert
oder dort sind andere externe Abhängigkeiten, was einen Pod Restart erforderlich macht.
Abhängig von der Applikation sollte ein Restart eine Aktualsierung durch helm upgrade
auslösen, aber die Deployment-Spezifikation selber ändert sich nicht und lässt die alte
Konfiguration als Ergebnis inkonsistent in der Bereitstellung.
Die sha256sum Funktion kann benutzt werden, um in der Annotation Sektion des Deployments
dieses zu aktualisieren, wenn sich die Datei geändert hat.
kind: Deployment
spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
[...]
In einem Ereignis, wenn Sie sowieso Ihr Deployment neu starten wollen, können Sie einen ähnlichen Schritt mit der Annotation gehen wie oben, aber diese mit einem zufälligen String ersetzen, sodass es immer eine Änderung gibt und diese einen Restart der Bereitstellung hervorruft:
kind: Deployment
spec:
  template:
    metadata:
      annotations:
        rollme: {{ randAlphaNum 5 | quote }}
[...]
Jede Benutzung dieser Vorlagenfunktion wird einen einzigartigen zufälligen String generieren. Das bedeutet, wenn dieser zufällige String mit mehreren Resourcen synchronisiert werden soll, müssen sich alle relevanten Resourcen in derselben Vorlagendatei befinden.
Beide Methoden helfen Ihnen, Ihre Aktualisierungsstrategie zu planen und Ausfälle zu verhindern.
HINWEIS: In der Vergangenheit empfohlen wir die Benutzung der Option
--recreate-pods. Diese Option ist als veraltet markiert und in Helm 3
favorisieren wir die Methoden oben.
Helm anweisen, keine Resourcen zu installieren
Manchmal sollen Resourcen von Helm nicht deinstalliert werden, wenn Helm
läuft mit helm uninstall. Chart Entwickler können eine Annotation zu einer
Resource hinzufügen, um das zu verhindern.
kind: Secret
metadata:
  annotations:
    "helm.sh/resource-policy": keep
[...]
(Als notwendig markieren)
Die Annotation "helm.sh/resource-policy": keep instruiert Helm, das Löschen
dieser Resource  bei Kommandos wie helm uninstall, helm upgrade oder
helm rollback zu übergehen, was normalerweise zum Löschen führen würde.
Helm wird diese nicht länger verwalten. Das kann zu Problemen führen,
etwa bei helm install --replace bei einer Version, die schon deinstalliert
ist, aber diese Resourcen behalten hat.
Benutzung von "Partials" und inkludierten Vorlagen
Manchmal möchten Sie Teile Ihres Charts wiederverwenden, in einem Block oder Vorlagenteile. Oft ist es sauberer, die in einer eigenen Datei vorzuhalten.
Im templates/ Verzeichnis werden Dateien, die mit einem Unterstrich
beginnen (_), nicht als Ausgabedateien für Kubernetes Manifeste betrachtet.
Mit dieser Konvention, werden Hilfsvorlagen und Teile in eine
_helpers.tpl Datei platziert.
Komplexe Charts mit vielen Abhängigkeiten
Viele Charts im CNCF Artifact Hub sind "building blocks" zum Erstellen erweiterter Applikationen. Aber Charts werden verwendet, zum Aufbau von Instanzen hochskalierbarer Anwendungen. In diesem Fall kann ein Schirm-Chart viele Unter-Charts haben, jede mit einer Funktion als Teil des Ganzen.
Die derzeitige Praxis zum Komponieren einer komplexten Applikation von
einzelnen Teilen ist ein Schirm-Chart auf höchster Stufe mit exponierten
globalen Konfigurationswerten und dann benutzen des charts/ Unterverzeichnis
zum Einschluss aller Komponenten.
YAML als Überschreibung von JSON
Entsprechend der Beschreibung der YAML Spezifikation ist YAML eine Überschreibung von JSON. Das bedeutet, dass jede valide JSON Struktur auch valide in YAML ist.
Dies hat Vorteile: Manchmal finden es Vorlagenentwickler einfacher eine Datenstruktur in JSON-ähnlicher Syntax anzugeben, anstatt sich mit dem leerzeichensensitiven YAML abzugeben.
Als bewährte Methode sollten Vorlagen einer YAML-ähnlichen Syntax folgen, unabhängig vom JSON. Die Syntax reduziert das Risiko eines Formatierungsproblems erheblich.
Vorsicht bei zufallsgenerierten Werten
Es gibt Funktionen in Helm, die zufällige Daten generieren, kryptographische Schlüssel usw.. Das ist gut so, aber achten Sie darauf, dass diese bem Aktualisieren und Rendern nochmal ausgeführt werden. Wenn eine Vorage unterschiedliche Daten wie beim letzten Lauf generiert, triggert das eine Aktualisierung der Resource.
Installieren oder Aktualisieren einer Version mit einem Kommando
Helm stellt einen Weg zur Verfügung, um Installation und Aktualisierung in einem Kommando
aufzurufen. Benutzen Sie helm upgrade mit dem --install Kommando. Das veranlasst Helm
erst nachzuschauen, ob eine Version schon installiert ist, bevor es sie installiert.
Wenn sie vorhanden ist, wird Helm die existierende Version aktualisieren.
$ helm upgrade --install <release name> --values <values file> <chart directory>