
Wenn Sie mit der Kubernetes-Umgebung arbeiten, verwenden Sie wahrscheinlich mehrere vorhandene Vorlagen-Tools, von denen einige Teil von Paketmanagern wie Helm oder Ksonnet sind oder nur Vorlagen-Sprachen (Jinja2, Go-Vorlage usw.). Alle haben ihre eigenen Nachteile und Vorteile, und wir werden sie durchgehen und unser eigenes Tool schreiben, das versucht, die besten Funktionen zu kombinieren.
Warum also nicht Helm?
Es gibt eine Reihe von Artikeln, die Helm kritisieren (z. B. nur einen: Überlegen Sie zweimal, bevor Sie Helm verwenden ). Das Hauptproblem bei Helm ist, dass es mit Zeichenfolgendarstellungen funktioniert und Kubernetes-Manifeste (json) Objekte sind . Die wahre Hölle für einen Helm-Diagrammentwickler beginnt, wenn er yaml
für ein yaml
Manifest berechnen yaml
. Manchmal sieht es so aus (es ist ein echtes Beispiel aus meinem Diagramm):
spec: jobTemplate: spec: template: spec: containers: - name: my-awesome-container resources: {{ toYaml .Values.resources | indent 14 }}

Aber Helm ist heute de facto der Standard für Kubernetes-Anwendungsverpackungen. Der Hauptvorteil von Helm ist eine große Community und eine große Anzahl öffentlicher Repositories mit Diagrammen. Und kürzlich haben Helm-Entwickler einen Helm-Hub angekündigt. Helm ist heute wie Docker - es ist nicht der einzige, aber es hat Gemeinschaft und Unterstützung.
Es gibt vielversprechende Änderungen mit der Veröffentlichung von Helm 3, aber niemand weiß, wann es sein könnte.
Abschließend Helm Vorteile:
- Große Community und eine Reihe von öffentlichen Charts
- (Relativ) menschenfreundliche Syntax. Zumindest ist es yaml + go template;)
Nachteile:
- Arbeiten mit Zeichenfolgen und nicht mit Objekten
- Begrenzte Anzahl von Operatoren und Funktionen, die Sie verwenden können
OK, dann vielleicht Ksonnet?
Wenn Sie Helm mit Ksonnet vergleichen, hat letzteres einen großen Vorteil, nämlich, dass es mit Objekten funktioniert. Ksonnet ist ein Tool, das auf der JSON-Vorlagensprache Jsonnet basiert. Ein weiteres cooles Feature von Ksonnet ist, dass es Kubernetes-API-kompatible Jsonnet-Bibliotheken enthält, die Sie in Ihre Vorlage importieren und mit Kubernetes-Objekten wie in jeder OOP-Sprache arbeiten können:
local k = import "k.libsonnet"; local deployment = k.apps.v1beta1.deployment; local appDeployment = deployment .new( params.name, params.replicas, container .new(params.name, params.image) .withPorts(containerPort.new(targetPort)), labels);
Sieht beeindruckend aus, nicht wahr?
Es ist etwas weniger ordentlich, wenn Sie nicht mit API-Objekten arbeiten, sondern nur mit yaml
Objekten, die aus der yaml
/ json
Datei importiert wurden:
{ global: {}, components: { "deployment-nginx-deployment-dkecx"+: { spec+: { replicas: 10, template+: { spec+: { containers+: [ { name: "nginx", image: "nginx:latest", ports: [ { containerPort: 80, }, ], }, ], }, }, }, }, }, }
Aber es ist immer noch etwas und es ist besser als mit Saiten in Helm zu arbeiten. Der Nachteil von Ksonnet ist, dass es eine kleinere Community und weniger Pakete als Helm hat (obwohl Sie Helm-Diagramme in Ihr Ksonnet-Projekt importieren können, aber Sie werden mit ihnen als json-Objekte arbeiten, nicht als jsonnet-Bibliotheksobjekte). Und aufgrund einer kleineren Community und eines kleineren Beitrags fehlen einige Funktionen, wenn Sie versuchen, Ihr eigenes Diagramm zu schreiben. Eine davon habe ich selbst erlebt: Sie wissen, dass Sie in Helm eine ConfigMap
aus einem Verzeichnis ConfigMap
können, das eine Reihe von Konfigurationsdateien enthält:
apiVersion: v1 kind: ConfigMap metadata: name: conf data: {{- (.Files.Glob "foo/*").AsConfig | nindent 2 }}
Sie können sich meine Frustration vorstellen, als ich herausfand, dass es in Ksonnet keine solche Funktion gibt. Es gibt jedoch Problemumgehungen. Aber der Punkt ist, dass es nur ein Beispiel für die Situation ist, in der Sie glücklich Ihr Diagramm schreiben und dann plötzlich ein Mangel an einer Funktion Sie auf halbem Weg aufhält.
Insgesamt Vorteile von Ksonnet:
- Arbeiten mit Objekten
- Kubernetes-API-kompatible Jsonnet-Bibliotheken
- Unterstützung für den Import von Helmdiagrammen
Nachteile:
- Kleinere Community und geringere Anzahl von Ksonnet-nativen Paketen
- Fehlende Funktionen, die Sie in Helm verwenden können
- Neue Syntax => erhöhte Lernzeit => erhöhter Busfaktor
- Syntax kann manchmal hässlich und weniger lesbar werden (insbesondere, wenn Problemumgehungen für fehlende Funktionen vorgenommen werden).
Hier sind einige Kriterien für das "ideale" Vorlagenwerkzeug:
- Es sollte mit Objekten funktionieren, nicht mit Strings
- Es sollte in der Lage sein, mit Kubernetes-API-kompatiblen Objekten zu arbeiten
- Es sollte einen anständigen Satz von Funktionen für die Arbeit mit Strings haben
- Es sollte gut mit json- und yaml-Formaten funktionieren
- Es sollte menschenfreundlich sein
- Es sollte einfach sein
- Es sollte die Möglichkeit haben, vorhandene Helm-Diagramme zu importieren (da dies Realität ist und wir die Helm-Community nutzen möchten).
Das reicht fürs Erste. Ich ging diese Liste in meinem Kopf durch und dachte mir: Okay, warum nicht Python ausprobieren? Mal sehen, ob es unseren Kriterien entspricht:
- Arbeiten Sie mit Objekten, nicht mit Zeichenfolgen . Ja, wir können dafür
dict
und dict
verwenden. - Sie können mit Kubernetes-API-kompatiblen Objekten arbeiten . Ja,
from kubernetes import client
- Haben Sie einen anständigen Satz von Funktionen für die Arbeit mit Zeichenfolgen . Viel!
- Arbeiten Sie gut mit den Formaten json und yaml . Sehr schön.
- Menschenfreundlich Keine Scheiße.
- Einfach Ja
- Möglichkeit zum Importieren vorhandener Helmdiagramme . Das werden wir uns hinzufügen.
Ok, sieht vielversprechend aus. Ich habe mich entschlossen, ein einfaches Template-Tool auf die offizielle Python-Client-Bibliothek für Kubernetes zu schreiben, und jetzt möchte ich Ihnen zeigen, was dabei herausgekommen ist.
Treffen Sie Karavel
Dieses Tool ist weder besonders noch kompliziert. Ich habe gerade die Kubernetes-Bibliothek (die mir die Möglichkeit gab, mit Kubernetes-Objekten zu arbeiten) genommen und einige grundlegende Funktionen für vorhandene Helm-Diagramme geschrieben (damit man sie abrufen und in ein eigenes Diagramm einfügen kann). Also, lass uns eine Tour machen.
Zuallererst ist dieses Tool bei Github Repo verfügbar und dort finden Sie ein Verzeichnis mit Beispielen.
Schnellstart mit Docker-Image
Wenn Sie es ausprobieren möchten, verwenden Sie am einfachsten dieses Docker-Image :
$ docker run greegorey/karavel -h usage: karavelcli.py [-h] subcommand ... optional arguments: -h, --help show this help message and exit list of subcommands: subcommand template generates manifests from template ensure ensure helm dependencies
Wenn Sie Diagramme vorlegen möchten, müssen Sie natürlich das Verzeichnis Ihres Diagramms bereitstellen:
$ cd example $ docker run -v $PWD:/chart greegorey/karavel template .
Schauen wir uns also die Diagrammstruktur an. Es ist einem von Helm sehr ähnlich:
$ cd example $ tree . . ├── dependencies ├── prod.yaml ├── requirements.yaml ├── templates │ ├── custom-resource.py │ ├── deployment.py │ └── service-helm.py └── values.yaml 2 directories, 6 files
Wie Helm hat es die Datei require.yaml mit demselben Layout:
dependencies: - name: mysql version: 0.13.1 repository: https://kubernetes-charts.storage.googleapis.com/
Hier listen Sie einfach Ihre Helm-Abhängigkeiten auf, die Sie in Ihr Diagramm importieren möchten. Die Abhängigkeiten werden in das dependencies
verschoben. Verwenden Sie zum Abrufen oder Aktualisieren den Befehl verify:
$ karavel ensure .
Danach sieht Ihr dependencies
aus:
$ tree dependencies dependencies └── mysql-0.13.1 └── mysql ├── Chart.yaml ├── README.md ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── configurationFiles-configmap.yaml │ ├── deployment.yaml │ ├── initializationFiles-configmap.yaml │ ├── pvc.yaml │ ├── secrets.yaml │ ├── svc.yaml │ └── tests │ ├── test-configmap.yaml │ └── test.yaml └── values.yaml 4 directories, 13 files
Nachdem wir nun unsere Abhängigkeiten sichergestellt haben, schauen wir uns die Vorlagen an. Zunächst erstellen wir eine einfache Nginx-Bereitstellung:
from kubernetes import client from karavel.helpers import Values def template(): values = Values().values
Damit die Vorlage gültig ist, benötigen Sie die Funktion template()
, die entweder ein einzelnes Kubernetes-Objekt oder eine list
/ ein tuple
davon zurückgibt. Die Liste der API-Objekte für den Python-Client finden Sie hier .
Wie Sie sehen können, ist der Code sauber, einfach und lesbar. Sie können sich fragen, woher von values.nginx.image.repository
kommt? Es erhält Werte aus den karavel template -f one.yaml --values two.yaml
des Diagramms übergeben, genau wie in Helm: karavel template -f one.yaml --values two.yaml
. Wir werden sie uns später ansehen.
Okay, was ist mit Helm-Charts?
Jetzt haben wir unsere eigene Bereitstellung erstellt. Aber was ist, wenn wir ein Helmdiagramm oder einen Teil eines Diagramms importieren möchten? templates/service-helm.py
wir einen Blick auf templates/service-helm.py
:
from kubernetes import client from karavel.helm import HelmChart from karavel.helpers import Values def template(): values = Values().values
Einfach, oder? Beachten Sie diese Zeile: service = chart.get(name='svc', obj_class=client.V1Service)
- Wir haben ein Objekt der Klasse V1Service
aus der Helm- yaml
Datei erstellt. Wenn Sie das nicht wollen / müssen, können Sie immer nur mit dict
.
Was ist, wenn ich eine benutzerdefinierte Ressource erstellen möchte?
Nun, damit gibt es ein kleines Problem. Die Kubernetes-API fügt der swagger json-Definition unter /openapi/v2
keine CRD-Objekte /openapi/v2
, und Python-Client-Objekte bauen auf dieser Definition auf. Sie können jedoch problemlos mit dict
. So:
from kubernetes import client def template(): resource = { 'apiVersion': 'stable.example.com/v1', 'kind': 'Whale', 'metadata': client.V1ObjectMeta( name='my-object', ), 'spec': { 'image': 'my-whale-image:0.0.1', 'tail': 1, 'fins': 4, } } return resource
Sieht immer noch gut aus, nicht wahr?
Kann ich Werte für verschiedene Umgebungen haben, z. B. dev / prod?
Ja, das kannst du!
Schauen wir values.yaml
zuerst values.yaml
:
nginx: image: repository: nginx tag: 1.15-alpine mysql: port: 3307 protocol: TCP helm: releaseName: my-release namespace: prod imageTag: '5.7.14' service: type: NodePort
Beachten Sie den chart = HelmChart(name='mysql', version='0.13.1', values=values.mysql.helm)
dict: Wir haben ihn verwendet, um Werte für helm chart chart = HelmChart(name='mysql', version='0.13.1', values=values.mysql.helm)
. Einige Helm-Diagramme benötigen releaseName
für die Anwendungsbenennung und den namespace
für RBAC-Richtlinien. Diese beiden Werte werden als Argumente --namespace
und NAME
in der --namespace
an Helm --namespace
.
Jetzt können Sie eine zusätzliche Datei für prod env angeben und alle unsere Beispiele vorlegen:
$ karavel template -f values.yaml -f prod.yaml . --- # Source: templates/custom-resource.py apiVersion: stable.example.com/v1 kind: Whale metadata: name: my-object spec: fins: 4 image: my-whale-image:0.0.1 tail: 1 --- # Source: templates/deployment.py apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - image: nginx:1.14-alpine name: nginx ports: - containerPort: 80 --- # Source: templates/service-helm.py apiVersion: v1 kind: Service metadata: annotations: null labels: app: prod-release-mysql chart: mysql-0.13.1 release: prod-release-suffix name: prod-release-mysql spec: ports: - name: my-custom-port port: 3308 protocol: TCP targetPort: 39000 selector: app: prod-release-mysql type: NodePort
Danach können Sie kubeclt apply
und diese Objekte im Cluster bereitstellen.
Cool! Was ist mit Codierung und base64?
import base64
Was ist mit Vault für Geheimnisse?
import hvac
URLs abrufen?
import importlib
Sichere Hash-Funktionen?
import Crypto
Du hast es verstanden. Mit Python können Sie viele Dinge mit Ihren Kubernetes-Manifesten tun.
Ist es das NIH-Syndrom?
Nein :)
Ich bin glücklich mit Helm in meinen aktuellen Projekten. Es gibt Dinge, die ich vermisse. Ich habe Ksonnet auch in einigen meiner Projekte verwendet.
Ich möchte dieses Tool als Proof-of-Concept betrachten, dass wir Vorlagen-Tools besser als Helm haben können und es nicht sehr schwierig ist, sie mit Python zu entwickeln. Wenn ein Gemeinschaftsinteresse / -bedürfnis an einem solchen Tool besteht, können wir es gemeinsam weiterentwickeln. Oder wir können auf die Veröffentlichung von Helm 3 warten;)
Fazit
Ich habe Ihnen ein Python-basiertes Template-Tool für Kubernetes gezeigt, das Unterstützung für Kubernetes-API-kompatible Objekte und Unterstützung für den Import von Helm-Diagrammen bietet. Alle Kommentare und Diskussionen aus der Community sind willkommen und auch im Repo willkommen.
Vielen Dank für das Lesen und einen schönen Tag!
Referenzen