Jenkins Server als Docker Container

Jenkins ist ein Open Source Server zur Automatisierung gewisser Tätigkeiten. Das können zum Beispiel Installationen von Infrastrukturkomponenten oder automatisierte Build and Deployment Tasks sein. Auch Docker Images lassen sich damit bauen. Damit der Jenkins Server die erforderlichen Projekte erfolgreich ausführen kann, bedarf es einiger Konfigurationsschritte. Dazu gehören neben den benötigten Plugins auch Zugangsdaten für Projekte sowie grundsätzliche Konfigurationen des Jenkins Servers. Das Jenkins Projekt bietet hierfür auch fertige Docker Images an, um den Einstieg zu vereinfachen. Ich greife hierzu immer zur LTS Version „jenkins/jenkins:lts“. Hierbei handelt es sich um ein völlig blankes Image ohne jegliche Konfiguration. Es verhält sich nach dem Start also wie eine lokale Jenkins Installation, die zum ersten Mal aufgerufen wird. Um sich die wiederkehrende Arbeit der Grundkonfiguration zu ersparen, können gewisse Konfigurationen bereits beim Erzeugen des Containers mit übergeben werden. Wird der Container mehrfach benötigt, spart das eine ganze Menge Zeit.

Die Konfiguration kann mit Hilfe einer YAML Datei übergeben werden. Um zu sehen, wie die Datei aufgebaut werden muss, kann das Jenkins Plugin „Configuration as a Code“ installiert werden.

Jenkins Plugin "Configuration as Code"

Alle Anpassungen werden hier direkt in einer YAML Datei hinterlegt, die später verwendet werden kann.

Jenkins casc.yml Datei

Wenn die Konfigurationsdatei den eigenen Anforderungen entspricht, kann diese als „casc.yml“ abgespeichert werden.

Neben der Konfiguration können auch direkt alle benötigten Plugins mit installiert werden, sobald der Container gestartet wird. Diese werden in der Datei „plugins.txt“ abgelegt. Wichtig ist, dass auf jeden Fall das Plugin “configuration-as-code:latest” mit angegeben wird, damit die Konfigurationsdatei auch eingelesen werden kann.

Jenkins plugins.txt

Dem Docker Container können auch Umgebungsvariablen für Jenkins mitgegeben werden. Diese werden in der Datei “jenkins-variable.env” abgelegt.

JAVA_OPTS=-Djenkins.install.runSetupWizard=false
JENKINS_HOST=jenkins.foo.bar
JENKINS_URL=http://${JENKINS_HOST}:8080
JENKINS_ADMIN=jenkins
JENKINS_PASS=foobar
SLAVE_AGENT_PORT=50000
CASC_JENKINS_CONFIG=/var/jenkins_home/casc.yml

Besonders wichtig sind die erste und die letzte Variable. Hierbei wird der Jenkins Setup Wizard deaktiviert, da ja bereits eine fertige Konfiguration mitgeben wird. “CASC_JENKINS_CONFIG” gibt an, wo die Konfigurationsdatei innerhalb des Containers zu finden ist. Die anderen Variablen können nach Belieben angepasst werden.

Für den Docker Container wird noch eine Docker Compose Datei angelegt. Diese erzeugt und startet den Container.

version: '3.9'
services:
  jenkins:
    build: .
    env_file: jenkins-variables.env
    ports:
      - 8000:8080
      - 50000:50000
    container_name: jenkins_server_lts
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - data-volume:/var/jenkins_home
    restart: always
volumes:
  data-volume:

Der Parameter “build: .” gibt an, dass wir zusätzlich ein Dockerfile mit angeben. Dies ist in diesem Fall erforderlich, damit auch die Konfiguration beim Erzeugen des Containers mit angewendet und die Plugins installiert werden. Die beiden Ports sind für die Weboberfläche und den Jenkins Agent. Damit ist der Container über diese beiden Ports von außen erreichbar. Falls der Jenkins Server selbst auf Docker zugreifen können soll, wird das Volume “docker.sock” im Read Only Modus mit eingehängt. Das Volume “data-volume” speichert die persistenten Daten des Containers, damit diese auch nach einem Neustart vorhanden sind.

Kommen wir nun zum Dockerfile. Dies wird ohne Erweiterung als “Dockerfile” erzeugt und bekommt folgenden Inhalt.

FROM jenkins/jenkins:lts
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN jenkins-plugin-cli -f /usr/share/jenkins/ref/plugins.txt
COPY casc.yml /var/jenkins_home/casc.yml

Damit wird später der Container mit dem aktuellen Jenkins LTS Image gebaut, die Plugins werden installiert und die Konfiguration wird angewendet. Über das Dockerfile können auch komplette vorgefertigte Projekte in den Container kopiert werden, damit diese später nicht manuell angelegt werden müssen.

Die Dateistruktur sollte nun wie folgt aussehen.

Docker Dateistruktur

Der Container kann jetzt über Docker Compose erzeugt und gestartet werden.

docker-compose up -d --build

Nach ein paar Sekunden lässt sich die Jenkins Oberfläche im Browser aufrufen.

Weboberfläche

In der Standardkonfiguration wird die Oberfläche per http und dem definierten Port “8000” aufgerufen. Hier lässt sich auch noch per Docker ein Reverse Proxy wie Traefik vorschalten, um eine saubere https Konfiguration zu ermöglichen. Somit wird die Kommunikation verschlüsselt und der Jenkins http Port muss nicht nach außen freigegeben werden.

Das fertige Jenkins Docker Projekt kann zusätzlich noch zum Beispiel in ein Github Repository eingecheckt werden. Wenn es dann zum Einsatz kommt, muss es nur noch aus Git ausgecheckt werden, um es sofort starten zu können. Zusätzlich ist es noch eine gute Backup Strategie.