Eine Einrichtung für die Arbeit mit Windows-Build-Slaves
Sami Alajrami
Sami is a DevOps consultant in our Oslo office. He comes from Palestine and has a PhD in Computing Science from Newcastle University. Sami’s previous work focused on cloud-based software development, model-based engineering, and safety-critical systems. He’s also an INTJ.
Die Installation und Verwaltung von CI-Servern ist eine zentrale Aufgabe für jedes IT-Team. Kubernetes und sein Paketmanager Helm bieten eine einfache Möglichkeit, Jenkins-Installationen anzupassen. Sehen wir uns an, wie das funktioniert und wie sich Windows-Build-Slaves hinzufügen lassen.
Container-Lösungen (z. B. Docker) ermöglichen es euren Entwicklern, Anwendungen zu entwickeln und für Tests oder Deployments bereitzustellen, ohne sich um die Einrichtung der Umgebung kümmern oder mit dem Phänomen „funktioniert-auf-meinem-Rechner“ konfrontiert werden zu müssen.
Kubernetes (auch k8s genannt) stellt ein Orchestrierungs-Framework für containerisierte Anwendungen bereit. Dieses Framework gewährleistet durch Zustandsüberwachung und die Wiederherstellung fehlgeschlagener Container die Verfügbarkeit containerisierter Anwendungen.
Container und k8s beschleunigen euren Entwicklungs-, Build-, Test- und Deployment-Zyklus, indem sie einen Großteil des Aufwands für die Infrastrukturverwaltung abstrahieren. Neue Tools bauen auf k8s und Containern auf, um Infrastruktur, Konfigurationen und sogar Anwendungs-Deployments per Code zu erstellen und zu verwalten. Dazu gehören Kops – ein Tool zur Verwaltung von k8s-Clustern – und Helm (ein Tool für die Paketverwaltung von k8s). Mit diesen Tools könnt ihr die Erstellung und Verwaltung eurer k8s-Cluster automatisieren. Außerdem könnt ihr eure Anwendungen einfach auf dem k8s-Cluster deployen und verwalten.
Mit Kops könnt ihr eure k8s-Cluster mithilfe von Manifestdateien im Yaml-Format definieren. Sobald ihr einen Cluster erstellt habt, speichert Kops dessen Zustand in einem S3-Bucket.
Helm ermöglicht euch, Anwendungs-Deployments auf eurem k8s-Cluster zu verwalten. Es bietet eine Reihe stabiler Pakete – sogenannte Charts –, die ihr direkt auf eurem k8s-Cluster deployen könnt. Alternativ könnt ihr mit Helm eigenen Chart erstellen und wiederverwenden.
Wie lässt sich ein Jenkins-CI-Server auf einem k8s-Cluster in AWS deployen?
In diesem Beitrag deployen wir den Jenkins-CI-Server mit Helm auf einem k8s-Cluster in AWS und verbinden anschließend Windows-Slaves damit. Um Jenkins auf k8s zu deployen, sind die folgenden Schritte erforderlich:
Hinweis: Dieser Beitrag verwendet AWS als Cloud-Anbieter. Die hier erläuterten Konzepte und Schritte lassen sich jedoch auf andere Cloud-Anbieter mit ähnlichen Services übertragen.
Erstellt mithilfe von Kops und dieser Anleitung einen k8s-Cluster auf AWS.
Sobald ihr den Cluster erstellt habt, müsst ihr Kubectl und anschließend Helm installieren – und zwar auf dem Rechner, mit dem ihr euren Cluster verwaltet. Nach der Installation muss Helm initialisiert werden, damit sein Server automatisch installiert wird. Dieser heißt Tiller und läuft auf dem verwendeten k8s-Cluster.
Jetzt habt ihr einen Cluster sowie Helm installiert und initialisiert. Mit dem folgenden Befehl könnt ihr den stabilen Jenkins-Chart auf dem k8s-Cluster installieren:
helm install --name <<your-release-name>> stable/jenkins
Erstellt mithilfe von Kops und dieser Anleitung einen k8s-Cluster auf AWS.
Sobald ihr den Cluster erstellt habt, müsst ihr Kubectl und anschließend Helm installieren – und zwar auf dem Rechner, mit dem ihr euren Cluster verwaltet. Nach der Installation muss Helm initialisiert werden, damit sein Server automatisch installiert wird. Dieser heißt Tiller und läuft auf dem verwendeten k8s-Cluster.
Jetzt habt ihr einen Cluster sowie Helm installiert und initialisiert. Mit dem folgenden Befehl könnt ihr den stabilen Jenkins-Chart auf dem k8s-Cluster installieren: helm install --name <<your-release-name>> stable/jenkins
Das war's! Ihr habt jetzt einen Jenkins-Master auf eurem Cluster deployt und ihn über einen Load Balancer (in diesem Fall AWS ELB) für die Außenwelt erreichbar gemacht. Die Ausgabe von Helm zeigt euch, wie ihr die URL eures Jenkins-Masters und das Admin-Passwort erhaltet.
Was geschieht im Hintergrund bei diesem einzeiligen Helm-Befehl?
Die folgende Abbildung zeigt, was passiert ist. Helm hat ein Deployment und mehrere Services auf eurem k8s-Cluster erstellt. Das Deployment definiert einen Sollzustand für den Pod, der den Jenkins-Master enthält. Dadurch kann k8s einen neuen Pod starten, in dem ein Jenkins-Master in einem Docker-Container läuft, falls der aktuelle Pod ausfällt. Da Pods nicht dauerhaft bestehen, ermöglichen die in diesem Schritt erstellten Services anderen Pods und Anwendungen, den Jenkins-Master über einen DNS-Namen des Services statt über die IP-Adresse des zugrunde liegenden Pods zu erreichen. Der Port des Jenkins-Masters wird über den Load Balancer des Cloud-Anbieters extern verfügbar gemacht, sodass er von überall im Internet erreichbar ist (in diesem Fall AWS ELB). Unabhängig davon, was mit den Pods im Cluster geschieht, könnt ihr daher über die IP-Adresse des Load Balancers stets auf euren Jenkins-Master zugreifen. Der Jenkins-Agent-Service wird hingegen mit Cluster IP bereitgestellt und ist daher nur innerhalb des Clusters erreichbar.
Aber Moment! Wie kann ich meine Jenkins-Konfigurationen anpassen?
Keine Sorge: Der Jenkins-Helm-Chart enthält eine Datei mit konfigurierbaren Parametern, die ihr anpassen könnt. So könnt ihr beispielsweise festlegen, welche Plugins zusammen mit Jenkins installiert werden sollen und welche Docker-Images für Master und Slaves verwendet werden.
Ihr fragt euch vielleicht: Wo sind die Slaves?
Wir haben die mit dem Jenkins-Helm-Chart bereitgestellte Standardkonfiguration verwendet. In dieser Konfiguration ist Jenkins mit dem Jenkins Kubernetes Plugin installiert. Dieses Plugin ermöglicht dem Master, bei Bedarf Slaves als Docker-Container in Pods zu erstellen. Das bedeutet: Sobald ein Job ansteht, erstellt der Master dynamisch einen Slave in eurem k8s-Cluster. Der Slave führt den Job aus und wird anschließend verworfen.
Jetzt fragt ihr euch vielleicht, ob auch Windows-Slaves möglich sind, oder?
In einem vorherigen Beitrag haben wir den aktuellen Stand der Windows-Unterstützung in k8s erläutert und sind zu dem Schluss gekommen, dass sie derzeit nicht ausgereift genug für produktionsnahe Umgebungen ist, wenn ihr Kops zur Verwaltung eures k8s-Clusters verwendet. Deshalb haben wir empfohlen, Windows-Hosts außerhalb des Clusters zu erstellen und ihnen die Kommunikation mit Anwendungen zu ermöglichen, die auf eurem k8s-Cluster deployt sind. Das folgende Diagramm veranschaulicht die von uns verwendete Architektur:
Wir haben eine separate AWS VPC erstellt, um Windows-VMs mit permanenten Jenkins-Slaves zu hosten.
Windows-Slaves mit dem Jenkins-Master verbinden
Helm hat den Jenkins-Agent-Service (der für die Verbindung der Slaves zuständig ist) nur für den Cluster verfügbar gemacht (mithilfe des Service-Typs Cluster IP). Helm geht davon aus, dass sich alle Slaves innerhalb des k8s-Clusters verbinden. Die Windows-Slaves verbinden sich jedoch, wie oben beschrieben, von außerhalb des Clusters.
Um den Jenkins-Agent-Service für Windows-Slaves zugänglich zu machen, die sich aus der Windows VPC verbinden, gibt es zwei Optionen:
Den Slave-Agent über den Service-Typ NodePort verfügbar machenNodePort stellt den Service über einen bestimmten Port auf allen Cluster-Nodes bereit. Dadurch ist der Service innerhalb des Clusters über Cluster-IPs, innerhalb der k8s VPC über private AWS-IPs und extern – also von außerhalb der k8s VPC – über jede öffentliche IP eines beliebigen k8s-Nodes erreichbar. Das Problem bei diesem Ansatz: k8s-Nodes sind nicht dauerhaft. Wenn sie ausfallen, werden sie durch neue Nodes ersetzt – und damit auch durch neue externe IPs.
Oder den Slave-Agent über den Service-Typ LoadBalancer verfügbar machenEin Load Balancer verbindet sich unabhängig von der internen IP des Services immer aus der Windows VPC mit dem Jenkins-Agent-Service. Aus Sicherheitsgründen müsst ihr den Datenverkehr jedoch weiterhin auf die Windows VPC beschränken.
Den Slave-Agent über den Service-Typ NodePort verfügbar machenNodePort stellt den Service über einen bestimmten Port auf allen Cluster-Nodes bereit. Dadurch ist der Service innerhalb des Clusters über Cluster-IPs, innerhalb der k8s VPC über private AWS-IPs und extern – also von außerhalb der k8s VPC – über jede öffentliche IP eines beliebigen k8s-Nodes erreichbar. Das Problem bei diesem Ansatz: k8s-Nodes sind nicht dauerhaft. Wenn sie ausfallen, werden sie durch neue Nodes ersetzt – und damit auch durch neue externe IPs.
Oder den Slave-Agent über den Service-Typ LoadBalancer verfügbar machenEin Load Balancer verbindet sich unabhängig von der internen IP des Services immer aus der Windows VPC mit dem Jenkins-Agent-Service. Aus Sicherheitsgründen müsst ihr den Datenverkehr jedoch weiterhin auf die Windows VPC beschränken.
Hinweis: Bei der ersten Option müsst ihr in der Security Group eurer k8s-Nodes Datenverkehr über den Jenkins-SlaveListener-Port (standardmäßig 50000) aus eurer Windows VPC zulassen. Standardmäßig blockiert diese Security Group Verbindungen von außerhalb der k8s-Cluster-VPC.
Hinweis: Wenn mehrere Services von außerhalb eures k8s-Clusters erreichbar sein müssen, solltet ihr einen HTTP-Reverse-Proxy (z. B. Træfik) in Betracht ziehen, um hohe Rechnungen für AWS ELB zu vermeiden.
Jetzt könnt ihr einen Jenkins-Master in eurem k8s-Cluster bereitstellen, der bei Bedarf Linux-Slaves innerhalb des Clusters erstellen kann. Darüber hinaus kann er sich mit permanenten Windows-Slaves verbinden, die auf VMs außerhalb des k8s-Clusters gehostet werden. In einem kommenden Beitrag erläutern wir, wie ihr Jenkins-Windows-Build-Slaves mit Packer und Terraform bereitstellt. Bleibt dran!
- Cloud
- CI/CD
Subscribe to our newsletter
Related blogs