{"id":3368,"date":"2024-01-28T14:55:35","date_gmt":"2024-01-28T13:55:35","guid":{"rendered":"https:\/\/informatik.htwk-leipzig.de\/seminar\/?p=3368"},"modified":"2024-01-28T17:09:15","modified_gmt":"2024-01-28T16:09:15","slug":"helm-sh","status":"publish","type":"post","link":"https:\/\/informatik.htwk-leipzig.de\/seminar\/lehrveranstaltungen\/betriebliche-informationssysteme\/2024\/helm-sh\/","title":{"rendered":"Helm.sh"},"content":{"rendered":"<div align=\"justify\">\n<h1>Helm.sh<\/h1>\n<p>In der Welt der Containerorchestrierung ist effizientes Deployment entscheidend. Der Paket-Manager <em>Helm<\/em> selbst bezeichnet sich als:<\/p>\n<blockquote><p>&#8222;Der beste Weg, Anwendungen f\u00fcr Kubernetes zu finden, zu teilen und einzusetzen&#8220; <sup>[1]<\/sup><\/p><\/blockquote>\n<p>Die Verwendung von Helm ist eng mit der Funktionsweise des Open-Source-Systems <em>Kubernetes<\/em> (K8s) verbunden. Helm fungiert als eine Abstraktionsebene f\u00fcr Kubernetes und zielt darauf ab, Administratoren und Entwicklern die Verwaltung, Entwicklung und Bereitstellung von Software in Kubernetes-Clustern zu erleichtern. Dabei erfordert die Vermittlung des Prinzips hinter der Paketverwaltung ein grundlegendes Verst\u00e4ndnis von Kubernetes, welches im Folgenden vermittelt werden soll.<\/p>\n<h2>Kubernetes<\/h2>\n<p>Kubernetes treibt als System zur Orchestrierung, Bereitstellung und allgemeinen Verwaltung von containerisierten Anwendungen seit 2014 den Paradigmenwechsel zur Containerisierung von Software und deren Abh\u00e4ngigkeiten voran. So soll eine konsistente Bereistellung von Systemen sowie eine Portabilit\u00e4t \u00fcber verschiedene Umgebungen erzielt werden.<br \/>\n\u00dcber Helm bereitgestellte Software profitiert damit von vielen leistungsf\u00e4higen nennenswerten Funktionen, die Kubernetes durch den Betrieb von Containern in einem Cluster realisiert, darunter Skalierung, Lastverteilung und allgemeine Widerstandsf\u00e4higkeit des Systems. Signifikant ist dabei nicht zuletzt der deklarative Ansatz, bei dem ein gewisser vorkonfigurierter Zielzustand beschrieben wird. Unabh\u00e4ngige, komponierbare Steuerungsprozesse treiben den aktuellen Zustand des Systems dabei kontinuierlich in Richtung des bereitgestellten Soll-Zustandes. <sup>[2]<\/sup><\/p>\n<p>Ein solches Kubernetes-Cluster besteht dabei grundlegend aus sogenannten <em>Nodes<\/em>, die auf einer oder mehreren Maschinen laufen k\u00f6nnen. Dabei fungiert einer dieser Nodes als <em>Main Node<\/em>, w\u00e4hrend die \u00dcbrigen als <em>Worker Nodes<\/em> bezeichnet werden. Der Main Node \u00fcbernimmt eine allgemeine Steuerungsfunktion f\u00fcr die Worker Nodes und verf\u00fcgt daf\u00fcr \u00fcber verschiedene Komponenten wie den Controller-Manager oder einen API-Server als Schnittstelle f\u00fcr Administratoren.<\/p>\n<figure id=\"attachment_3407\" aria-describedby=\"caption-attachment-3407\" style=\"width: 1225px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-3407\" src=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2024\/12\/helm1.png\" alt=\"Grundlegender Bestandteile eines Kubernetes-Clusters: Worker Node(s) und Main Node\" width=\"1225\" height=\"966\" \/><figcaption id=\"caption-attachment-3407\" class=\"wp-caption-text\">Komponenten der Main Node und Worker Nodes in einem Kubernetes-Cluster<\/figcaption><\/figure>\n<p>Auch die Worker Nodes verf\u00fcgen \u00fcber essentielle Komponenten, wobei die wichtigsten die sogenannten <em>Pods<\/em> sind. Diese Pods umfassen jeweils einen oder mehrere Container, in denen wiederum die letztendlich bereitzustellenden Anwendungen in isolierten Umgebungen laufen.<br \/>\nDer erreichte Endzustand dieser Konfiguration wird als Deployment bezeichnet und beschreibt nicht nur die Anzahl der laufenden Pods in den jeweiligen Nodes, sondern auch weitere Eigenschaften wie das Verhalten der Container beim Einspielen von Updates oder \u00e4hnliches.<\/p>\n<p>In der Praxis sind komplexe Anwendungen oft modular aufgebaut, was die Notwendigkeit einer Kommunikation der Pods untereinander erfordert. Daf\u00fcr werden die Anwendungen in den Pods \u00fcber sogenannte Services abgebildet, die als eine Art Reverse-Proxy dienen und die Netzwerkkomplexit\u00e4t f\u00fcr den Entwickler abstrahieren. Der Service fungiert dann als Kommunikationsendpunkt f\u00fcr eine gewisse bereitgestellte Anwendung des Clusters.<\/p>\n<figure id=\"attachment_3406\" aria-describedby=\"caption-attachment-3406\" style=\"width: 1218px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-3406\" src=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2024\/12\/helm2.png\" alt=\"Services in einem Kubernetes-Cluster\" width=\"1218\" height=\"963\" \/><figcaption id=\"caption-attachment-3406\" class=\"wp-caption-text\">Abstrahierung durch Services in einem Kubernetes-Cluster<\/figcaption><\/figure>\n<p>Das illustrierte Beispiel zeigt den Betrieb eines Webserver und einer Datenbank in einem Kubernetes-Cluster. Potentielle Anfragen eines beliebigen Webserver-Pods sind dabei nicht an die Datenbank-Pods direkt gerichtet, sondern werden zun\u00e4chst an den abstrahierenden Datenbank-Service adressiert. Dieser leitet die Anfrage letztendlich an einen verf\u00fcgbaren Datenbank-Pod weiter, wobei die Auswahl des Pods von Faktoren wie der aktuellen Auslastung abh\u00e4ngen kann.<\/p>\n<p>Damit nun auch eine Kommunikation von extern erfolgen kann, kommt zus\u00e4tzlich ein sogenannter <em>Ingress<\/em>-Controller zum Einsatz. Mittels Konfiguration durch Ingress-Resourcen werden bestimmte Pfade und Hostnamen auf bereitgestellte Services abgebildet. Der Ingress-Controller realisiert damit eine Verarbeitung und Weiterleitung von Anfragen aus dem Internet, sodass die betriebenen Anwendungen auch von Clients au\u00dferhalb des Clusters addressiert werden k\u00f6nnen.<\/p>\n<figure id=\"attachment_3405\" aria-describedby=\"caption-attachment-3405\" style=\"width: 1680px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-3405\" src=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2024\/12\/helm3.png\" alt=\"Ingress Controller und Ingress Ressourcen\" width=\"1680\" height=\"967\" \/><figcaption id=\"caption-attachment-3405\" class=\"wp-caption-text\">Ingress Controller und Ingress Ressourcen<\/figcaption><\/figure>\n<h2>Grundkonzept von Helm.sh<\/h2>\n<p>Damit Kubernetes Ressourcen nicht manuell angelegt werden m\u00fcssen kann Helm verwendet werden, ein auf Go basierender Paketmanager f\u00fcr Kubernetes. Das Ziel besteht darin, Updates und Rollbacks effizienter zu gestalten. Daf\u00fcr verwendet es insgesamt drei <strong>Grundkonzepte<\/strong>:<\/p>\n<h4>Charts<\/h4>\n<p>Diese sind vergleichbar mit <em>Homebrew formulaes<\/em>, <em>apt dpkg<\/em> oder <em>yum rpm<\/em> Dateien. Charts sind praktisch eine Sammlung von Dateien, die eine zusammenh\u00e4ngende Menge von Kubernetes-Ressourcen beschreiben. Daf\u00fcr gibt es zum einen die <code>chart.yml<\/code>. Diese beinhaltet die Definition der Metadaten des Paketes, z. B. die Angabe der <code>apiVersion<\/code>, den Namen des Charts, sowie die Beschreibung oder den Typ des Charts, etc.<br \/>\nOptionale Parameter sind m\u00f6glich, wie zum Beispiel <code>dependencies<\/code>, <code>maintainers<\/code>, <code>keyWords<\/code> oder <code>kubeVersion<\/code>. Der Typ kann sowohl <em>Application<\/em> (Standard) oder <em>Library<\/em> sein. Letzteres beinhaltet \u00fcblicherweise keine Ressourcen-Objekte und ist nicht installierbar.<br \/>\nDie <code>values.yml<\/code> stellt den zentralen Ort f\u00fcr Konfigurationen bereit und beinhaltet Standardwerte f\u00fcr Konfigurationseinstellungen. Die darin definierten Werte k\u00f6nnen anschlie\u00dfend innerhalb von <em>Templates<\/em> verwendet werden. Die Wortseparierung erfolgt mittels <em>CamelCase<\/em>. Eine Definition der Werte ist sowohl verschachtelt als auch flach m\u00f6glich. Zudem k\u00f6nnen definierte Standardwerte \u00fcberschrieben werden, um die Charts an unterschiedliche Umgebungen anpassen zu k\u00f6nnen. Dadurch wird eine hohe Flexibilit\u00e4t und die Wiederverwendbarkeit von Charts erm\u00f6glicht.<br \/>\nDie Dateien <code>chart.yml<\/code> und <code>values.yml<\/code> k\u00f6nnen dann jeweils f\u00fcr Templates verwendet werden, bspw. in einer Kubernetes <code>deployment.yml<\/code>-Datei. Diese Templates stellen die eigentlichen Kernkomponenten eines Charts dar. Es sind Kubernetes-Manifest-Dateien, \u00fcber welche dynamische Inhalte gerendert werden k\u00f6nnen. Zudem verwenden sie verschiedene Werte aus <code>values.yml<\/code>, um spezifische Aspekte der Kubernetes-Ressourcen zu entwickeln. Als Beispiel k\u00f6nnen hier die Anzahl der Replikate aufgef\u00fchrt werden. Insgesamt entsteht eine dynamische Gestaltung der Helm Charts durch die Verwendung von Templates. Dadurch kann der gleiche Chart f\u00fcr verschiedene Installationen mit unterschiedlichen Konfigurationen verwendet werden.<\/p>\n<h4>Repositories<\/h4>\n<p>Erstellte Helm Charts k\u00f6nnen in Repositories gespeichert werden. Diese k\u00f6nnen selbst gehostet werden, wie z. B. \u00fcber das firmeninterne Nexus. Auf Wunsch kann das eigene Repository bei Artifact Hub angegeben werden. Daraufhin werden die Pakete indexiert und in der Suche angezeigt. <a href=\"https:\/\/artifacthub.io\/\">Artifact Hub<\/a> stellt dabei eine Vielzahl von vorgefertigten Charts f\u00fcr g\u00e4ngige Anwendungen zur Verf\u00fcgung.<\/p>\n<h4>Release<\/h4>\n<p>Ein Release bezeichnet eine Instanz eines installierten Charts innerhalb eines Kubernetes-Clusters. Helm erm\u00f6glicht es, verschiedene Releases des selben Charts mit unterschiedlichen Konfigurationen zu verwalten.<\/p>\n<p>&nbsp;<\/p>\n<h2>Beispielhafter Workflow<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-3401 aligncenter\" src=\"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-content\/uploads\/2024\/01\/helm_workflow.png\" alt=\"\" width=\"501\" height=\"240\" \/><\/p>\n<ol>\n<li>Der Softwareentwickler entwickelt ein Chart mit den darin enthaltenen Templates.<\/li>\n<li>Dieses wird anschlie\u00dfend in das firmeninterne Repository verschoben.<\/li>\n<li>Die Cluster werden von einem Administrator verwaltet. Dieser nutzt Helm, muss jedoch nicht genau wissen wie der Chart aufgebaut ist. Er muss eventuell nur wissen, welche Konfigurationen notwendig sind.<\/li>\n<li>Der Administrator kann nun per Kommandozeile der erstellte Chart herunterladen bzw. aktualisieren und in das Kubernetes-Cluster deployen. Dadurch entf\u00e4llt die Notwendigkeit des manuellen Anlegens der Kubernetes-Ressourcen<\/li>\n<li>Das Deployment erfolgt \u00fcber den Kubernetes-API-Server, welcher auf dem Main Node l\u00e4uft und die Charts und Konfigurationen kombiniert, die zum Erstellen eines Releases ben\u00f6tigt werden. Aktualisierung und Deinstallation von Releases sind hier\u00fcber ebenfalls m\u00f6glich.<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<div align=\"left\">\n<h2><b>Anwendungsbeispiel 1: \u00d6ffentliches Helm Chart<br \/>\n<\/b><\/h2>\n<\/div>\n<h3>Installation von Minikube und Helm<\/h3>\n<p align=\"justify\">Es gibt verschiedene Wege, um sich ein eigenes kleines lokales Kubernetes-Cluster aufzusetzen. In diesem Fall soll <i>Minikube<\/i> verwendet werden. In dieser Anleitung geht man davon aus, dass Minikube auf einem Linux System mit der x86-64 Prozessorarchitektur installiert werden soll. Auf der <a href=\"https:\/\/minikube.sigs.k8s.io\/docs\/start\/\">Minikube Website<\/a> findet man weitere Anleitungen f\u00fcr andere Betriebssysteme und Prozessorarchitekturen. Minikube kann dann \u00fcber folgende Kommandos installiert werden:<\/p>\n<pre>$ curl -LO \\\r\n\r\n<u><a href=\"https:\/\/storage.googleapis.com\/minikube\/releases\/latest\/minikube-linuxamd64\">https:\/\/storage.googleapis.com\/minikube\/releases\/latest\/minikube-linuxamd64<\/a><\/u>\r\n\r\n$ sudo install minikube-linux-amd64 \/usr\/local\/bin\/minikube<\/pre>\n<p>&nbsp;<\/p>\n<p>Um das Cluster hochzufahren, muss eine Container-Virtualisierungssoftware wie etwa <em>Docker<\/em> installiert sein. Das Cluster kann man dann hochfahren \u00fcber die Eingabe von:<\/p>\n<pre>$ minikube start<\/pre>\n<p>&nbsp;<\/p>\n<p align=\"justify\">Ab jetzt kann mit dem Kubernetes Cluster mithilfe des Kommandos <i>kubectl<\/i> interagiert werden, welches bei der Installation von Minikube automatisch mitinstalliert wird. Um sich von der Funktionsweise von <i>kubectl<\/i> zu \u00fcberzeugen, kann folgendes Kommando ausgef\u00fchrt werden, welches die Nodes, aus dem das Cluster besteht, auflistet:<\/p>\n<pre>$ kubectl get nodes\r\nNAME       STATUS   ROLES           AGE   VERSION\r\nminikube   Ready    control-plane   42d   v1.28.3<\/pre>\n<p>Zudem muss noch ein Addon auf dem Minikube Cluster aktiviert werden:<\/p>\n<pre>$ minikube addons enable ingress<\/pre>\n<p>Abschlie\u00dfend kann dann noch Helm \u00fcber die Kommandozeile installiert werden:<\/p>\n<pre>$ curl https:\/\/raw.githubusercontent.com\/helm\/helm\/main\/scripts\/get-helm-3 | bash<\/pre>\n<\/div>\n<h3><\/h3>\n<h3><b>Installation des Nextcloud Charts<\/b><\/h3>\n<div align=\"justify\">\n<p align=\"justify\">F\u00fcr dieses Beispiel gehen wir davon aus, dass man einen Nextcloud Server auf dem Kubernetes Cluster installieren m\u00f6chte. Auf Artifact Hub bietet Nextcloud ein offizielles <a href=\"https:\/\/artifacthub.io\/packages\/helm\/nextcloud\/nextcloud\">Nextcloud Helm Chart<\/a> an. Die Seite des Charts gibt neben Installationsanweisungen auch dar\u00fcber Auskunft, wie man der Chart bei der Installation konfigurieren kann. Die folgenden Schritte beschreiben chronologisch die Installation des Nextcloud Helm Charts, lassen sich aber theoretisch auch auf die Installation eines beliebigen anderen Charts \u00fcbertragen.<\/p>\n<h4>1. Verweis auf das Nextcloud Repo anlegen<\/h4>\n<p>Um der Chart \u00fcber Helm auf dem lokalen Cluster zu installieren, muss zun\u00e4chst eine Referenz auf das Repo, in dem der Chart liegt, hinterlegt werden, damit Helm bei der Installation wei\u00df, welches genaue Chart installiert werden soll.<\/p>\n<pre>$ helm repo add nextcloud <span style=\"color: #0563c1\"><u><a href=\"https:\/\/nextcloud.github.io\/helm\/\">https:\/\/nextcloud.github.io\/helm\/<\/a><\/u><\/span>\r\n\"nextcloud\" has been added to your repositories<\/pre>\n<h4>2. Konfigurationsdatei anlegen<\/h4>\n<p>Um der Chart bei der Installation zu konfigurieren, legt man eine Datei <code>config.yaml<\/code> an, in der die angestrebte Konfiguration \u00fcber Key-Value-Paare beschrieben wird:<\/p>\n<pre>nextcloud:\r\n   host: mynextcloud.xyz\r\n   username: user01\r\n   password: password123\r\n\r\ningress: \r\n   enabled: true \r\n   ingressClass: \"nginx\"\r\n\r\nmariadb: \r\n   enabled: true\r\n   auth.username: \"admin\"\r\n   auth.password: \"1337H@xx0r\"\r\n   auth.rootPassword: \"1337H@xx0r\"<\/pre>\n<p>Mit dieser Konfiguration sorgt man daf\u00fcr, dass der Nextcloud Server unter der Domain <em>mynextcloud.xyz<\/em> erreichbar ist und ein Benutzer mit dem Namen <em>user01<\/em> und dem Passwort <em>password123<\/em> angelegt wird. Da der Server auch von au\u00dfen bspw. \u00fcber den Browser ansprechbar sein soll, wird zus\u00e4tzlich ein Ingress Objekt dazu konfiguriert. Damit die vom Server verwalteten Dateien auch nach einem Neustart des Servers noch vorhanden sind, soll neben dem Nextcloud Server abschlie\u00dfend noch eine <em>MariaDB<\/em> installiert werden.<\/p>\n<h4>3. Installation des Charts<\/h4>\n<p>Nun kann der Chart unter der Angabe der im vorigen Schritt erstellten Konfigurationsdatei installiert werden. Der Chart wird hierbei im <i>demo<\/i> Namespace installiert:<\/p>\n<pre>$ : helm -n demo install my-nextcloud nextcloud\/nextcloud -f config.yaml\r\nNAME: my-nextcloud\r\nLAST DEPLOYED: Thu Jan 25 11:50:56 2024\r\nNAMESPACE: demo\r\nSTATUS: deployed\r\nREVISION: 1\r\nTEST SUITE: None\r\nNOTES:\r\n...\r\n<\/pre>\n<p>Die Installation des Helm Charts &#8211; also das Release &#8211; tr\u00e4gt den gew\u00e4hlten Namen <em>my-nextcloud<\/em>, was man aus der Ausgabe des Kommandos erkennen kann.<\/p>\n<p>Um zu sehen, was im Hintergrund auf dem Kubernetes Cluster passiert ist, l\u00e4sst man sich die Pods, Ingress Objekte und Services im demo Namespace anzeigen:<\/p>\n<pre>$ kubectl -n demo get pods,ingress,svc\r\nNAME                                READY   STATUS    RESTARTS   AGE\r\npod\/my-nextcloud-688c657846-n2jzt   1\/1     Running   0          80s\r\npod\/my-nextcloud-mariadb-0          1\/1     Running   0          80s\r\n\r\nNAME                                     CLASS   HOSTS             ADDRESS        PORTS   AGE\r\ningress.networking.k8s.io\/my-nextcloud   nginx   mynextcloud.xyz   192.168.49.2   80      81s\r\n\r\nNAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE\r\nservice\/my-nextcloud           ClusterIP   10.100.85.36                  8080\/TCP   81s\r\nservice\/my-nextcloud-mariadb   ClusterIP   10.101.116.73                 3306\/TCP   81s\r\n<\/pre>\n<p>Hier sieht man nun, dass durch die Installation des Charts Kubernetes Ressourcen angelegt wurden. So repr\u00e4sentieren die zwei Pods den Nextcloud Server sowie die MariaDB Instanz. Ebenso wurde ein Ingress-Objekt erstellt, das angibt, dass der Nextcloud Server unter der angegebenen Domain zu erreichen ist. Die zwei bereitgestellten Services stellen sicher, dass die Pods im Cluster erreicht werden k\u00f6nnen. Wie man an dieser Stelle sehen kann, spiegelt der Zustand des Clusters mit den angelegten Kubernetes Ressourcen genau die Konfiguration wider, die man bei der Installation des Charts mithilfe der <code>config.yaml<\/code> \u00fcbergeben hat.<\/p>\n<h4>3. DNS-Eintrag anlegen<\/h4>\n<p>Um den Nextcloud Server \u00fcber die angegebene Domain erreichen zu k\u00f6nnen, muss im letzten Schritt nur noch ein lokaler DNS-Eintrag angelegt werden, mit dem die Domain mynextcloud.xyz auf die IP-Adresse des Clusters aufgel\u00f6st wird. Die IP-Adresse des Clusters erh\u00e4lt man \u00fcber:<\/p>\n<pre>$ minikube ip\r\n192.168.49.2<\/pre>\n<p>Dann erstellt man einen DNS-Eintrag in der Datei <em>\/etc\/hosts<\/em>. Hier muss die IP-Adresse, die man aus dem Output des vorigen Commands erh\u00e4lt, gefolgt von der Domain mynextcloud.xyz eingetragen werden.<br \/>\nEin m\u00f6gliches Beispiel sieht man in der folgenden Abbildung, in der die Domain auf die IP-Adresse 192.168.49.2 aufl\u00f6st.<\/p>\n<pre>127.0.0.1\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 localhost\r\n\r\n192.168.49.2       mynextcloud.xyz<\/pre>\n<p>Damit ist die Installation des Nextcloud Helm Charts abgeschlossen und kann nun genutzt werden. Hierzu einfach mynextcloud.xyz im Browser eingeben.<\/p>\n<\/div>\n<p>&nbsp;<\/p>\n<h3><b>Upgrade des installierten Nextcloud Charts<\/b><\/h3>\n<div align=\"justify\">\n<p>Neben der Installation ist es auch m\u00f6glich, die Konfiguration eines Helm Releases nach der Installation abzu\u00e4ndern. Der installierte Nextcloud Server soll nun nicht mehr auf die MariaDB angewiesen sein. Dazu passt man zun\u00e4chst die <code>config.yaml<\/code> an und kommentiert den nicht mehr ben\u00f6tigten Teil aus:<\/p>\n<pre>nextcloud:\r\n   host: mynextcloud.xyz\r\n   username: user01\r\n   password: password123\r\n\r\ningress: \r\n   enabled: true \r\n   ingressClass: \"nginx\"\r\n\r\n# mariadb: \r\n   # enabled: true\r\n   # auth.username: \"admin\"\r\n   # auth.password: \"1337H@xx0r\"\r\n   # auth.rootPassword: \"1337H@xx0r\"<\/pre>\n<p>Jetzt kann man der Helm Chart mit der ge\u00e4nderten Konfiguration upgraden.<\/p>\n<pre>$ helm -n demo upgrade my-nextcloud nextcloud\/nextcloud -f config.yaml\r\nRelease \"my-nextcloud\" has been upgraded. Happy Helming!\r\n...\r\n<\/pre>\n<p>Wenn man sich nun erneut die Pods und Services auf dem Cluster anzeigen l\u00e4sst, so f\u00e4llt auf, dass der MariaDB-Pod und der zugeh\u00f6rige Service verschwunden sind.<\/p>\n<pre>kubectl -n demo get pods,ingress,svc\r\nNAME                                READY   STATUS    RESTARTS   AGE\r\npod\/my-nextcloud-69ddd8f55f-5jvhh   1\/1     Running   0          113s\r\n\r\nNAME                                     CLASS   HOSTS             ADDRESS        PORTS   AGE\r\ningress.networking.k8s.io\/my-nextcloud   nginx   mynextcloud.xyz   192.168.49.2   80      8m49s\r\n\r\nNAME                   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE\r\nservice\/my-nextcloud   ClusterIP   10.100.85.36                 8080\/TCP   8m49s\r\n<\/pre>\n<h3 align=\"left\"><b>Deinstallation des installierten Nextcloud Charts<\/b><\/h3>\n<p>Abschlie\u00dfend m\u00f6chten wir das Release deinstallieren, um unser Cluster in den Ausgangszustand vor der Installation zur\u00fcckzuversetzen. Dazu folgenden Command in der Kommandozeile eingeben:<\/p>\n<pre>$ helm -n demo uninstall my-nextcloud\r\nrelease \"my-nextcloud\" uninstalled<\/pre>\n<p>Mit der Deinstallation des Charts werden alle erstellten Kubernetes Ressourcen vollst\u00e4ndig entfernt.<\/p>\n<p>&nbsp;<\/p>\n<div align=\"left\">\n<h2>Anwendungsbeispiel 2: Eigenes Helm Chart<\/h2>\n<\/div>\n<h3><span style=\"font-weight: 400\">Scenario<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Wir arbeiten in einem Unternehmen und haben die Aufgabe jeder Abteilung des Unternehmens zu erm\u00f6glichen eine eigene Website auf dem Kubernetes-Cluster bereitzustellen. Hierzu erstellen wir ein Helm Chart, welches unternehmensintern bereitgestellt wird.\u00a0<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Der Helm Chart<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Der folgende Helm Chart erstellt einen NGINX Server, welcher eine einfache HTML Website darstellt. Die Domain der Website und der Inhalt k\u00f6nnen dabei von der installierenden Person konfiguriert werden. So kann jede Abteilung mit demselben Helm Chart individuelle Webseiten bereitstellen.<\/span><\/p>\n<h4><span style=\"font-weight: 400\">Dateien:<\/span><\/h4>\n<pre><span style=\"font-weight: 400\">department-website-chart\/<\/span>\r\n<span style=\"font-weight: 400\">  app-chart\/<\/span>\r\n<span style=\"font-weight: 400\">    templates\/<\/span>\r\n<span style=\"font-weight: 400\">      configmap.yaml<\/span>\r\n<span style=\"font-weight: 400\">      deployment.yaml<\/span>\r\n<span style=\"font-weight: 400\">      ingress.yaml<\/span>\r\n<span style=\"font-weight: 400\">      service.yaml<\/span>\r\n<span style=\"font-weight: 400\">    Chart.yaml<\/span>\r\n<span style=\"font-weight: 400\">    values.yaml<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Ein Helm Chart besteht immer aus einer <code>Chart.yaml<\/code>, einer <code>values.yaml<\/code> und mehreren Template-Files.\u00a0<\/span><\/p>\n<p><b>Charts.yaml<\/b><\/p>\n<pre><span style=\"font-weight: 400\">apiVersion: v2<\/span>\r\n<span style=\"font-weight: 400\">name: bis-app<\/span>\r\n<span style=\"font-weight: 400\">description: sample nginx deployment<\/span>\r\n<span style=\"font-weight: 400\">type: application<\/span>\r\n<span style=\"font-weight: 400\">version: 1.0<\/span>\r\n<span style=\"font-weight: 400\">appVersion: 1.0<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Hier sind die Meta-Informationen des Helm Charts festgehalten, wie Name und Version unseres Charts.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Weitere Infos: https:\/\/helm.sh\/docs\/topics\/charts\/#the-chartyaml-file<\/span><\/p>\n<h2><\/h2>\n<p><b>values.yaml<\/b><\/p>\n<pre>host: department1.local\r\ndepartment: \"department1\"\r\nmessage: \"Welcome on our website!\"\r\nreplicas: 1<\/pre>\n<p><span style=\"font-weight: 400\">Hier werden alle variablen Konfigurationen unseres Helm Charts mit zugeh\u00f6rigen Default-Werten festgehalten. Die hier aufgelisteten Parameter k\u00f6nnen beim Installieren und beim Upgraden des Helm Charts f\u00fcr den entsprechenden Use-Case \u00fcberschrieben werden.<\/span><\/p>\n<p><b>templates\/configmap.yaml<\/b><\/p>\n<pre><span style=\"font-weight: 400\">apiVersion: v1<\/span>\r\n<span style=\"font-weight: 400\">kind: ConfigMap<\/span>\r\n<span style=\"font-weight: 400\">metadata:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0name: {{ .Release.Name }}-nginx-config<\/span>\r\n<span style=\"font-weight: 400\">data:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0nginx.conf: |<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0events {<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0worker_connections\u00a0 1024;<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0http {<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0server {<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0listen 80;<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0location \/ {<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return 200 \"Greeting from Department {{ .Values.department }}! {{ .Values.message }}\";<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0}<\/span>\r\n<span style=\"font-weight: 400\">\u00a0\u00a0\u00a0\u00a0}<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Die Templates im Ordner <\/span><em><span style=\"font-weight: 400\">templates<\/span><\/em><span style=\"font-weight: 400\"> enthalten die jeweiligen Kubernetes Ressources, welche durch den Helm Chart angelegt werden.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Eine ConfigMap ist ein Kubernetes-Objekt, welches Konfigurationen beinhaltet, die von anderen Kubernetes-Objekten genutzt werden k\u00f6nnen.<\/span><\/p>\n<p><span style=\"font-weight: 400\">In diesem Beispiel benutzen wir die ConfigMap f\u00fcr unsere NGINX Konfiguration.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Mit <\/span><span style=\"font-weight: 400\"><code>{{ .Values.department }}<\/code><\/span><span style=\"font-weight: 400\"> und\u00a0 <\/span><span style=\"font-weight: 400\"><code>{{ .Values.message }}<\/code><\/span><span style=\"font-weight: 400\"> greifen wir hier auf die Werte unserer Eintr\u00e4ge aus der <\/span><span style=\"font-weight: 400\"><code>values.yaml<\/code><\/span><span style=\"font-weight: 400\"> zu. Beim Installieren werden die vom Nutzer festgelegten Values (bzw. die Default-Values vom Nutzer nicht \u00fcberschrieben) an die entsprechenden Stellen eingesetzt.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Neben den values k\u00f6nnen noch auf weitere Werte zur\u00fcckgegriffen werden, wie z.B. <\/span><span style=\"font-weight: 400\"><code>{{ .Release.Name }}<\/code><\/span><span style=\"font-weight: 400\"> welches uns den bei der Installation festgelegten Namen der Installation zur\u00fcckgibt.<\/span><\/p>\n<p><b>deployment.yaml<\/b><\/p>\n<pre><span style=\"font-weight: 400\">apiVersion: apps\/v1<\/span>\r\n<span style=\"font-weight: 400\">kind: Deployment<\/span>\r\n<span style=\"font-weight: 400\">metadata:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0name: {{ .Release.Name }}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0labels:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0app: {{ .Release.Name }}<\/span>\r\n<span style=\"font-weight: 400\">spec:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0replicas: {{ .Values.replicas }}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0selector:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0matchLabels:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0app: {{ .Release.Name }}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0strategy:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0type: RollingUpdate<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0rollingUpdate:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0maxUnavailable: 1<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0maxSurge: 1<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0template:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0metadata:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0labels:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0app: {{ .Release.Name }}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0annotations:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0checksum\/config: {{ include (print $.Template.BasePath \"\/configmap.yaml\") . | sha256sum }}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0checksum\/values: {{ printf \"%s-%s\" .Values.department .Values.message | sha256sum }}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0spec:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0containers:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0- name: {{ .Release.Name }}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0image: nginx:stable<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ports:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0- containerPort: 80<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0volumeMounts:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0- name: config<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0mountPath: \/etc\/nginx\/nginx.conf<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0subPath: nginx.conf<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0volumes:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0- name: config<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0configMap:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0name: {{ .Release.Name }}-nginx-config<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Die Deployment Kubernetes-Ressource beschreibt wie der Pod welcher unseren NGINX Container ausf\u00fchrt aussehen soll und wie h\u00e4ufig er bereitgestellt werden soll. Hier wird die zuvor definierte ConfigMap verwendet, um die NGINX Konfiguration als <\/span><span style=\"font-weight: 400\"><code>nginx.conf<\/code><\/span><span style=\"font-weight: 400\">Datei in dem Container zu erstellen.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Weitere Infos zu Deployments in der <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/workloads\/controllers\/deployment\/\">Kubernetes Dokumentation<\/a>.<\/span><\/p>\n<h2><\/h2>\n<p><b>service.yaml<\/b><\/p>\n<pre><span style=\"font-weight: 400\">apiVersion: v1<\/span>\r\n<span style=\"font-weight: 400\">kind: Service<\/span>\r\n<span style=\"font-weight: 400\">metadata:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0name: {{ .Release.Name }}-service<\/span>\r\n<span style=\"font-weight: 400\">spec:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0type: ClusterIP<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0selector:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0app: {{ .Release.Name }}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0ports:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0- protocol: \"TCP\"<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0port: 80<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0targetPort: 80<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Die Service Kubernetes-Ressource erm\u00f6glicht es, innerhalb des Clusters mit den in der <code>deployment.yaml<\/code> definierten Pods zu kommunizieren.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">Weitere Infos zu Services in der <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/service\/\">Kubernetes Dokumentation<\/a><\/span><span style=\"font-weight: 400\">.<\/span><\/p>\n<p><b>ingress.yaml<\/b><\/p>\n<pre><span style=\"font-weight: 400\">apiVersion: networking.k8s.io\/v1<\/span>\r\n<span style=\"font-weight: 400\">kind: Ingress<\/span>\r\n<span style=\"font-weight: 400\">metadata:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0name: {{ .Release.Name }}-ingress<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0annotations:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0nginx.ingress.kubernetes.io\/rewrite-target: \/$1<\/span>\r\n<span style=\"font-weight: 400\">spec:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0rules:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0- host: {{ .Values.host }}<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0http:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0paths:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0- path: \/<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0pathType: Prefix<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0backend:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0service:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0name: {{ .Release.Name }}-service<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0port:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0number: 80<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Der Ingress beschreibt eine Route, \u00fcber die von extern auf den zuvor definierten Service zugegriffen werden kann. Ein Ingress-Controller sammelt alle Ingress-Ressourcen in einem Cluster und leitet eingehende Anfragen anhand dieser Regeln weiter.<\/span><\/p>\n<p><span style=\"font-weight: 400\">In unserem Fall sagen wir, dass alle Anfragen an den Host, welcher in der <code>values.yaml<\/code> hinterlegt ist (\u00fcber <\/span><span style=\"font-weight: 400\">host: <code>{{ .Values.host }}<\/code><\/span><span style=\"font-weight: 400\">), an den Service, den wir in <\/span><span style=\"font-weight: 400\"><code>templates\/service.yaml<\/code><\/span><span style=\"font-weight: 400\"> definiert haben, weitergeleitet werden.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">Weitere Infos zu Ingress und Ingress-Controllern in der <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress\/\">Kubernetes Dokumentation<\/a><\/span><span style=\"font-weight: 400\">.<\/span><\/p>\n<p>&nbsp;<\/p>\n<h3><strong>Helm Chart bereitstellen<\/strong><\/h3>\n<p><span style=\"font-weight: 400\">Damit der Helm Chart von den Abteilungen unseres Unternehmens genutzt werden kann, m\u00fcssen wir diesen den Helm Chart zun\u00e4chst bereitstellen.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Hierzu erstellen wir zun\u00e4chst einen neuen Ordner <\/span><span style=\"font-weight: 400\"><code>charts<\/code><\/span><\/p>\n<pre><span style=\"font-weight: 400\">department-website-chart\/<\/span>\r\n<span style=\"font-weight: 400\">  app-chart\/<\/span>\r\n<span style=\"font-weight: 400\">    \u2026<\/span>\r\n<strong>  charts\/<\/strong><\/pre>\n<p><span style=\"font-weight: 400\">In diesem Ordner f\u00fchren wir in der Konsole folgenden Befehl aus:<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ helm package app-chart -d charts<\/span>\r\n<span style=\"font-weight: 400\">Successfully packaged chart and saved it to: charts\/bis-app-1.tgz<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Die erstellte Datei <\/span><span style=\"font-weight: 400\"><code>bis-app-1.tgz<\/code><\/span><span style=\"font-weight: 400\"> (die 1 im Namen ist die Version des Charts) enth\u00e4lt den gesamten Helm Chart und kann so nun an einzelne Personen im Unternehmen verteilt werden.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">Gehen wir davon aus, wir haben unser Helm Chart erweitert. Dann erh\u00f6hen wir die Version des Charts in der <code>Charts.yaml<\/code>\u00a0Datei, z.B. auf 1.1 (<\/span><span style=\"font-weight: 400\">version: 1.1<\/span><span style=\"font-weight: 400\">). Nun m\u00fcssen wir den Chart erneut packen.<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ helm package app-chart -d charts<\/span>\r\n<span style=\"font-weight: 400\">Successfully packaged chart and saved it to: charts\/bis-app-1.1.tgz<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Diese neu erstellte Datei m\u00fcssten wir nun erneut an alle Personen im Unternehmen verteilen, welche bereits eine fr\u00fchere Chart Version installiert haben. Diese manuelle Verteilung des Charts ist jedoch unpraktisch und sorgt daf\u00fcr, dass alte Chart Versionen eventuell nicht geupdatet werden. Auch bei der Verwendung von CI\/CD ist ein manuelles Verteilen der Releases nicht m\u00f6glich. Daher m\u00f6chten wir uns Helm-Repositories als eine bessere L\u00f6sung anschauen, um Charts bereitzustellen.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Hierzu indizieren wir zun\u00e4chst den <code>chart<\/code> Ordner<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ helm repo index charts<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Wir erhalten die Datei <\/span><span style=\"font-weight: 400\"><code>charts\/index.yaml<\/code><\/span><\/p>\n<h2><\/h2>\n<pre><span style=\"font-weight: 400\">apiVersion: v1<\/span>\r\n<span style=\"font-weight: 400\">entries:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0bis-app:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0- apiVersion: v2<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0appVersion: \"1\"<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0created: \"2024-01-23T13:46:16.938718324+01:00\"<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0description: sample nginx deployment<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0digest: c964f1a73aa1920286359578496a52341b77d4d226ad32cd6dfdb421c59fd4cb<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0name: bis-app<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0type: application<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0urls:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0- bis-app-1.1.tgz<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0version: \"1.1\"<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0- apiVersion: v2<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0appVersion: \"1\"<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0created: \"2024-01-23T13:46:16.939021608+01:00\"<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0description: sample nginx deployment<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0digest: 552c9bdf46b657dae607483912088d245c0a11b34a4ae35644c9a863ae61b10b<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0name: bis-app<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0type: application<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0urls:<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0- bis-app-1.tgz<\/span>\r\n<span style=\"font-weight: 400\"> \u00a0\u00a0\u00a0version: \"1\"<\/span>\r\n<span style=\"font-weight: 400\">generated: \"2024-01-23T13:46:16.938178662+01:00\"<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Diese Datei listet alle gepackten Helm Charts in Ordner <\/span><span style=\"font-weight: 400\"><code>charts<\/code><\/span><span style=\"font-weight: 400\"> inklusive deren Metainformation auf.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Der Ordner <\/span><span style=\"font-weight: 400\"><code>charts<\/code><\/span><span style=\"font-weight: 400\"> kann nun mit einem beliebigen Webserver bereitgestellt und direkt als Helm Repository verwendet werden. Als schnelle und einfache M\u00f6glichkeit, Dateien \u00fcber einen Webserver bereitzustellen, nutzen wir f\u00fcr das Beispiel Github-Pages.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Hierzu muss der Ordner in ein Github-Repository gepusht werden und f\u00fcr das Repository <a href=\"https:\/\/docs.github.com\/en\/pages\/getting-started-with-github-pages\/creating-a-github-pages-site\">Github-Pages aktiviert werden<\/a>.<br \/>\n<\/span><\/p>\n<p><span style=\"font-weight: 400\">Ob euer Helm Repository erreichbar ist k\u00f6nnt ihr \u00fcberpr\u00fcfen, indem ihr versucht die <code>index.yaml<\/code> Datei von eurer Github-Page anzufragen:<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ curl https:\/\/&lt;Username&gt;.github.io\/&lt;repository&gt;\/charts\/index.yaml<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Da die Github Page \u00f6ffentlich erreichbar ist, sind auch die Helm Charts \u00f6ffentlich erreichbar. Unternehmensintern m\u00fcsste der Webserver entweder durch Zugangsdaten abgesichert werden oder nur aus dem internen Netz erreichbar sein.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Chart installieren<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Nun wollen wir den erstellten Helm Chart \u00fcber das eigene Repository installieren. Hierzu m\u00fcssen wir das neu erstellte Repository zun\u00e4chst lokal hinterlegen.<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ helm repo add bis-repo https:\/\/&lt;Username&gt;.github.io\/&lt;repository&gt;\/charts\/<\/span>\r\n<span style=\"font-weight: 400\">\"bis-repo\" has been added to your repositories<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Mit dem folgenden Befehl kann \u00fcberpr\u00fcft werden, welche Repositories lokal hinterlegt sind:<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ helm repo list<\/span>\r\n<span style=\"font-weight: 400\">NAME\u00a0 \u00a0 <\/span> <span style=\"font-weight: 400\">URL\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <\/span>\r\n<span style=\"font-weight: 400\">bis-repo<\/span> <span style=\"font-weight: 400\">https:\/\/&lt;Username&gt;.github.io\/&lt;repository&gt;\/charts\/<\/span><\/pre>\n<h2><\/h2>\n<p><span style=\"font-weight: 400\">Mit dem hinterlegten Repository k\u00f6nnen wir nun einen Namespace erstellen und unser Helm Chart dort installieren:<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ kubectl create ns bis<\/span>\r\n<span style=\"font-weight: 400\">namespace\/bis created\r\n<\/span>\r\n<span style=\"font-weight: 400\">$ helm install bis bis-repo\/bis-app -n bis<\/span>\r\n<span style=\"font-weight: 400\">NAME: bis<\/span>\r\n<span style=\"font-weight: 400\">LAST DEPLOYED: Tue Jan 23 14:09:25 2024<\/span>\r\n<span style=\"font-weight: 400\">NAMESPACE: bis<\/span>\r\n<span style=\"font-weight: 400\">STATUS: deployed<\/span>\r\n<span style=\"font-weight: 400\">REVISION: 1<\/span>\r\n<span style=\"font-weight: 400\">TEST SUITE: None<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Der <code>install<\/code> Befehl ist wie folgt aufgebaut <\/span><\/p>\n<div align=\"left\"><span style=\"font-weight: 400\"><code>helm install &lt;release-name&gt; &lt;repo&gt;\/&lt;chart&gt;[:&lt;chart-version&gt;] -n &lt;kubernetes-namespace&gt;<\/code><\/span><\/div>\n<p><span style=\"font-weight: 400\">Wenn wir nun die einzelnen Kubernetes Ressourcen ausgeben, sehen wir, dass alles im Helm Chart Definierte erstellt wurde. Hier als Beispiel einmal die erstellten Pods und der Ingress.<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ kubectl get pod -n bis<\/span>\r\n<span style=\"font-weight: 400\">NAME \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 READY \u00a0 STATUS\u00a0 \u00a0 RESTARTS \u00a0 AGE<\/span>\r\n<span style=\"font-weight: 400\">bis-6ff46c7499-24bgx \u00a0 1\/1 \u00a0 \u00a0 Running \u00a0 0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 2m17s\r\n<\/span>\r\n<span style=\"font-weight: 400\">$ kubectl get ingress -n bis<\/span>\r\n<span style=\"font-weight: 400\">NAME\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 CLASS \u00a0 HOSTS \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ADDRESS\u00a0 \u00a0 \u00a0 \u00a0 PORTS \u00a0 AGE<\/span>\r\n<span style=\"font-weight: 400\">bis-ingress \u00a0 nginx \u00a0 department1.local \u00a0 192.168.58.2 \u00a0 80\u00a0 \u00a0 \u00a0 3m50s<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Wenn wir nun die Website <code>department1.local<\/code> aufrufen, bekommen wir folgende Antwort.<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ curl department1.local<\/span>\r\n<span style=\"font-weight: 400\">Greeting from Department department1! Welcome on our website!<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Die angezeigte Nachricht k\u00f6nnen wir nun durch \u00dcberschreiben einiger Values unseres Helm Releases anpassen:<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ helm upgrade bis bis-repo\/bis-app -n bis --set message=\"Greetings to BIS!\" --set replicas=3<\/span>\r\n<span style=\"font-weight: 400\">Release \"bis\" has been upgraded. Happy Helming!<\/span>\r\n<span style=\"font-weight: 400\">NAME: bis<\/span>\r\n<span style=\"font-weight: 400\">LAST DEPLOYED: Tue Jan 23 14:20:55 2024<\/span>\r\n<span style=\"font-weight: 400\">NAMESPACE: bis<\/span>\r\n<span style=\"font-weight: 400\">STATUS: deployed<\/span>\r\n<span style=\"font-weight: 400\">REVISION: 2<\/span>\r\n<span style=\"font-weight: 400\">TEST SUITE: None<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Einerseits haben wir die Replicas auf 3 gesetzt. Dadurch wurden anstelle nur eines Pods nun drei Pods gestartet.<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ kubectl get pods -n bis<\/span>\r\n<span style=\"font-weight: 400\">NAME \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 READY \u00a0 STATUS\u00a0 \u00a0 RESTARTS \u00a0 AGE<\/span>\r\n<span style=\"font-weight: 400\">bis-6d6549c7fb-b9wnh \u00a0 1\/1 \u00a0 \u00a0 Running \u00a0 0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 37s<\/span>\r\n<span style=\"font-weight: 400\">bis-6d6549c7fb-nb68f \u00a0 1\/1 \u00a0 \u00a0 Running \u00a0 0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 39s<\/span>\r\n<span style=\"font-weight: 400\">bis-6d6549c7fb-z75j4 \u00a0 1\/1 \u00a0 \u00a0 Running \u00a0 0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 40s<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Des Weiteren haben wir die Nachricht, welche vom Webserver zur\u00fcckgegeben wird, angepasst.<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ curl department1.local<\/span>\r\n<span style=\"font-weight: 400\">Greeting from Department department1! Greetings to BIS!<\/span><\/pre>\n<p><b>Zweite Abteilung<\/b><\/p>\n<p><span style=\"font-weight: 400\">Jetzt wollen wir das Gleiche noch einmal f\u00fcr eine zweite Abteilung in unserem Unternehmen umsetzen. Diese soll ebenfalls eine eigene Website bekommen, welche auf demselben Kubernetes Cluster l\u00e4uft.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Hierzu erstellen wir zun\u00e4chst eine neue Datei <code>department2-values.yaml<\/code> welche die Konfiguration f\u00fcr unser Helm Release beinhaltet.<\/span><\/p>\n<pre><span style=\"font-weight: 400\">host: department2.local<\/span>\r\n<span style=\"font-weight: 400\">department: \"department2\"<\/span>\r\n<span style=\"font-weight: 400\">replicas: 2<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Dann erstellen wir einen neuen Namespace und installieren den Chart f\u00fcr unsere <em>Abteilung2<\/em>.<\/span><\/p>\n<h2><\/h2>\n<pre><span style=\"font-weight: 400\">$ kubectl create ns bis2<\/span>\r\n<span style=\"font-weight: 400\">namespace\/bis2 created\r\n<\/span>\r\n<span style=\"font-weight: 400\">$ helm install bis bis-repo\/bis-app -n bis2 -f department2-values.yaml<\/span>\r\n<span style=\"font-weight: 400\">NAME: bis<\/span>\r\n<span style=\"font-weight: 400\">LAST DEPLOYED: Tue Jan 23 14:27:25 2024<\/span>\r\n<span style=\"font-weight: 400\">NAMESPACE: bis2<\/span>\r\n<span style=\"font-weight: 400\">STATUS: deployed<\/span>\r\n<span style=\"font-weight: 400\">REVISION: 1<\/span>\r\n<span style=\"font-weight: 400\">TEST SUITE: None<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Wir k\u00f6nnen nun beide Webseiten aufrufen.<\/span><\/p>\n<pre><span style=\"font-weight: 400\">$ curl department1.local<\/span>\r\n<span style=\"font-weight: 400\">Greeting from Department department1! Greetings to BIS!\r\n<\/span>\r\n<span style=\"font-weight: 400\">$ curl department2.local<\/span>\r\n<span style=\"font-weight: 400\">Greeting from Department department2! Welcome on our website!\r\n\r\n<\/span><\/pre>\n<p><span style=\"font-weight: 400\">Abschlie\u00dfend k\u00f6nnen wir uns von Helm noch einmal alle aktuell installierten Helm Charts anzeigen lassen<\/span><\/p>\n<pre>$ helm ls -A\r\nNAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION\r\nbis bis 2 2024-01-23 14:20:55.470634413 +0100 CET deployed bis-app-1.1 1.1 \r\nbis bis2 1 2024-01-23 14:27:25.781652628 +0100 CET deployed bis-app-1.1 1.1<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p align=\"justify\"><span style=\"font-size: x-large\"><b>Fazit<br \/>\n<\/b><\/span><\/p>\n<p align=\"justify\">Anhand des ersten Anwendungsbeispiels, bei dem das \u00f6ffentlich zug\u00e4ngliche Helm Chart von Nextcloud auf einem Kubernetes Cluster installiert wurde, lassen sich einige der Vorteile, die Helm bietet, erkennen. Die Installation eines Charts entspricht dem geb\u00fcndelten Deployment von Kubernetes Ressourcen. Im Gegensatz zur herk\u00f6mmlichen Interaktion mit einem Cluster m\u00fcssen die Kubernetes Ressourcen nicht einzeln h\u00e4ndisch angelegt werden, sondern k\u00f6nnen \u00fcber einen einzigen Helm Command schnell und einfach auf das Cluster gebracht werden. Das Gleiche gilt f\u00fcr den Vorgang des L\u00f6schens eines Releases bei dem alle von Helm angelegten Ressourcen geb\u00fcndelt gel\u00f6scht werden. Des Weiteren kann man am ersten Anwendungsbeispiel erkennen, dass der Anwender zu keinem Zeitpunkt dazu gezwungen war, direkt mit dem Kubernetes Cluster zu interagieren. Helm schafft mit seiner Nutzerschnittstelle ein Abstraktionslevel, das den internen Aufbau und die Funktionsweise von Kubernetes vor dem Anwender versteckt. Den Entwicklern von Helm war es wichtig, dass sich Helm sowohl an mit der Funktionsweise von Kubernetes vertraute Anwender als auch an solche richtet, die \u00fcber wenig bis kaum Erfahrung und technisches Wissen im Bereich von Kubernetes verf\u00fcgen.<\/p>\n<p align=\"justify\">Am zweiten Anwendungsbeispiel kann man erkennen, dass Helm die Abdeckung verschiedener Anwendungsf\u00e4lle mit nur einem Chart erm\u00f6glicht, wodurch die Notwendigkeit f\u00fcr neue Charts entf\u00e4llt. Wir konnten problemlos zwei Webserver f\u00fcr unterschiedliche Abteilungen erstellen, indem wir lediglich Konfigurationsparameter anpassten, ohne den Code \u00e4ndern zu m\u00fcssen. Ein entscheidender Vorteil von Helm liegt zudem in seiner F\u00e4higkeit, das installierte Chart zusammen mit seiner Version auf dem Cluster zu dokumentieren. Dadurch wird eine umfassende Versionsverwaltung gew\u00e4hrleistet, die Transparenz \u00fcber den aktuellen Stand sowie potenzielle \u00c4nderungen mit einem Update oder zwischen den Deployments schafft. Diese Dokumentation erm\u00f6glicht eine klare Nachvollziehbarkeit jeder Chart Version. Des Weiteren erleichtert Helm die Reproduzierbarkeit eines bestimmten Zustands erheblich, da sowohl die Konfiguration als auch der Status des Charts als Code gespeichert werden k\u00f6nnen. Dadurch wird eine konsistente Bereitstellung und Verwaltung von Anwendungen gew\u00e4hrleistet, was wiederum die Zuverl\u00e4ssigkeit und Effizienz der Entwicklungs- und Betriebsprozesse verbessert.<\/p>\n<p align=\"justify\">Es l\u00e4sst sich festhalten, dass das Deployment von Charts \u00fcber Helm gro\u00dfe Vorteile bietet. Helm tr\u00e4gt wesentlich dazu bei, Anwendungen auf Kubernetes Clustern einfach und schnell zur Verf\u00fcgung zu stellen und spielt damit im Bereich der betrieblichen Informationssysteme eine nicht unwesentliche Rolle.<\/p>\n<\/div>\n<div align=\"justify\">\n<h2><\/h2>\n<h2>Einzelnachweise<\/h2>\n<ol style=\"font-weight: 400\">\n<li data-charcodes=\"65533,0,46\" data-buautonum=\"8\" data-margin=\"720\" data-aria-posinset=\"1\" data-aria-level=\"1\"><i><span data-usefontface=\"true\" data-contrast=\"none\">Was ist\u00a0<\/span><\/i><i><span data-usefontface=\"true\" data-contrast=\"none\">Kubernetes<\/span><\/i><i><span data-usefontface=\"true\" data-contrast=\"none\">?<\/span><\/i><span data-usefontface=\"true\" data-contrast=\"none\">\u00a0(2022, 17. Juli).\u00a0<\/span><span data-usefontface=\"true\" data-contrast=\"none\">Kubernetes<\/span><span data-usefontface=\"true\" data-contrast=\"none\">.\u00a0<\/span><a href=\"https:\/\/kubernetes.io\/de\/docs\/concepts\/overview\/what-is-kubernetes\/\"><span data-usefontface=\"true\" data-contrast=\"none\">https:\/\/kubernetes.io\/de\/docs\/concepts\/overview\/what-is-kubernetes\/<\/span><\/a>\u200b<\/li>\n<li data-charcodes=\"65533,0,46\" data-buautonum=\"8\" data-margin=\"720\" data-aria-posinset=\"2\" data-aria-level=\"1\"><i><span data-usefontface=\"true\" data-contrast=\"none\">Helm | Helm<\/span><\/i><span data-usefontface=\"true\" data-contrast=\"none\">. (o.\u00a0D.).\u00a0<\/span><a href=\"https:\/\/helm.sh\/\"><span data-usefontface=\"true\" data-contrast=\"none\">https:\/\/helm.sh\/<\/span><\/a>\u200b<\/li>\n<li data-charcodes=\"65533,0,46\" data-buautonum=\"8\" data-margin=\"720\" data-aria-posinset=\"3\" data-aria-level=\"1\"><i><span data-usefontface=\"true\" data-contrast=\"none\">Helm | Docs Home<\/span><\/i><span data-usefontface=\"true\" data-contrast=\"none\">. (o.\u00a0D.).\u00a0<\/span><a href=\"https:\/\/helm.sh\/docs\/\"><span data-usefontface=\"true\" data-contrast=\"none\">https:\/\/helm.sh\/docs\/<\/span><\/a>\u200b<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Helm.sh In der Welt der Containerorchestrierung ist effizientes Deployment entscheidend. Der Paket-Manager Helm selbst bezeichnet sich als: &#8222;Der beste Weg,<\/p>\n","protected":false},"author":160,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-3368","post","type-post","status-publish","format-standard","hentry","category-betriebliche-informationssysteme"],"_links":{"self":[{"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/posts\/3368","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/users\/160"}],"replies":[{"embeddable":true,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/comments?post=3368"}],"version-history":[{"count":38,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/posts\/3368\/revisions"}],"predecessor-version":[{"id":3465,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/posts\/3368\/revisions\/3465"}],"wp:attachment":[{"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/media?parent=3368"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/categories?post=3368"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/informatik.htwk-leipzig.de\/seminar\/wp-json\/wp\/v2\/tags?post=3368"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}