DevOps Projekt 6: CI/CD mit Jenkins auf AWS EC2 für die Web-Profile-Anwendung

Jenkins Github SonarQube Maven Nexus Repository AWS EC2 Webhook Quality Gates Slack Checkstyle

1. Projekt Ziel

Ziel dieses Projekts ist es, einen automatisierten CI-Prozess für die Profile-Anwendung zu implementieren, bei dem jeder Code-Commit automatisch gebaut, getestet, analysiert und versioniert wird.

2. Architekturübersicht – CI Pipeline (Profile)

Jenkins orchestriert den gesamten CI-Flow: Source aus GitHub, Code-Analyse mit SonarQube (Quality Gate) und Artefakt-/Dependency-Management über Nexus (Maven Repository).

2.1 CI-Flow (was wirklich passiert)

Ablauf der CI-Pipeline von GitHub → Jenkins → SonarQube → Nexus (inkl. Quality Gate).

  1. Developer Push auf GitHub
  2. GitHub Webhook → Jenkins
    Der Webhook triggert den Jenkins-Job, die Pipeline startet automatisch.
  3. Jenkins: Checkout des Codes
    Jenkins lädt den Source Code aus dem GitHub-Repository.
  4. Jenkins: Maven Build
    Build & Tests laufen in Jenkins. Maven bezieht Dependencies über Nexus (Proxy/Cache).
    • Maven → Nexus: Dependencies via Proxy/Cache (schneller & reproduzierbar)
  5. Jenkins: SonarQube Scanner
    Code-Analyse wird ausgeführt und die Ergebnisse werden an SonarQube gesendet.
    • Jenkins → SonarQube: sendet Code/Metriken (Scan-Resultate)
    • SonarQube → Jenkins: gibt das Quality Gate zurück
  6. Quality Gate (Entscheidungspunkt)
    • PASSJenkins macht weiter
    • FAILJenkins stoppt (kein Artefakt-Upload)
  7. Jenkins: Artefakt in Nexus publishen
    Das Build-Artefakt (z.B. WAR/JAR) wird in ein Hosted Repository in Nexus hochgeladen.
  8. (Optional) CD / Deployment
    Nach der CI kann eine CD-Stufe folgen: Deployment z.B. auf Tomcat/EC2/Elastic Beanstalk etc.

2.2 Eingesetzte Tools

3. Praktischer Teil – Aufbau der Pipeline

3.1) – EC2 Instanzen vorbereiten CI Infrastructure

In diesem Schritt wird die komplette AWS EC2 Infrastruktur für das CI-Projekt vorbereitet. Dazu gehören AWS-Zugang, Key Pair, Security Groups sowie die Erstellung der EC2-Instanzen mit passendem Betriebssystem und User Data.

    1. Anmeldung im AWS Account

    2. Key Pair erstellen

      • EC2 → Key Pairs → Create key pair
      • Name: profile-ci-key
      • Typ: RSA
      • Format: .pem
      • Key wird für alle drei EC2 Instanzen verwendet

    3. Security Groups erstellen

      Jenkins – jenkins-sg
      • SSH – Port 22 (My IP)
      • HTTP – Port 80
      • Jenkins – Port 8080(IPv4, IPv6)
      • Port 8080(sonar-sg)
      Nexus – nexus-sg
      • SSH – Port 22 (My IP)
      • Nexus UI – Port 8081
      • Port 8081 (from jenkins-sg)
      SonarQube – sonar-sg
      • SSH – Port 22 (My IP)
      • HTTP – Port 80 (Nginx)
      • SonarQube – Port 80 (jenkins-sg)

    4. EC2 Instanzen mit User Data erstellen

      • EC2 → Launch Instance
      • Key Pair: profile-ci-key
      • Security Group je nach Tool auswählen
      • User Data wird beim Erstellen der Instanz hinterlegt
      🛠️ Jenkins EC2 (JenkinsServer)
      • OS: Ubuntu 24.04
      • Security Group: jenkins-sg
      • User Data:
        – Java installieren
        – Jenkins installieren & starten
      • Standard User: ubuntu
      • http://JENKINS_PUBLIC_IP:8080
      📦 Nexus EC2 (NexusServer)
      • OS: Amazon Linux 2023
      • Security Group: nexus-sg
      • User Data:
        – Java installieren
        – Nexus herunterladen & konfigurieren
      • Standard User: ec2-user
      • http://NEXUS_PUBLIC_IP:8081
      🔍 SonarQube EC2 (SonarServer)
      • OS: Ubuntu 24.04
      • Security Group: sonar-sg
      • User Data:
        – Java + PostgreSQL
        – SonarQube Installation
        – Nginx als Reverse Proxy
      • Standard User: ubuntu
      • http://SONAR_PUBLIC_IP
      • Jenkins Zugriff via: http://SONAR_PRIVATE_IP:8080

      Docker Images Liste

3.2) Post-Installation – Jenkins, Nexus & SonarQube Setup

Nach der Erstellung der EC2-Instanzen folgt die Post-Installation. In diesem Schritt werden Jenkins, Nexus und SonarQube vollständig konfiguriert, sodass ein funktionierender CI-Pipeline entsteht.

    1) Jenkins – Konfiguration nach der Installation

    • Anmeldung auf der Jenkins-EC2 per SSH
      Verbindung zur Jenkins-EC2 über Git Bash mittels SSH herstellen. Anschließend prüfen, ob Jenkins und Java korrekt laufen:
      systemctl status jenkins
      java -version
    • Erstzugang & Initiales Admin-Setup
      Zugriff auf Jenkins über den Browser: http://<JENKINS_PUBLIC_IP>:8080

      Das initiale Admin-Passwort wird direkt auf der Jenkins-EC2 ausgelesen:
      cat /var/lib/jenkins/secrets/initialAdminPassword

      Dieses Passwort wird beim ersten Login verwendet, um Jenkins zu entsperren und die empfohlenen Plugins zu installieren.
    • Erstellung eines Admin-Benutzers
      Nach der Plugin-Installation wird ein eigener Admin-User erstellt (Username, Passwort, E-Mail).
      Dieser Benutzer wird künftig für alle Jenkins-Operationen verwendet.

    Benötigte Jenkins Plugins:

      Navigation: Manage Jenkins → Plugins → Available Plugins
      • GitHub Integration Plugin – Source Code Checkout aus GitHub
      • Nexus Artifact Uploader – Upload von Build-Artefakten nach Nexus
      • Maven Integration – Maven Build Management
      • SonarQube Scanner – Code-Qualitätsanalyse
      • Slack Notification – Build-Status Benachrichtigungen
      • Build Timestamp – Eindeutige Build-Versionierung
    • Jenkins Tools-Konfiguration
      Konfiguration der benötigten Build-Werkzeuge, damit Jenkins Builds korrekt ausführen kann.
      • Java (JDK) konfigurieren
        In Jenkins zu Manage Jenkins → Tools navigieren und unter JDK Installations eine neue JDK-Konfiguration hinzufügen.
        Auf der Jenkins-EC2 per SSH prüfen, wo Java installiert ist:

        ls /usr/lib/jvm
        Den passenden JDK-Pfad kopieren und in Jenkins als JAVA_HOME eintragen, z.B.:
        /usr/lib/jvm/java-17-openjdk-amd64
      • Maven konfigurieren
        Ebenfalls unter Manage Jenkins → Tools zu Maven Installations gehen und eine neue Maven-Version hinzufügen (z.B. Maven 3.9.9).
        Jenkins lädt Maven automatisch oder nutzt die konfigurierte Version für alle Maven-Builds.
      • SonarScanner konfigurieren
        Ebenfalls unter Manage Jenkins → Tools zu SonarQube Scanner Installations gehen und eine neue SonarQube Scanner (sonnarscanner) hinzufügen (z.B. SonarQube Scanner 4.7.0.2747).
      • Nach der Konfiguration aller Tools die Änderungen mit Save speichern.

    2) Nexus Repository – Setup & Repositories

    Nexus dient als zentrales Artefakt- und Dependency-Repository für alle Maven-Builds im Continuous-Integration-Prozess.

    • Anmeldung auf der Nexus-EC2 per SSH
      Verbindung zur Nexus-EC2 über Git Bash mittels SSH herstellen. Anschließend prüfen, ob der Nexus-Service korrekt läuft:
      systemctl status nexus
    • Login & Initiales Setup
      Zugriff auf Nexus über den Browser: http://<NEXUS_PUBLIC_IP>:8081

      Beim ersten Login wird das initiale Admin-Passwort benötigt. Dieses Passwort befindet sich auf der Nexus-EC2 und kann wie folgt ausgelesen werden:
      cat /opt/sonatype-work/nexus3/admin.password

      Danach im Browser mit Username: admin anmelden, das ausgelesene Passwort eingeben und anschließend ein neues Admin-Passwort setzen.
    • Repository Administration
      Navigation: Administration → Repositories → Create Repository
      Hier werden die benötigten Maven-Repositories für den CI-Prozess erstellt.

    Maven Repositories

    • profile-release (maven2 hosted)
      Repository für stabile Release-Artefakte (z.B. Versionen wie 1.0.0). Artefakte in diesem Repository gelten als produktionsreif.
    • profile-snapshot (maven2 hosted)
      Repository für Snapshot-Versionen während der Entwicklungsphase (z.B. 1.0.0-SNAPSHOT).
    • pro-maven-central (maven2 proxy)
      Proxy- und Cache-Repository für Maven Central (Nexus holt maven Dependencies hier: https://repo1.maven.org/maven2/). und liefert es weiter an Maven in jenkins
      Reduziert externe Abhängigkeiten, beschleunigt Builds und erhöht die Verfügbarkeit.
    • pro-maven-group (maven2 group)
      Zentrales Gruppen-Repository für Jenkins und Maven.
      Kombiniert:
      • profile-release
      • profile-snapshot
      • pro-maven-central
      Alle Builds greifen ausschließlich auf diese eine Repository-URL zu.

    3) SonarQube – Code Quality & Quality Gate

    • Login & Initiale Konfiguration
      Zugriff über http://<SONAR_PUBLIC_IP>, initiale Admin-Anmeldung und Passwort-Änderung.
    • Token-Erstellung für Jenkins
      Generierung eines SonarQube Tokens und Speicherung in Jenkins Credentials.
    • Quality Gate Integration
      Jenkins stoppt den Pipeline automatisch, wenn der Quality Gate Status fehlschlägt.

3.3) Git & GitHub – Repository erstellen und Code migrieren

In diesem Schritt wird der bestehende Quellcode in ein GitHub-Repository migriert und mit den lokalen Entwicklungswerkzeugen (VS Code & Git Bash) integriert.

    1) GitHub Repository erstellen

    • Neues Repository auf GitHub anlegen
      Erstellung eines leeren Repositories (profile) ohne README, um Konflikte beim ersten Push zu vermeiden.
    • Das Repository dient als zentrale Quelle für Jenkins, Webhooks und CI-Pipelines.

    2) Lokalen Code mit Git initialisieren

    Auf der Entwickler-Maschine (lokal) wird das bestehende Projekt unter Versionskontrolle gestellt.

    cd profile
    git init
    git branch -M main

    Ergebnis: Das Projekt ist jetzt ein lokales Git-Repository mit dem Hauptbranch main.

    3) GitHub Repository als Remote hinzufügen

    git remote add origin https://github.com/<username>/profile.git
    git remote -v

    Dadurch wird das lokale Repository mit GitHub verbunden. Jenkins greift später genau auf dieses Remote-Repository zu.

    4) Code committen und nach GitHub pushen

    git status
    git add .
    git commit -m "Initial commit – Profile Application"
    git push -u origin main

    Nach dem Push ist der komplette Code auf GitHub verfügbar und versionskontrolliert.

3.4) Build Job mit Nexus Integration (Jenkins + Maven)

Ziel: Jenkins baut die Profile-Applikation mit Maven, lädt Abhängigkeiten über Nexus (Proxy/Group Repo) und kann danach Artefakte in Nexus Hosted Repos (Snapshots/Releases) veröffentlichen.

    1) Jenkins Credentials (Nexus Login) anlegen

    1. In Jenkins Browser: Manage JenkinsCredentials → (Global) → Add Credentials
    2. Typ: Username with password
      Username/Password = Nexus Benutzer.
      ID = nexuslogin (diese ID wird später im Jenkinsfile referenziert).

    Hinweis:
    Um Probleme nach einem Shutdown oder Power-Off der Jenkins-EC2-Instanz (z.B. Änderung der Public IP-Adresse) zu vermeiden, sollte in Jenkins eine feste Basis-URL konfiguriert werden.
    Dazu in Jenkins navigieren zu: Manage Jenkins → System
    und im Feld Jenkins URL eine feste URL eintragen, z.B.: http://myjenkins.ci.com

    2) Jenkinsfile – Build Stage mit Nexus

    Jenkins setzt Umgebungsvariablen (Nexus IP/Port, Repo-Namen) und nutzt Credentials, um settings.xml dynamisch mit User/Pass zu füllen.

  • Jenkins Pipeline erstellen
    In Jenkins auf New Item klicken und einen neuen Pipeline-Job anlegen.

    Schritte in Jenkins:
    • Name des Jobs: profile-ci-pipeline
    • Job-Typ: Pipeline auswählen → OK
    • Unter Definition die Option Pipeline script from SCM wählen
    • SCM-Typ: Git
    • Repository URL: git@github.com:<username>/profile.git
    • Zugangsdaten: SSH Private Key von GitHub auswählen
    • Branch: z.B. jenkins-ci
    • Script Path: Jenkinsfile
    • Konfiguration speichern (Save)
    Anschließend im Projektverzeichnis das Pipeline-Skript erstellen:
    Jenkinsfile
    Das Jenkinsfile wird im Projekt mit Visual Studio Code erstellt und beschreibt alle CI-Stages (Build, Test, Analyse, Upload).
    Docker Images Liste
  • Jenkinsfile (Build-Teil)

    pipeline {
      environment {
        NEXUSIP        = '--EC2_NEXUS_PRIVATE_IP--'
        NEXUSPORT      = '8081'
        NEXUS_GRP_REPO = 'vpro-maven-group'
        NEXUS_LOGIN    = 'nexuslogin'
      }
    
      stages {
        stage('Build') {
          steps {
              sh 'mvn -s settings.xml -DskipTests install' // Führt den Maven-Build aus, nutzt Nexus über settings.xml und überspringt Tests
            }
          }
        }
      }
    }
    • mvn -s settings.xml ... → Maven verwendet exakt settings.xml (Mirror auf Nexus + Deploy Server-IDs).
    • -DskipTests → verkürzt Build-Zeit (Tests kommen typischerweise in eigener Stage).

    3) Maven settings.xml (Nexus Mirror + Server Credentials)

    Maven muss wissen: (1) wo es Dependencies holt (Mirror → Nexus Group Repo) und (2) mit welchen Credentials es in Hosted Repos deployen darf (servers).

    Beispiel: settings.xml

    <settings>
    
      <servers>
        <server>
          <id>${env.SNAP_REPO}</id>
          <username>${env.NEXUS_USER}</username>
          <password>${env.NEXUS_PASS}</password>
        </server>
    
        <server>
          <id>${env.RELEASE_REPO}</id>
          <username>${env.NEXUS_USER}</username>
          <password>${env.NEXUS_PASS}</password>
        </server>
    
        <server>
          <id>${env.CENTRAL_REPO}</id>
          <username>${env.NEXUS_USER}</username>
          <password>${env.NEXUS_PASS}</password>
        </server>
    
        <server>
          <id>${env.NEXUS_GRP_REPO}</id>
          <username>${env.NEXUS_USER}</username>
          <password>${env.NEXUS_PASS}</password>
        </server>
      </servers>
    
      <mirrors>
        <mirror>
          <id>${env.CENTRAL_REPO}</id>
          <name>${env.CENTRAL_REPO}</name>
          <url>http://${env.NEXUSIP}:${env.NEXUSPORT}/repository/${env.NEXUS_GRP_REPO}/</url>
          <mirrorOf>*</mirrorOf>
        </mirror>
      </mirrors>
    
    </settings>
    Wichtig: <mirrorOf>*</mirrorOf> sorgt dafür, dass Maven ALLE Repos über Nexus zieht (praktisch: Nexus Group Repo wie vpro-maven-group).

    4) Was passiert beim Build technisch?

    1. Jenkins checkt den Code aus GitHub aus.
    2. Maven startet den Build und fragt NEXUS Dependencies an.
    3. Durch Mirror gehen alle Requests an: http://NEXUSIP:NEXUSPORT/repository/vpro-maven-group/
    4. Nexus liefert Dependencies aus Cache oder holt sie (einmalig) aus Maven Central.
    5. Build erzeugt Artefakt(e) unter target/ (z.B. WAR/JAR).

    Ergebnis der Build-Stage (erster Jenkins Build)

    Beim ersten Durchlauf der Pipeline ist der Build direkt in der Checkout/Fetch-Phase fehlgeschlagen. Ursache war nicht Maven oder der Code, sondern die SSH-Verifikation zu GitHub (Host Key Verification).

    Was ist passiert?

    • Build #1: FAIL
      Der Job wurde gestartet, aber Jenkins konnte das Repository nicht per SSH fetchen. Dadurch wurde die Pipeline abgebrochen, bevor überhaupt Maven oder Tests laufen konnten.
    Jenkins Build #1 - fehlgeschlagen

    Fehlermeldung (Konsole)

    In der Konsole sieht man klar den Grund: „Host key verification failed“. Jenkins hat striktes Checking aktiv, aber der GitHub-Host-Key war auf der Jenkins-EC2 noch nicht bekannt.

    Jenkins Console Output - Host key verification failed

    Was habe ich gemacht, damit der nächste Build funktioniert?

    • Fix (SSH Host Key bekannt machen)
      Auf der Jenkins-EC2 habe ich den GitHub Host-Key in ~/.ssh/known_hosts eingetragen, damit GitHub als „trusted host“ gilt. Typisch z.B. mit ssh-keyscan für github.com. Danach konnte Jenkins das Repo per SSH sauber auschecken.
      • 1. Anmeldung auf der Jenkins-EC2
        Zuerst habe ich mich per SSH auf die Jenkins-EC2 verbunden.
      • 2. Wechsel zum Jenkins-User
        Da Jenkins selbst als Benutzer jenkins läuft, habe ich zu diesem User gewechselt:
        sudo su - jenkins
        So stelle ich sicher, dass der SSH-Trust für genau den Benutzer gesetzt wird, der später das Git-Checkout ausführt.
      • 3. Manueller SSH-Test zu GitHub
        Anschließend habe ich bewusst eine manuelle SSH-Verbindung zu GitHub aufgebaut:
        ssh -T git@github.com
        Beim ersten Verbindungsversuch erscheint Sicherheitsabfrage
      Was bedeutet diese Abfrage?

      SSH teilt hier mit:

      • Der GitHub-Server ist noch nicht bekannt
      • Der angezeigte Fingerprint gehört zum offiziellen GitHub-SSH-Key
      • SSH fragt, ob dieser Host dauerhaft als vertrauenswürdig gespeichert werden soll
      Entscheidung & Wirkung
      • Eingabe von yes
        Mit yes bestätige ich:
        → GitHub wird in ~/.ssh/known_hosts gespeichert
        → Zukünftige SSH-Verbindungen sind erlaubt
        → Kein Host-Key-Fehler mehr bei Jenkins
      • Ergebnis
        Der nächste Build lief erfolgreich durch (Checkout → Build → weitere Stages).
      Jenkins Build Liste - späterer Build erfolgreich

      Nach dem Build: Dependencies & Artefakte in Nexus sichtbar

      Nach einem erfolgreichen Pipeline-Lauf sieht man in Nexus, dass Maven-Abhängigkeiten über das Proxy/Group Repository aufgelöst und gecached wurden (z.B. im vpro-maven-central).

      Nexus Repository - gecachte Maven Dependencies

3.5) GitHub Webhook

Der GitHub Webhook verbindet das GitHub-Repository direkt mit Jenkins und ermöglicht das automatische Starten des CI-Pipelines bei jedem Code-Commit.

    - Ziel:

    • Automatischer Build bei jedem git push
    • Kein manueller Start des Jenkins Jobs
    • Schnelles Feedback über Build- und Code-Qualität

    - Ablauf:

    1. Developer pusht Code in das GitHub Repository
    2. GitHub Webhook sendet ein HTTP POST Event
    3. Jenkins empfängt das Event
    4. Jenkins startet automatisch den CI Pipeline Job

    - Konfiguration in Jenkins:

    • Jenkins Job → Build Triggers
    • Option aktivieren: GitHub hook trigger for GITScm polling

    - Konfiguration in GitHub

    • Repository → Settings → Webhooks → Add Webhook
    • Payload URL: http://<JENKINS_PUBLIC_IP>:8080/github-webhook/
    • Content type: application/json
    • Trigger Event: Just the push event

    - Sicherheit & Netzwerk

    • Jenkins Security Group erlaubt eingehenden Traffic auf Port 8080
    • Webhook Endpoint ist öffentlich erreichbar

    - Ergebnis

    Jeder Push auf GitHub triggert automatisch den Jenkins CI Pipeline (Build → SonarQube → Quality Gate → Nexus Upload).

3.6) SonarQube Server Integration Stage

Nach dem Build durchläuft die CI-Pipeline mehrere Qualitätsstufen. Diese Stages stellen sicher, dass nur getesteter, sauberer und qualitativ hochwertiger Code weiterverarbeitet wird.

    1- Stage: Test

    stage('Test') {
      steps {
        sh 'mvn -s settings.xml test'
      }
    }
    • Führt alle Unit-Tests des Projekts aus
    • Nutzt settings.xml, um Abhängigkeiten über Nexus zu beziehen
    • Erzeugt JUnit-Testberichte in target/surefire-reports
    • ❌ Bei fehlgeschlagenen Tests wird die Pipeline abgebrochen

    Ziel: Sicherstellen, dass die Anwendung funktional korrekt ist.

    2- Stage: Checkstyle-Analyse

    stage('Checkstyle Analysis') {
      steps {
        sh 'mvn -s settings.xml checkstyle:checkstyle'
      }
    }
    • Überprüft den Java-Code-Stil anhand definierter Regeln
    • Erkennt Verstöße gegen Coding-Standards (Naming, Struktur, Komplexität)
    • Erzeugt den Bericht target/checkstyle-result.xml
    • Der Bericht wird später von SonarQube ausgewertet

    - Ziel: Einheitlicher, wartbarer und sauberer Quellcode.

    3- Stage: SonarQube-Analyse

      Voraussetzungen:

        • SonarQube läuft auf eigener EC2 (z.B. http://<SONAR_PUBLIC_IP>)
        • Jenkins kann SonarQube erreichen (Security Group / Netzwerk ok)
        • In Jenkins ist SonarQube als Server registriert (Manage Jenkins → System → SonarQube servers)
        • Ein Sonar Token ist in Jenkins Credentials gespeichert (Secret Text)
        • SonarScanner ist verfügbar (Jenkins Tool oder per Maven Plugin)

      Credentials (Best Practice):

        • sonarserver (Jenkins SonarQube Server Name) → wird in Pipeline referenziert
        • sonartoken (Secret Text) → Zugriff für Scanner auf SonarQube

      Jenkins Konfiguration (einmalig)

      1. SonarQube Token erstellen in SonarQube:
        My Account → Security → Generate Token → z.B. jenkins-token
      2. Token in Jenkins speichern:
        Manage Jenkins → Credentials → (global) → Add Credentials → Secret text
        Secret = <SONAR_TOKEN>
        ID = sonartoken
      3. SonarQube Server in Jenkins registrieren:
        Manage Jenkins → System → SonarQube servers
        Name: sonarserver
        Server URL: http://<SONAR_PRIVATE_IP>
        Authentication Token: sonartoken

      SonarQube Stage in Pipeline

        stage('Sonar Analysis') {
          environment {
            scannerHome = tool "${SONARSCANNER}"
          }
          steps {
            withSonarQubeEnv("${SONARSERVER}") {
              sh '''
              ${scannerHome}/bin/sonar-scanner \
              -Dsonar.projectKey=profile \
              -Dsonar.projectName=profile \
              -Dsonar.projectVersion=1.0 \
              -Dsonar.sources=src/ \
              -Dsonar.java.binaries=target/test-classes \
              -Dsonar.junit.reportsPath=target/surefire-reports/ \
              -Dsonar.jacoco.reportsPath=target/jacoco.exec \
              -Dsonar.java.checkstyle.reportPaths=target/checkstyle-result.xml
              '''
            }
          }
        }

      Was passiert in dieser Stage?

        • Start des SonarScanners aus Jenkins
        • Übertragung von Code und Metriken an SonarQube
        • Analyse von:
          • Bugs und Sicherheitslücken
          • Code Smells
          • Testabdeckung (JaCoCo)
          • Checkstyle-Ergebnissen
        • Ergebnisse werden in der SonarQube-Datenbank gespeichert

        ✅ Nach dieser Stage ist das Projekt in SonarQube sichtbar und bereit für die Quality-Gate-Prüfung.

        Quality Gate stage (SonarQube)

          stage("Quality Gate") {
            steps {
              timeout(time: 1, unit: 'HOURS') {
                waitForQualityGate abortPipeline: true
              }
            }
          }

          Diese Stage stellt sicher, dass der Build nur dann fortgesetzt wird, wenn die Code-Qualitätsregeln von SonarQube erfüllt sind.

          Erklärung

          • waitForQualityGate wartet auf das Ergebnis der SonarQube-Analyse
          • timeout verhindert ein endloses Warten auf die Antwort von SonarQube
          • abortPipeline: true stoppt die Pipeline sofort, wenn der Quality Gate Status FAILED ist

          ❌ Wenn der Quality Gate fehlschlägt, wird kein Artefakt veröffentlicht. Dadurch wird sichergestellt, dass nur qualitativ hochwertiger Code weitergegeben wird.

        Zusammenfassung

          • Test → Funktionale Validierung
          • Checkstyle → Code-Qualität & Standards
          • SonarQube → Zentrale Qualitätsbewertung

        Ergebnis nach Hinzufügen der Stages: Test, Checkstyle & Sonar Analysis

        Nach der Erweiterung der Jenkins-Pipeline um die Stages Test, Checkstyle Analysis und Sonar Analysis wurde der CI-Prozess deutlich qualitätsorientierter. Die folgenden Ergebnisse zeigen den erfolgreichen Ablauf dieser neuen Stages.

        1) Jenkins Pipeline – Erfolgreicher Build

        Die Jenkins-Konsole zeigt, dass alle neuen Stages ohne Fehler durchlaufen wurden. Insbesondere wurde der SonarQube-Analyseprozess erfolgreich abgeschlossen und das Quality Gate als OK bewertet.

        Jenkins Console Output – Sonar Analysis Success

        2) SonarQube Quality Gate – Passed

        Nach Abschluss der statischen Codeanalyse bestätigt SonarQube, dass alle definierten Quality-Gate-Bedingungen erfüllt wurden. Damit darf die Pipeline fortgesetzt werden (z. B. Artefakt-Upload).

        Jenkins Quality Gate Passed

        3) SonarQube Projektübersicht – Code Quality Metriken

        Die SonarQube-Dashboard-Ansicht zeigt detaillierte Qualitätsmetriken des Projekts: Bugs, Vulnerabilities, Code Smells, Test Coverage und technische Schulden. Obwohl Warnungen existieren, bleibt das Quality Gate insgesamt bestanden.

        SonarQube Dashboard – Quality Overview

3.7) Artifact Upload in Nexus

Nach erfolgreichem Build, Tests und bestandener Code-Analyse wird das erzeugte Artefakt in das zentrale Artefakt-Repository Nexus Repository Manager hochgeladen.

    Timestamp – Versionierung des Artefakts vor dem Upload

    Bevor das Artefakt in das Nexus Repository hochgeladen wird, wird ein Timestamp verwendet, um jede Build-Version eindeutig zu kennzeichnen. Dadurch wird verhindert, dass sich Artefakte überschreiben, und jeder Build bleibt eindeutig nachvollziehbar.

    Warum ein Timestamp?

    • Vermeidet das Überschreiben von Artefakten im Nexus Repository
    • Jeder Jenkins-Build erzeugt ein eindeutig versioniertes Artefakt
    • Erleichtert Debugging, Rollbacks und Nachvollziehbarkeit

    Was passiert technisch?

    Das erzeugte WAR-File im target/-Verzeichnis wird logisch versioniert, z.B.:

    profile-v2.war
    → profile-v2-${BUILD_ID}-${BUILD_TIMESTAMP}.war

    Der Timestamp selbst wird nicht direkt im Dateinamen geändert, sondern als Version-Attribut beim Upload nach Nexus verwendet.

    Konfiguration in Jenkins

    • Installation des Jenkins Plugins Build Timestamp
    • Aktivierung des Plugins in der Jenkins Pipeline (Manage jenkins -> system -> Build Timestamp)
    • Nutzung der Jenkins-Variablen BUILD_ID und BUILD_TIMESTAMP im Upload-Stage

    - Stage: Publish Artifact to Nexus

    stage("UploadArtifact") {
      steps {
        nexusArtifactUploader(
          nexusVersion: 'nexus3',
          protocol: 'http',
          nexusUrl: "${NEXUSIP}:${NEXUSPORT}",
          groupId: 'QA',
          version: "${env.BUILD_ID}-${env.BUILD_TIMESTAMP}",
          repository: "${RELEASE_REPO}",
          credentialsId: "${NEXUS_LOGIN}",
          artifacts: [
            [artifactId: 'profileapp',
             classifier: '',
             file: 'target/vprofile-v2.war',
             type: 'war']
          ]
        )
      }
    }

    Erklärung

    • Verwendet das Jenkins Plugin Nexus Artifact Uploader
    • Lädt das erzeugte .war-Artefakt nach Nexus 3 hoch
    • Die Version wird dynamisch erzeugt: BUILD_ID + BUILD_TIMESTAMP
    • Upload erfolgt nur nach bestandenem Quality Gate
    • Zugangsdaten werden sicher über Jenkins Credentials verwaltet

    Repository-Auswahl in Nexus

    Maven entscheidet automatisch, in welches Repository das Artefakt hochgeladen wird – abhängig von der Versionsnummer im pom.xml.

    • Snapshot-Version (1.0-SNAPSHOT) → profile-snapshot
    • Release-Version (1.0) → profile-release

    ℹ️ Beide Repositories sind über das pro-maven-group-Repository zusammengefasst, das als zentraler Zugriffspunkt dient.

    Sicherheit & Credentials

    • Nexus-Zugangsdaten sind nicht im Code gespeichert
    • Credentials werden in Jenkins als:
      • Username/Password Credentials
      • z. B. ID: nexuslogin
    • Jenkins injiziert die Credentials als Umgebungsvariablen:
      • NEXUS_USER
      • NEXUS_PASS

    Ergebnis nach der Stage „Publish Artifact to Nexus“

      Nach erfolgreichem Durchlauf aller vorherigen Pipeline-Stages (Build, Test, Checkstyle, Sonar Analysis und Quality Gate) wurde das erzeugte Artefakt automatisch im Nexus Repository veröffentlicht.

      Das WAR-Artefakt wurde im profile-release Repository abgelegt und eindeutig versioniert, basierend auf Build-ID und Timestamp. Dadurch ist jeder Build klar nachvollziehbar und reproduzierbar.

      • Repository: profile-release (maven2 hosted)
      • GroupId: QA
      • ArtifactId: profileapp
      • Version: 36-26-01-20_23:46
      • Datei: profileapp-36-26-01-20_23:46.war

      Zusätzlich wurden automatisch Prüfsummen-Dateien (.md5 und .sha1) generiert, um die Integrität des Artefakts sicherzustellen.

      Nexus Repository – Uploaded Artifact

      Ergebnis:
      Das Artefakt steht nun zentral im Nexus Repository zur Verfügung und kann von weiteren CI/CD- oder Deployment-Prozessen (CD, Docker, Kubernetes, EC2, etc.) wiederverwendet werden.

3.8) Letzter Schritt: Slack Notification

In diesem finalen Schritt wird das Ergebnis der Jenkins-Pipeline automatisch an Slack gesendet. Dadurch wird das Team sofort informiert, ob der Build erfolgreich war oder fehlgeschlagen ist.

Benötigte Credentials / Jenkins Setup / Slack Konfiguration

  • Slack – Workspace & Channel erstellen
    Im Slack-Browser einen neuen Workspace erstellen (profilecicd) und darin einen Channel anlegen (#jenkinscicd), der für CI-Benachrichtigungen genutzt wird.
  • Slack App „Jenkins CI“ hinzufügen
    In Slack unter Apps hinzufügen nach Jenkins CI suchen, die App installieren, den Channel #jenkinscicd auswählen und anschließend den generierten Token kopieren.
  • Slack in Jenkins konfigurieren
    In Jenkins: Manage Jenkins → Configure System → Slack
    • Workspace: profilecicd
    • Credentials: Slack Token als Secret Text in Jenkins speichern
    • Default Channel: #jenkinscicd
    • Test Connection: Verbindung testen und Konfiguration speichern

Benachrichtigungen über den post-Block

Diese Variante ist besonders empfehlenswert, da der post-Block immer ausgeführt wird – unabhängig davon, ob der Pipeline-Status SUCCESS, FAILURE oder ABORTED ist. Der post-Abschnitt wird am Ende der Pipeline, nach allen Stages, definiert.

post {
    always {
        echo 'Slack Notification wird gesendet'

        slackSend(
            channel: '#jenkinscicd',
            color: COLOR_MAP[currentBuild.currentResult],
            message: "*${currentBuild.currentResult}:* Job ${env.JOB_NAME} \
                       Build ${env.BUILD_NUMBER}\nWeitere Details: ${env.BUILD_URL}"
        )
    }
}

Die Funktion slackSend() stammt aus dem Jenkins Slack Notification Plugin und wird verwendet, um Nachrichten aus der Pipeline direkt an einen Slack-Channel zu senden.

  • slackSend(
    Startet den Versand einer Slack-Nachricht aus der Jenkins-Pipeline.
  • channel: '#jenkinscicd'
    Definiert den Slack-Channel, in den die Nachricht gesendet wird. In diesem Projekt wird der Channel #jenkinscicd verwendet, der speziell für CI/CD-Benachrichtigungen vorgesehen ist.
  • color: COLOR_MAP[currentBuild.currentResult]
    Setzt die Farbe der Slack-Nachricht abhängig vom Build-Ergebnis:
    • SUCCESS → Grün
    • FAILURE → Rot
    • UNSTABLE / ABORTED → Gelb
    Dadurch ist der Status des Builds auf einen Blick erkennbar.
  • message:
    Definiert den eigentlichen Text der Slack-Nachricht.
  • *${currentBuild.currentResult}:*
    Zeigt das finale Ergebnis der Pipeline an (z.B. SUCCESS oder FAILURE). Die Sterne sorgen für eine fettgedruckte Darstellung in Slack.
  • Job ${env.JOB_NAME}
    Gibt den Namen des Jenkins-Jobs aus, der die Pipeline ausgeführt hat.
  • Build ${env.BUILD_NUMBER}
    Zeigt die eindeutige Build-Nummer an, sodass der Durchlauf eindeutig identifiziert werden kann.
  • ${env.BUILD_URL}
    Fügt einen direkten Link zum Jenkins-Build hinzu. Über diesen Link kann sofort auf Logs, Stages und Artefakte zugegriffen werden.

Ergebnis: Der komplette CI-Prozess ist automatisiert – von GitHub Commit bis Artefakt-Upload inklusive Team-Notification.

4- Fazit

In diesem Projekt wurde erfolgreich eine vollständige Continuous-Integration-Pipeline für die Web-Profile-Anwendung umgesetzt. Die gesamte CI-Architektur basiert auf AWS EC2 und nutzt Jenkins als zentrale Orchestrierungsplattform.

Durch die Integration von GitHub, Nexus Repository und SonarQube wurde ein automatisierter Build-, Analyse- und Artefakt-Management-Prozess realisiert. Jeder Code-Push triggert automatisch die Pipeline, führt Builds, Tests, statische Code-Analyse sowie Quality Gates aus und veröffentlicht geprüfte Artefakte versioniert in Nexus.

Die Verwendung von Quality Gates stellt sicher, dass nur qualitativ geprüfter Code weiterverarbeitet wird, während die Slack-Notifications dem Team unmittelbares Feedback über den Pipeline-Status liefern. Dadurch wird Transparenz, Reaktionsgeschwindigkeit und Code-Qualität deutlich verbessert.