Building an Automated CI/CD Pipeline on AWS

In this project, a complete CI/CD pipeline on AWS is implemented to automate the entire software delivery process, from source code management and quality analysis to artifact creation and pipeline notifications.

AWS Pipeline AWS CodeBuild AWS CodeArtifact Sonarcloud Bitbucket S3 Git

1. Project Objective

The objective of this project is to design and implement an automated, scalable CI/CD pipeline using AWS managed services. The pipeline is triggered automatically on every code change and performs the following tasks:

This approach ensures high code quality, reliability, and full transparency throughout the development lifecycle.

2. Architecture

The architecture is fully based on AWS managed services and follows a modular, cloud-native pipeline design.

AWS PIPELINE Developer Commit Code Editor Git Repo Workspace SOURCE Bitbucket Repository Trigger REVIEW AWS CodeBuild SonarCloud BUILD AWS CodeBuild Build & Package S3 Artifacts AWS CodeArtifact Dependencies / Packages

Pipeline Process Flow

3. Practical Implementation

In the practical section, the CI/CD pipeline is implemented step by step. Each stage builds logically on the previous one and represents a functional component of the overall architecture.

3.1) – AWS CodeCommit Setup

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.

Insgesamt zeigt dieses Projekt eine praxisnahe, skalierbare und erweiterbare CI-Lösung, die den Grundstein für eine zukünftige Continuous-Delivery- oder Continuous-Deployment-Strategie legt und moderne DevOps-Best-Practices erfolgreich umsetzt.