
Die Notwendigkeit,
die Ressourcen des Kubernetes-Clusters zu nutzen, kann unter Kampfbedingungen auftreten, wenn Sie sie nicht einfach mit Helm-Tools neu erstellen können. Zwei Hauptgründe können unterschieden werden:
- Es wird einfach sein - unabhängig davon, ob Sie eine Wolke oder Bare Metal haben.
- Beim Entfernen können Dienste in den Clouds verloren gehen, und die zugehörigen Load Balancer in Kubernetes fliegen ab.
In unserem Fall war die Lösung erforderlich, um funktionierende
Ingress-Nginx zu erfassen und gleichzeitig unseren Kubernetes-Operator zu integrieren.
Für Helm ist es absolut inakzeptabel, dass die von ihm verwalteten Ressourcen nicht von ihm erstellt werden.
"Wenn die Release-Ressourcen Ihres Teams manuell geändert werden können, müssen Sie sich auf die im Abschnitt [BUG] beschriebenen Probleme einstellen. Nach dem Rollout entspricht der Status der Release-Ressourcen im Cluster nicht dem beschriebenen Helm-Diagramm ." (aus unserem letzten Artikel )
Wie bereits erwähnt, funktioniert Helm wie folgt:
- Bei jeder Installation (
helm install
, helm upgrade
) speichert Helm das generierte Release-Manifest im Speicher-Backend . Standardmäßig wird ConfigMaps verwendet: Für jede Version einer Version wird ConfigMap in demselben Namespace erstellt, in dem Tiller ausgeführt wird. - Bei wiederholten Rollouts (Befehl zum
helm upgrade
Helms) vergleicht Helm das neu generierte Manifest mit dem alten Manifest der neuesten Version der DEPLOYED-Version von ConfigMap und wendet den resultierenden Unterschied in Kubernetes an.
Basierend auf diesen Funktionen sind wir zu dem Schluss gekommen, dass es ausreicht, ConfigMap (Storage Backend Release) zu patchen,
um es aufzunehmen , d. H. vorhandene Ressourcen im Cluster übernehmen.
Tiller bezieht sich auf ConfigMap im folgenden Format:
%RELEASE_NAME.v%REVISION
. Um vorhandene
Einträge kubectl get cm -l OWNER=TILLER --namespace kube-system
müssen Sie den Befehl
kubectl get cm -l OWNER=TILLER --namespace kube-system
(standardmäßig ist Tiller im Namespace
kube-system
- andernfalls müssen Sie den verwendeten angeben).
$ kubectl get cm -l OWNER=TILLER -n kube-system NAME DATA AGE release_name_1.v618 1 5d release_name_1.v619 1 1d release_name_2.v1 1 2d release_name_2.v2 1 3d
Jede ConfigMap wird in diesem Format dargestellt:
apiVersion: v1 data: release: H4sIAHEEd1wCA5WQwWrDMAyG734Kwc52mtvwtafdAh27FsURjaljG1kp5O3nNGGjhcJ21M/nT7+stVZvcEozO7LAFAgLnSNOdG4boSkHFCpNIb55R2bBKSjM/ou4+BQt3Fp19XGwcNoINZHggIJWAayaH6leJ/24oTIBewplpQEwZ3Ode+JIdanxqXkw/D4CGClMpoyNG5HlmdAH05rDC6WPRTC6p2Iv4AkjXmjQ/WLh04dArEomt9aVJVfHMcxFiD+6muTEsl+i74OF961FpZEvJN09HEXyHmdOklwK1X7s9my7eYdK7egk8b8/6M+HfwNgE0MSAgIAAA== kind: ConfigMap metadata: creationTimestamp: 2019-02-08T11:12:38Z labels: MODIFIED_AT: "1550488348" NAME: release_name_1 OWNER: TILLER STATUS: DEPLOYED VERSION: "618" name: release_name_1.v618 namespace: kube-system resourceVersion: "298818981" selfLink: /api/v1/namespaces/kube-system/configmaps/release_name_1.v618 uid: 71c3e6f3-2b92-11e9-9b3c-525400a97005
OU4 + BQt3Fp19XGwcNoINZHggIJWAayaH6leJ / 24oTIBewplpQEwZ3Ode + JIdanxqXkw / D4CGClMpoyNG5HlmdAH05rDC6WPRTC6p2Iv4AkjXmjQ / WLh04dArEomt9aVJVfHMcxFiD + 6muTEsl + i74OF961FpZEvJN09HEXyHmdOklwK1X7s9my7eYdK7egk8b8 / 6M + HfwNgE0MSAgIAAA == apiVersion: v1 data: release: H4sIAHEEd1wCA5WQwWrDMAyG734Kwc52mtvwtafdAh27FsURjaljG1kp5O3nNGGjhcJ21M/nT7+stVZvcEozO7LAFAgLnSNOdG4boSkHFCpNIb55R2bBKSjM/ou4+BQt3Fp19XGwcNoINZHggIJWAayaH6leJ/24oTIBewplpQEwZ3Ode+JIdanxqXkw/D4CGClMpoyNG5HlmdAH05rDC6WPRTC6p2Iv4AkjXmjQ/WLh04dArEomt9aVJVfHMcxFiD+6muTEsl+i74OF961FpZEvJN09HEXyHmdOklwK1X7s9my7eYdK7egk8b8/6M+HfwNgE0MSAgIAAA== kind: ConfigMap metadata: creationTimestamp: 2019-02-08T11:12:38Z labels: MODIFIED_AT: "1550488348" NAME: release_name_1 OWNER: TILLER STATUS: DEPLOYED VERSION: "618" name: release_name_1.v618 namespace: kube-system resourceVersion: "298818981" selfLink: /api/v1/namespaces/kube-system/configmaps/release_name_1.v618 uid: 71c3e6f3-2b92-11e9-9b3c-525400a97005
Die generierten Manifeste werden in binärer Form gespeichert (im obigen Beispiel mit dem Schlüssel
.data.release
).
.data.release
wir beschlossen, die Version mit den Standard-Helm-Werkzeugen zu erstellen, jedoch mit einem speziellen
Stub , der später durch die Manifeste der ausgewählten Ressourcen ersetzt wird.
Implementierung
Der Lösungsalgorithmus lautet wie folgt:
- Wir bereiten eine
manifest.yaml
Datei mit Ressourcenmanifesten zur Annahme vor (dieses Element wird nachstehend ausführlicher erläutert). - Wir erstellen ein Diagramm, in dem es eine einzige Vorlage mit einer temporären ConfigMap gibt, weil Helm kann kein Release ohne Ressourcen erstellen.
- Wir erstellen ein
templates/stub.yaml
mit einem Stub, dessen Länge der Anzahl der Zeichen in manifest.yaml
(während der Experimente stellte sich heraus, dass die Anzahl der Bytes übereinstimmen muss). Als Stub sollte ein reproduzierbarer Zeichensatz ausgewählt werden, der nach der Generierung verbleibt und im Speicher-Backend gespeichert wird. Zur Vereinfachung und Klarheit wird #
verwendet, d.h.
{{ repeat ${manifest_file_length} "#" }}
- Installieren Sie das Diagramm:
helm install
und helm upgrade --install
. - Wir ersetzen den Stub in der Speicher-Backend-Version durch die Ressourcenmanifeste aus
manifest.yaml
, die im ersten Schritt zur Übernahme ausgewählt wurden:
stub=$(printf '#%.0s' $(seq 1 ${manifest_file_length})) release_data=$(kubectl get -n ${tiller_namespace} cm/${release_name}.v1 -o json | jq .data.release -r) updated_release_data=$(echo ${release_data} | base64 -d | zcat | sed "s/${stub}/$(sed -z 's/\n/\\n/g' ${manifest_file_path} | sed -z 's/\//\\\//g')/" | gzip -9 | base64 -w0) kubectl patch -n ${tiller_namespace} cm/${release_name}.v1 -p '{"data":{"release":"'${updated_release_data}'"}}'
- Wir prüfen, ob Tiller verfügbar ist und haben unsere Änderungen übernommen.
- Löschen Sie die temporäre ConfigMap (ab dem zweiten Schritt).
- Darüber hinaus unterscheidet sich die Arbeit mit der Version nicht von der regulären.
Das Wesentliche zu der oben beschriebenen Implementierung finden Sie unter:
$ ./script.sh Example: ./script.sh foo bar-prod manifest.yaml Usage: ./script.sh CHART_NAME RELEASE_NAME MANIFEST_FILE_TO_ADOPT [TILLER_NAMESPACE]
Als Ergebnis des Skripts wird die Version von
RELEASE_NAME
erstellt. Es wird Ressourcen zugeordnet, deren Manifeste in der Datei
MANIFEST_FILE_TO_ADOPT
beschrieben sind.
CHART_NAME
wird ein
CHART_NAME
Diagramm generiert, mit dem insbesondere Manifeste und Releases weiter begleitet werden können.
Bei der Vorbereitung des Manifests mit Ressourcen müssen Dienstfelder gelöscht werden, die von Kubernetes verwendet werden (dies sind dynamische Dienstdaten, daher ist es falsch, sie in Helm zu versionieren). In einer idealen Welt besteht das Training aus einem Befehl:
kubectl get RESOURCE -o yaml --export
. Immerhin heißt es in der Dokumentation:
--export=false: If true, use 'export' for the resources. Exported resources are stripped of cluster-specific information.
... aber wie die Praxis gezeigt hat, ist die Option
--export
noch
--export
, sodass zusätzliche Manifestformatierungen erforderlich sind. Im
service/release-name-habr
müssen Sie die
selfLink
creationTimestamp
und
selfLink
entfernen.
kubectl version $ kubectl version Client Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.3", GitCommit:"721bfa751924da8d1680787490c54b9179b1fed0", GitTreeState:"clean", BuildDate:"2019-02-01T20:08:12Z", GoVersion:"go1.11.5", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.3", GitCommit:"721bfa751924da8d1680787490c54b9179b1fed0", GitTreeState:"clean", BuildDate:"2019-02-01T20:00:57Z", GoVersion:"go1.11.5", Compiler:"gc", Platform:"linux/amd64"}
kubectl get service / release-name-habr -o yaml --export apiVersion: v1 kind: Service metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"release-name","app.kubernetes.io/managed-by":"Tiller","app.kubernetes.io/name":"habr","helm.sh/chart":"habr-0.1.0"},"name":"release-name-habr","namespace":"default"},"spec":{"ports":[{"name":"http","port":80,"protocol":"TCP","targetPort":"http"}],"selector":{"app.kubernetes.io/instance":"release-name","app.kubernetes.io/name":"habr"},"type":"ClusterIP"}} creationTimestamp: null labels: app.kubernetes.io/instance: release-name app.kubernetes.io/managed-by: Tiller app.kubernetes.io/name: habr helm.sh/chart: habr-0.1.0 name: release-name-habr selfLink: /api/v1/namespaces/default/services/release-name-habr spec: ports: - name: http port: 80 protocol: TCP targetPort: http selector: app.kubernetes.io/instance: release-name app.kubernetes.io/name: habr sessionAffinity: None type: ClusterIP status: loadBalancer: {}
Im Folgenden finden Sie Beispiele für die Verwendung des Skripts. Beide zeigen, wie das Skript verwendet wird, um im Cluster arbeitende Ressourcen zu übernehmen und sie anschließend mit den Helm-Tools zu löschen.
Beispiel 1

Beispiel 2

Fazit
Die im Artikel beschriebene Lösung kann finalisiert und verwendet werden, um Kubernetes-Ressourcen nicht nur von Grund auf neu zu übernehmen, sondern sie auch vorhandenen Versionen hinzuzufügen.
Derzeit gibt es keine Lösungen, mit denen die im Cluster vorhandenen Ressourcen beschlagnahmt und an das Helm-Management übertragen werden können. Es ist möglich, dass in Helm 3 eine Lösung für dieses Problem implementiert wird (zumindest gibt es einen
Vorschlag zu diesem Thema).
PS
Andere aus dem K8s Tipps & Tricks-Zyklus:
Lesen Sie auch in unserem Blog: