Private Kubernetes-Cluster in der Azure Public Cloud – Teil 3: Continuous Deployment

Private Cluster = private Applikationen?

Dies ist der dritte Teil der Artikelreihe zum Thema „Private Kubernetes-Cluster in der Azure Public Cloud“. Nachdem wir uns in Teil 1 mit der Architektur und in Teil 2 mit der Bereitstellung der Infrastruktur beschäftigt haben, widmen wir uns in diesem Teil den Applikationen, die wir in unseren privaten AKS-Cluster ausliefern und betreiben wollen. Dabei müssen wir beachten, dass der Kubernetes API-Server ausschließlich über einen privaten Endpunkt erreichbar ist.

Zunächst sollte klargestellt werden, dass die Erreichbarkeit des API-Servers unabhängig von der Zugänglichkeit der Applikationen im Cluster ist. Auch wenn der Kubernetes API-Server ausschließlich über einen privaten Endpunkt erreichbar ist, können die Applikationen öffentlich verfügbar sein. Das nachfolgende Schaubild zeigt eine mögliche Architektur, in der eine Applikation über zwei unterschiedliche Wege zugänglich ist. Während Entwickler über eine private Verbindung (orange markiert) auf die Applikation zugreifen, nutzen Endnutzer einen öffentlichen Weg (grün markiert). Für die Domain „myapp.com“ gibt es eine öffentliche und eine private DNS-Zone („Split-DNS“).

Schematische Darstellung eines Zugriffs auf eine Applikation. Dabei werden unterschiedliche Bereiche durch farbliche Kästen mit gestrichelten Linien abgegrenzt
Abb. 1: Zugriff auf eine Applikation über unterschiedliche Wege in Abhängigkeit vom netzwerktechnischen Standort der Person

Bevor wir uns jedoch um die Erreichbarkeit der Applikation(en) über öffentliche oder private Netzwerke Gedanken machen, gehen wir in diesem Teil der Artikelreihe zunächst einen Schritt zurück und stellen uns die Frage: Wie kann eine Applikation in einem privaten Cluster bereitgestellt werden?

Inwieweit auch private Endpunkte für die Applikationen im AKS-Cluster genutzt werden können, schauen wir uns im nachfolgenden Teil näher an.

Continuous Delivery mit Azure DevOps

Sofern unsere Applikation kontinuierlich weiterentwickelt wird und regelmäßig neue Versionen erscheinen, sollte der Bereitstellungsprozess automatisiert werden („Continuous Delivery“ oder „Continuous Deployment“). Die Bereitstellung einer Applikation läuft meist nach folgendem Schema ab:

  1. Es wird ein Ereignis/Event ausgelöst. Dieses Ereignis kann beispielsweise eine Veränderung eines Git-Branches, ein Pull-Request oder auch eine manuelle Aktion eines Benutzers sein.
  2. Das Ereignis löst eine oder mehrere Aktionen aus.
  3. Die Aktionen werden auf einem dafür vorgesehenen System ausgeführt.

Der Bereitstellungsprozess wird somit nicht durch eine natürliche Person auf einer persönlichen Workstation, sondern durch eine technische Identität auf einem dafür vorgesehenen System ausgeführt.

In dieser Artikelreihe fokussieren wir uns auf das Produkt „Azure DevOps“ aus dem Hause Microsoft als Tool für die Automatisierung der Bereitstellung von Applikationen. In diesem Kontext wird das zuvor be-schriebene System als „Agent“ bezeichnet. Die grundsätzliche Vorgehensweise ähnelt der Nutzung anderer Tools wie GitHub oder GitLab jedoch stark. Die Nutzung anderer Methodiken und Tools wird im letzten Abschnitt dieses Artikels kurz angesprochen.

Schematische Darstellung einzelner Schritte in der CI/CD-Pipeline in schwarz/weiß.
Abb. 2: Continuous Integration (CI) und Continuous Deployment (CD) (Quelle: Microsoft Learn)

Pipeline Jobs und Tasks

Der Bereitstellungsprozess setzt sich aus mehreren Schritten zusammen, die in Azure DevOps als „Steps“ oder „Tasks“ definiert werden. Schritte, die sequenziell abgearbeitet werden müssen, können zu „Jobs“ zusammengefasst werden. Jobs, zwischen denen keine Abhängigkeiten bestehen, können parallel ausgeführt werden. Jobs werden wiederum zu Pipelines zusammengeschlossen. Eine Pipeline beinhaltet somit mindestens einen Job mit mindestens einem Task. Das Ziel der Ausführung der Pipelines ist in unserem Fall, dass die Applikation in unserem AKS-Cluster läuft und voll funktionsfähig ist.

Azure Pipeline Agents

Für die Bereitstellung der Applikation benötigen wir einen oder mehrere „Pipeline Agents“. Ein Agent ist ein System, das alle Anforderungen für die Ausführung von automatisierten Prozessen erfüllt. Dies ist in diesem Fall die Bereitstellung einer Applikation in Kubernetes. Zu diesen Anforderungen zählen beispielsweise Rechenleistung und Speicherkapazität für die Ausführung der Pipelines und das Vorhandensein von verschie-denen Softwarepaketen.

Folgende Voraussetzung muss in unserem Fall darüber hinaus immer erfüllt werden: Der Agent benötigt Zugriff auf den privaten Endpunkt der Kubernetes API, um Applikationen bereitstellen zu können. Grund-sätzlich bietet Azure DevOps zwei Optionen für das Hosting der Agents, die wir uns nachfolgend näher ansehen. Wir können die Agents entweder von Microsoft hosten lassen oder selbst hosten.

Von Microsoft gehostete Agents

Von Microsoft gehostete Agents werden bei Bedarf – also sobald ein Job ausgeführt werden soll – durch Microsoft bereitgestellt und nach Abschluss des Jobs wieder deprovisioniert. Der Vorteil liegt in dem reduzierten Aufwand für die Verwaltung des Agents, da dieser zu Microsoft ausgelagert werden kann. Viele Softwarepakete sind bereits vorinstalliert. Je nach Bedarf können weitere Softwarepakete als Teil einer Pipeline nachinstalliert werden.

Während der reduzierte Verwaltungsaufwand zwar einen Vorteil darstellt, haben wir in unserem Szenario jedoch folgendes Problem: Die Agents werden durch Microsoft betrieben und sind somit netzwerktechnisch von unseren Azure-Ressourcen getrennt. Es ist nicht möglich einen von Microsoft gehosteten Agent in ein eigenes virtuelles Netzwerk in Azure zu integrieren.

Daher gilt grundsätzlich: Sofern der API-Server privat ist, können von Microsoft gehostete Agents nicht für die Auslieferung von Software in den AKS-Cluster genutzt werden, da sie den privaten Endpunkt des API-Servers nicht erreichen können. Stattdessen müssen wir die Agents selbst bereitstellen und betreiben – in diesem Fall sprechen wir von selbst gehosteten Agents“.

Selbst gehostete Agents

Ein selbst gehosteter Agent basiert auf derselben Software wie ein von Microsoft gehosteter Agent, wir müssen diese jedoch auf einem eigenen System selbst installieren und betreiben. Das Hosting des Agents kann auf einer physischen oder virtuellen Maschine (VM) oder auch auf einem Container basieren. Die Agent-Software wird von Microsoft bereitgestellt und kann installiert oder zu einem Container Image hin-zugefügt werden.

Der Agent kann grundsätzlich in jedem Netzwerk platziert werden, von dem aus Verbindungen zu der API des AKS-Clusters möglich sind. Eine netzwerktechnisch einfache Methode ist es, den Agenten als Container in AKS zu betreiben oder in einem Subnetz des AKS-Netzwerks zu platzieren. So kann der Agent die API direkt erreichen. Alternativ kann dieser in einem dedizierten virtuellen Netzwerk in Azure platziert werden. Dieses Netzwerk muss dann mittels „Network Peering“ an das AKS-Netzwerk angebunden werden.

Der Agent kann aber auch bei einem anderen Cloud Provider oder in einem lokalen Unternehmensnetzwerk betrieben werden, solange Verbindungen zu dem virtuellen Netzwerk in Azure möglich sind (z. B. via VPN).

Managed Identity Authentifizierung

Sofern wir Agents in Azure betreiben und die Integration unseres AKS-Clusters in das Azure Active Directory bzw. Microsoft Entra IDhttps://learn.microsoft.com/en-us/azure/aks/enable-authentication-microsoft-entra-id aktiviert ist, bietet es sich an, sogenannte „Managed Identities“ für die Authentifi-zierung am Kubernetes API-Server und somit für die Bereitstellung von Applikationen im Cluster zu nutzen.

Screenshot aus dem Azure Resource Portal. Links sieht man einen Teil des Einstellungsmenüs, bei dem "Clusterkonfiguration" ausgewählt wurde. Rechts sieht man neben einem Beschreibungstext ein Drop-Down-Menü zur Authentifizierung und ein Auswahlfeld für lokale Kubernetes-Konten.
Abb. 3: Konfiguration der Entra ID-Integration von AKS im Azure-Portal

Hierfür können wir die jeweilige Identität auf den gesamten Cluster oder auf bestimmte Namespaces be-rechtigen. Die Berechtigung auf einzelne Namespaces ist jedoch aktuell noch nicht über das Azure Portal, sondern nur mit der Azure CLI oder anderen Tools, die die Azure Resource Manager API nutzen (z. B. Hashi-Corp Terraform), möglich (Stand: März 2024).

Sofern wir einen Agent beispielsweise auf einer virtuellen Maschine in Azure betreiben, können wir dieser VM eine „Managed Identity“ zuweisen. Diese kann entweder systemseitig oder benutzerseitig zugewiesen werden. Eine benutzerseitig zugewiesene Identität kann auch mehreren VMs zugewiesen werden.

Schematische Darstellung von zwei Pipeline-Agents mit einer gemeinsamen Managed Identity, von der zwei Pfeile zu zwei Rollenzuweisungen abgehen.
Abb. 4: Zwei Pipeline Agents mit einer gemeinsamen „Managed Identity“ und mehreren Rollenzuweisungen

Zur Nutzung dieser Authentifizierungsmethode muss in Azure DevOps eine Service Connection vom Typ „Azure Resource Manager“ mit der Authentifizierungsmethode „Managed Identity“ erstellt werden. Pipe-lines, die von einem selbst gehosteten Agent ausgeführt werden und diese Service Connection nutzen, können sich dann mit der „Managed Identity“ authentifizieren.

Screenshot aus dem Azure Resource Manager, das eine Liste an 5 Auswahlmethoden zur Authentifizierung zeigt.
Abb. 5: Authentifizierungsmethoden für Service Connections vom Typ „Azure Resource Manager“

Anschließend können wir eine Pipeline definieren. In dieser geben wir den Agent Pool an, zu dem wir unse-re selbstverwalteten Agents hinzugefügt haben. Außerdem definieren wir Tasks, beispielsweise basierend auf den integrierten Tasks für kubectl und Helm. In den Tasks geben wir die zuvor erstellte Service Connection an, um diese für die Bereitstellung der Applikation zu verwenden. Wir haben nun also eine Pipeline, über die wir Applikationen in unseren privaten AKS-Cluster ausrollen können.

Ausblick: GitOps als alternative Methodik

In diesem Artikel haben wir uns auf die Bereitstellung von Anwendungen mit Hilfe von Azure DevOps Pipelines fokussiert. An dieser Stelle soll eine etwas andere Methodik zumindest erwähnt werden: GitOps.

Diese Methodik wurde ursprünglich primär für Kubernetes entwickelt, kann aber auch in anderen Bereichen angewendet werden. Hierbei steht ebenfalls das Versionsverwaltungssystem Git im Mittelpunkt. Ein Repository dient als „single source of truth“, der gewünschte Zielzustand des Clusters (oder eines einzelnen Namespaces) wird also in Git gepflegt. Azure DevOps bzw. Azure Repos können also auch bei dieser Methodik eingesetzt werden.

Im Gegensatz zu der zuvor beschriebenen Vorgehensweise werden für die Bereitstellung von Applikationen keine Pipelines verwendet. Stattdessen werden in Kubernetes Software-Agenten betrieben, die den beschriebenen Zielzustand in Git mit dem tatsächlichen Zustand vergleichen. Sofern Unterschiede vorliegen, wird der Zustand des Clusters so angepasst, dass dieser dem Zielzustand entspricht. Genehmigte Änderungen (Pull Requests) werden somit automatisch auf den Kubernetes-Cluster angewendet.

Um den Rahmen dieses Artikels nicht zu sprengen, verweisen wir an dieser Stelle auf unseren Podcast „Focus on DevOps“. Bei Interesse geben wir Ihnen in der Folge „E30 – GitOps“ weitere Einblicke in die GitOps-Methodik.

Zusammenfassung

In diesem Teil der Artikelreihe haben wir betrachtet, was bei der Auslieferung von Applikationen in einen privaten AKS-Cluster beachtet werden muss. Entscheidend ist hierbei, dass das System, welches den Auslieferungsprozess ausführt, den Kubernetes API-Server erreichen kann. Sofern sich das System nicht innerhalb des Clusters befindet, muss also für Netzwerkkonnektivität zwischen dem System und dem virtuellen Netzwerk in Azure gesorgt werden.

Auch die Applikationen können über private Endpunkte zugänglich gemacht werden, sodass der Zugriff aus dem Internet nicht möglich ist. Hierauf werden wir im nächsten Teil der Artikelreihe näher eingehen.