Blog

Jenkins auf Kubernetes bereitstellen

OCT 26, 2017

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 wichtige 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 ihr Windows-Build-Slaves hinzufügt.

Containerlösungen (z. B. Docker) ermöglichen euren Entwicklern, Anwendungen zu entwickeln und für Tests oder Deployments bereitzustellen, ohne sich um die Einrichtung der Umgebung kümmern oder sich mit dem „works-on-my-machine“-Phänomen auseinandersetzen zu müssen.

Kubernetes (auch k8s genannt) bietet ein Orchestrierungs-Framework für containerisierte Anwendungen. Dieses Framework stellt durch Zustandsüberwachung und die Wiederherstellung ausgefallener Container die Verfügbarkeit der containerisierten Anwendung sicher.

Container und k8s beschleunigen euren Dev-Build-Test-Deploy-Zyklus, indem sie einen Großteil des Aufwands für die Infrastrukturverwaltung abstrahieren. Neue Tools bauen auf k8s und Containern auf und ermöglichen es, 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 Paketmanagement-Tool für k8s). Mit diesen Tools könnt ihr die Erstellung und Verwaltung eurer k8s-Cluster automatisieren. Außerdem könnt ihr Anwendungen einfach auf dem k8s-Cluster deployen und verwalten.

Mit Kops könnt ihr eure k8s-Cluster mithilfe von Manifestdateien definieren, die im Yaml-Format vorliegen. Sobald ihr einen Cluster erstellt habt, speichert Kops dessen Status in einem S3-Bucket.

Helm ermöglicht euch, Anwendungs-Deployments auf eurem k8s-Cluster zu verwalten. Es bietet eine Reihe stabiler Pakete – sogenannter Charts –, die ihr sofort auf eurem k8s-Cluster deployen könnt. Alternativ könnt ihr mit Helm einen eigenen Chart erstellen und ihn wiederverwenden.

Wie wird ein Jenkins-CI-Server auf einem k8s-Cluster in AWS deployt?

In diesem Beitrag deployen wir einen Jenkins-CI-Server mit Helm auf einem k8s-Cluster in AWS und verbinden anschließend Windows-Slaves damit. Für das Jenkins-Deployment auf k8s sind folgende Schritte erforderlich:

Note: While this post uses AWS as a cloud provider. The concepts and steps discussed here can be mapped to other cloud providers offering similar services.

  1. Erstellt mithilfe von Kops und dieser Anleitung einen k8s-Cluster auf AWS.

  2. Nachdem ihr den Cluster erstellt habt, müsst ihr Kubectl und anschließend Helm installieren – und zwar auf dem Rechner, über den ihr euren Cluster verwaltet. Nach der Installation muss Helm initialisiert werden, damit sein Server automatisch installiert wird. Dieser heißt auf dem verwendeten k8s-Cluster Tiller.

  3. Nachdem ihr nun einen Cluster habt und Helm installiert sowie initialisiert ist, könnt ihr den stabilen Jenkins-Chart mit folgendem Befehl 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.

Nachdem ihr den Cluster erstellt habt, müsst ihr Kubectl und anschließend Helm installieren – und zwar auf dem Rechner, über den ihr euren Cluster verwaltet. Nach der Installation muss Helm initialisiert werden, damit sein Server automatisch installiert wird. Dieser heißt auf dem verwendeten k8s-Cluster Tiller.

Nachdem ihr nun einen Cluster habt und Helm installiert sowie initialisiert ist, könnt ihr den stabilen Jenkins-Chart mit folgendem Befehl 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 verfügbar gemacht. Die Helm-Ausgabe zeigt euch, wie ihr die URL eures Jenkins-Masters und das Admin-Passwort abruft.

Jenkins Helm chart output

Was passiert im Hintergrund bei diesem einzeiligen Helm-Befehl?

Die folgende Abbildung zeigt, was passiert ist. Helm hat auf eurem k8s-Cluster ein Deployment und mehrere Services erstellt. Das Deployment definiert einen gewünschten Zustand für den Pod, der den Jenkins-Master enthält. Dadurch kann k8s einen neuen Pod starten, in dem ein Jenkins-Master innerhalb eines Docker-Containers 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-Service-Namen statt über die IP-Adresse des zugrunde liegenden Pods zu erreichen. Der Jenkins-Master-Port wird über den Load Balancer des Cloud-Anbieters extern verfügbar gemacht, sodass ihr von überall im Internet darauf zugreifen könnt (in diesem Fall AWS ELB). Unabhängig davon, was mit den Pods im Cluster passiert, könnt ihr also immer über die IP-Adresse des Load Balancers auf euren Jenkins-Master zugreifen. Der Jenkins-Agent-Service wird dagegen mit Cluster IP bereitgestellt und ist somit nur innerhalb des Clusters erreichbar.

k8s services created by Helm

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. Ihr könnt beispielsweise festlegen, welche Plugins 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 wird Jenkins mit installiertem Jenkins Kubernetes Plugin bereitgestellt. 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 direkt in eurem k8s-Cluster einen Slave. 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 besprochen und sind zu dem Schluss gekommen, dass sie derzeit für produktionsnahe Umgebungen noch nicht ausgereift genug ist, wenn ihr Kops zur Verwaltung eures k8s-Clusters verwendet. Daher 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:

adding windows slaves

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 innerhalb des Clusters verfügbar gemacht (über den Service-Typ 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.

Damit der Jenkins-Agent-Service für Windows-Slaves erreichbar ist, die sich aus der Windows-VPC verbinden, gibt es zwei Optionen:

  1. Den Slave-Agent über den Service-Typ NodePort verfügbar machenNodePort stellt den Service über einen bestimmten Port auf allen Cluster-Knoten bereit. Dadurch ist der Service innerhalb des Clusters über Cluster-IPs, innerhalb der k8s-VPC über private AWS-IPs und extern – außerhalb der k8s-VPC – über jede öffentliche IP eines beliebigen k8s-Knotens erreichbar. Das Problem bei diesem Ansatz: k8s-Knoten sind nicht dauerhaft verfügbar. Wenn sie ausfallen, werden sie durch neue Knoten und damit auch neue externe IPs ersetzt.

  2. 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 weiterhin ausschließlich aus der Windows-VPC zulassen.

Den Slave-Agent über den Service-Typ NodePort verfügbar machenNodePort stellt den Service über einen bestimmten Port auf allen Cluster-Knoten bereit. Dadurch ist der Service innerhalb des Clusters über Cluster-IPs, innerhalb der k8s-VPC über private AWS-IPs und extern – außerhalb der k8s-VPC – über jede öffentliche IP eines beliebigen k8s-Knotens erreichbar. Das Problem bei diesem Ansatz: k8s-Knoten sind nicht dauerhaft verfügbar. Wenn sie ausfallen, werden sie durch neue Knoten und damit auch neue externe IPs ersetzt.

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 weiterhin ausschließlich aus der Windows-VPC zulassen.

Note: for the first option you need to allow traffic on the Jenkins Slavelistener port (default 50000) from your Windows VPC in your k8s nodes’ security group. By default this security group blocks connections from outside the k8s cluster VPC.

Note: If you have multiple services that need to be accessible from outside your k8s cluster then you might consider using an HTTP reverse proxy (e.g. Træfik) to avoid receiving hefty bills for AWS ELB.

Jetzt könnt ihr einen Jenkins-Master in eurem k8s-Cluster bereitstellen, der bei Bedarf Linux-Slaves innerhalb des Clusters erstellen kann. Außerdem kann er sich mit permanenten Windows-Slaves verbinden, die auf VMs außerhalb des k8s-Clusters gehostet werden. In einem kommenden Beitrag zeigen wir euch, wie ihr Jenkins-Windows-Build-Slaves mit Packer und Terraform bereitstellt. Bleibt dran!

  • Cloud
  • CI/CD

Subscribe to our newsletter