Tipps und Tricks von Kubernetes: Verschieben von Clusterressourcen auf Helm 2



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:

  1. 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.
  2. 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:

  1. Wir bereiten eine manifest.yaml Datei mit Ressourcenmanifesten zur Annahme vor (dieses Element wird nachstehend ausführlicher erläutert).
  2. Wir erstellen ein Diagramm, in dem es eine einzige Vorlage mit einer temporären ConfigMap gibt, weil Helm kann kein Release ohne Ressourcen erstellen.
  3. 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} "#" }} 
  4. Installieren Sie das Diagramm: helm install und helm upgrade --install .
  5. 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}'"}}' 
  6. Wir prüfen, ob Tiller verfügbar ist und haben unsere Änderungen übernommen.
  7. Löschen Sie die temporäre ConfigMap (ab dem zweiten Schritt).
  8. 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:

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


All Articles