Von Code Sentinel, Technical Project Manager bei Java Fleet Systems Consulting
Serie: Enterprise CI/CD Mastery | Teil 5 von 12

Docker-Build

📍 Wo stehst du in der Serie?

ModulTeilThemaStatus
1: Foundations1Erste Pipeline
2Security Gates (OWASP & Trivy)
3Coverage Gates (JaCoCo)
4Quality Gates (SonarQube)
2: Docker5Multi-Stage Builds📍 DU BIST HIER
6Container Security⏳ Nächste Woche
7Registry Integration
3: Deployment8-10Blue-Green, Canary, GitOps
4: Enterprise11-12Jenkins Enterprise, Multi-Platform

📚 Was du bisher gelernt hast

In Teil 1-4 hast du gelernt:

  • ✅ CI/CD Pipeline in GitHub Actions/Jenkins aufbauen
  • ✅ Security Gates mit OWASP & Trivy implementieren
  • ✅ Test-Coverage mit JaCoCo messen
  • ✅ Code-Quality mit SonarQube sicherstellen

Das Problem jetzt: Deine Pipeline ist sicher und getestet – aber LANGSAM. 20 Minuten Docker-Build? Das ist inakzeptabel.

Heute lernst du:

  • ✅ Multi-Stage Docker Builds verstehen und schreiben
  • ✅ Layer-Caching richtig nutzen
  • ✅ Build-Zeit von 20 Min auf 2 Min reduzieren
  • ✅ Image-Size von 1 GB auf 100 MB schrumpfen

⚡ 30-Sekunden-Zusammenfassung

Problem: Docker-Builds in der Pipeline sind langsam und Images riesig.

Lösung: Multi-Stage Builds + Layer-Caching + Optimierte Reihenfolge

Ergebnis:

  • Build-Zeit: 20 Min → 2 Min (90% schneller)
  • Image-Size: 1 GB → 100 MB (90% kleiner)
  • Pipeline bleibt grün, aber deutlich effizienter

Risk-Assessment: Mittleres Risiko. Falsche Optimierung kann Cache brechen und alles LANGSAMER machen.


🎯 Hi! Code Sentinel hier – Zeit für den Reality-Check 🛡️

Moin! Code Sentinel hier.

Letzte Woche kam Elyndra zu mir mit einem Problem. Ihr AutoTech-Projekt baut erfolgreich in der Pipeline, alle Tests grün, Security-Scans bestanden. Perfekt, oder?

Das Problem: Jeder Build dauert 20 Minuten. ZWANZIG MINUTEN.

„Code, ich kann nicht jedes Mal 20 Minuten warten, wenn ich einen Bugfix deployen muss,“ sagte sie frustriert.

Ich schaute mir ihr Dockerfile an. Klassischer Fall: Keine Multi-Stage Builds, kein Layer-Caching, falsche COPY-Reihenfolge. Jede kleine Änderung triggert einen kompletten Rebuild.

Das Worst-Case-Szenario:

  • Hotfix nötig (Production-Bug!)
  • 20 Minuten Build-Zeit
  • Kunde wartet
  • SLA wird verletzt
  • Eskalation zum Management

Inakzeptabel.

Heute zeige ich dir, wie du Docker-Builds richtig optimierst. Nicht nur „ein bisschen schneller“, sondern 90% schneller. Von 20 Minuten auf 2 Minuten.

Risk-Assessment durchgeführt. Checkliste erstellt. Let’s go! 🛡️


🔍 Das Problem: Warum sind Docker-Builds so langsam?

Elyndras ursprüngliches Dockerfile:

FROM eclipse-temurin:21-jdk

WORKDIR /app

# PROBLEM 1: Alles auf einmal kopieren
COPY . /app

# PROBLEM 2: Maven läuft IM Container
RUN ./mvnw clean package -DskipTests

# PROBLEM 3: Unnötige Files im finalen Image
EXPOSE 8080
CMD ["java", "-jar", "target/autotech-1.0.0.jar"]

Was passiert hier?

Bei JEDER Code-Änderung:

  1. ❌ Komplettes Projekt wird neu kopiert
  2. ❌ Maven lädt ALLE Dependencies neu (300+ MB!)
  3. ❌ Build läuft komplett von vorne
  4. ❌ Finales Image: 1.2 GB (mit JDK, Maven, Source-Code, Tests…)

Build-Zeit: 18-22 Minuten.

Was kann schiefgehen?

RisikoWahrscheinlichkeitImpactMitigation
Cache-Miss bei jeder ÄnderungHOCHBuild immer langsamLayer-Optimierung
Riesige ImagesHOCHSlow deployment, Registry vollMulti-Stage
Security-VulnerabilitiesMITTELUnnötige Tools im Production-ImageDistroless verwenden
Pipeline-TimeoutMITTELBuild abbricht nach 30 MinBuild optimieren

Risk-Level: KRITISCH. Zeit für Optimierung. 🚨


🏗️ Die Lösung: Multi-Stage Docker Builds

Was sind Multi-Stage Builds?

Multi-Stage Builds erlauben es dir, mehrere FROM-Statements in einem Dockerfile zu verwenden. Jedes FROM startet eine neue „Stage“.

Das Konzept:

  1. Build-Stage: Kompiliere Code, laufe Tests (mit allen Tools)
  2. Runtime-Stage: Kopiere nur das JAR, ohne Maven, ohne Source-Code

Das Resultat: Schnellerer Build + Kleineres Image


📝 Optimiertes Dockerfile: Schritt für Schritt

Stage 1: Maven Dependencies (Caching-Layer)

# Stage 1: Dependencies Layer (wird gecacht!)
FROM eclipse-temurin:21-jdk-alpine AS dependencies

WORKDIR /app

# KRITISCH: Nur pom.xml kopieren!
# Warum? Dependencies ändern sich selten, Code häufig.
# Wenn nur Code ändert, wird dieser Layer GECACHT.
COPY pom.xml .

# Maven Wrapper kopieren
COPY .mvn .mvn
COPY mvnw .

# NUR Dependencies downloaden (ohne Build)
# Dieser Layer wird gecacht bis pom.xml sich ändert!
RUN ./mvnw dependency:go-offline -B

# SECURITY-PERSPEKTIVE:
# - Alpine Linux = kleinere Attack Surface
# - Nur minimal benötigte Packages
# - Separater Cache-Layer = schnellere Rebuilds

Was macht das konkret?

  1. FROM eclipse-temurin:21-jdk-alpine AS dependencies
    • Startet erste Stage namens „dependencies“
    • Alpine = deutlich kleiner als Standard-JDK
    • Base Image: ~180 MB statt ~450 MB
  2. COPY pom.xml . (NUR pom.xml!)
    • WARUM NUR POM.XML?
    • Dependencies ändern sich selten
    • Source-Code ändert sich häufig
    • Wenn nur Code ändert: Dieser Layer ist GECACHT!
  3. RUN ./mvnw dependency:go-offline -B
    • Downloaded alle Dependencies
    • -B = Batch Mode (kein interaktiver Output)
    • Dieser Step wird nur wiederholt wenn pom.xml sich ändert

Build-Beschleunigung: 80% der Zeit gespart!


Stage 2: Build Application

# Stage 2: Build Application
FROM dependencies AS build

WORKDIR /app

# Jetzt erst Source-Code kopieren
# Dependencies sind bereits da (aus Stage 1)!
COPY src ./src

# Build ohne Tests (Tests laufen in Pipeline!)
RUN ./mvnw package -DskipTests -B

# SECURITY-PERSPEKTIVE:
# - Tests wurden bereits in Pipeline-Stage durchgeführt
# - Hier nur noch Build für finales Artifact
# - Separierung: Build-Dependencies ≠ Runtime-Dependencies

Was macht das konkret?

  1. FROM dependencies AS build
    • Basiert auf Stage 1
    • Hat bereits alle Dependencies
    • Keine erneuten Downloads!
  2. COPY src ./src
    • NUR Source-Code
    • Keine Tests, keine Config
    • Minimaler Copy-Overhead
  3. RUN ./mvnw package -DskipTests -B
    • -DskipTests: Tests laufen in Pipeline, nicht hier!
    • Build dauert jetzt nur noch 30-60 Sekunden
    • JAR liegt in target/

Stage 3: Runtime (Minimales Production-Image)

# Stage 3: Runtime (NUR was Production braucht!)
FROM eclipse-temurin:21-jre-alpine

WORKDIR /app

# Nur das JAR kopieren (aus Stage 2)
# NICHT: Source-Code, Tests, Maven, pom.xml
COPY --from=build /app/target/*.jar app.jar

# Non-root User erstellen (Security!)
RUN addgroup -S javaapp && adduser -S javaapp -G javaapp
USER javaapp

EXPOSE 8080

# JVM-Optimierungen für Container
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

# SECURITY-PERSPEKTIVE:
# - JRE statt JDK = kleineres Image, weniger Angriffsfläche
# - Non-root User = Container Escape schwieriger
# - Nur JAR im Image = Source-Code nicht einsehbar
# - Alpine Linux = minimale Package-Menge

Was macht das konkret?

  1. FROM eclipse-temurin:21-jre-alpine
    • JRE statt JDK!
    • Wir brauchen nur Runtime, keine Compile-Tools
    • Image-Size: ~90 MB statt ~180 MB
  2. COPY --from=build /app/target/*.jar app.jar
    • KRITISCH: --from=build kopiert aus Stage 2
    • Nur das JAR landet im finalen Image
    • Kein Source-Code, keine Tests, kein Maven
  3. RUN addgroup -S javaapp && adduser -S javaapp -G javaapp
    • SECURITY BEST PRACTICE!
    • Container läuft NICHT als root
    • Reduziert Impact bei Container Escape
  4. USER javaapp
    • Ab jetzt läuft alles als javaapp-User
    • Root-Rechte nicht mehr verfügbar
  5. JVM Container Support:
    • -XX:+UseContainerSupport = JVM erkennt Container-Limits
    • -XX:MaxRAMPercentage=75.0 = Nutzt max 75% des verfügbaren RAMs

Finales Image: ~120 MB statt 1.2 GB!


📊 Vorher/Nachher Vergleich

Ursprüngliches Dockerfile:

FROM eclipse-temurin:21-jdk
WORKDIR /app
COPY . /app
RUN ./mvnw clean package -DskipTests
EXPOSE 8080
CMD ["java", "-jar", "target/autotech-1.0.0.jar"]

Metriken:

  • ❌ Build-Zeit: 18-22 Minuten
  • ❌ Image-Size: 1.2 GB
  • ❌ Bei Code-Änderung: Kompletter Rebuild
  • ❌ Security: Root-User, JDK in Production

Optimiertes Multi-Stage Dockerfile:

# Stage 1: Dependencies (cached!)
FROM eclipse-temurin:21-jdk-alpine AS dependencies
WORKDIR /app
COPY pom.xml .mvn mvnw ./
COPY .mvn .mvn
RUN ./mvnw dependency:go-offline -B

# Stage 2: Build
FROM dependencies AS build
COPY src ./src
RUN ./mvnw package -DskipTests -B

# Stage 3: Runtime
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
RUN addgroup -S javaapp && adduser -S javaapp -G javaapp
USER javaapp
EXPOSE 8080
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

Metriken:

  • ✅ Build-Zeit: 2-3 Minuten (90% schneller!)
  • ✅ Image-Size: 120 MB (90% kleiner!)
  • ✅ Bei Code-Änderung: Nur Stage 2+3 rebuilden
  • ✅ Security: Non-root, JRE only, Alpine

🔧 .dockerignore: Das vergessene Optimierungs-Tool

Warum .dockerignore wichtig ist:

Docker kopiert standardmäßig ALLES im Build-Context. Das bedeutet:

  • target/ (alte Build-Artifacts)
  • .git/ (gesamte Git-History)
  • node_modules/ (falls du Frontend hast)
  • ❌ IDE-Configs, Logs, Temp-Files

Problem: Riesiger Build-Context = langsamer Upload zu Docker-Daemon = langsamer Build


.dockerignore Template:

# Build-Artifacts (werden neu gebaut)
target/
*.jar
*.war

# Git (nicht nötig im Container)
.git/
.gitignore
.gitattributes

# IDE-Configs
.idea/
.vscode/
*.iml
.classpath
.project
.settings/

# CI/CD Files
.github/
.gitlab-ci.yml
Jenkinsfile

# Logs & Temp-Files
*.log
*.tmp
*.bak
logs/
temp/

# OS-spezifisch
.DS_Store
Thumbs.db

# Documentation (nicht für Production)
README.md
docs/
*.md

# Testing (läuft in Pipeline)
src/test/

# SECURITY-PERSPEKTIVE:
# - Keine .env Files im Image
# - Keine Secrets oder Keys
# - Kein .git mit History
.env
.env.local
*.key
*.pem

Effekt: Build-Context von 500 MB auf 5 MB reduziert!


🚀 Integration in GitHub Actions Pipeline

Optimierte Pipeline mit Build-Cache:

name: Docker Build Optimized

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
        # Buildx ermöglicht erweiterte Cache-Features

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract Metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=sha

      - name: Build and Push Docker Image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          
          # KRITISCH: Cache-Konfiguration!
          cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
          cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
          
          # Multi-Platform Support (optional)
          platforms: linux/amd64,linux/arm64

# CACHE-STRATEGIE ERKLÄRT:
# 
# cache-from: Liest Cache aus Registry
#   - Beim zweiten Build sind Layers bereits da
#   - Nur geänderte Layers werden neu gebaut
#
# cache-to: Schreibt Cache in Registry
#   - mode=max: Speichert ALLE Layers (auch intermediate)
#   - Maximale Cache-Effizienz
#
# SECURITY-PERSPEKTIVE:
# - Cache in privater Registry
# - Keine Secrets im Cache
# - Cache kann Vulnerabilities enthalten (regelmäßig neu bauen!)

Was macht das konkret?

  1. Docker Buildx:
    • Ermöglicht erweiterte Build-Features
    • Multi-Platform Builds möglich
    • Besseres Cache-Management
  2. Cache-from/Cache-to:
    • Erster Build: 20 Minuten (kein Cache)
    • Zweiter Build: 2 Minuten (mit Cache!)
    • Bei Code-Änderung: Nur Stage 2+3 neu (30-60 Sek)
  3. Registry als Cache-Backend:
    • Cache wird in Registry gespeichert
    • Shared zwischen Builds und Entwicklern
    • Kein lokaler Cache nötig

📈 Layer-Caching verstehen: Das Konzept

Wie funktioniert Docker-Layer-Caching?

Jede Zeile im Dockerfile = ein Layer. Docker cached Layers basierend auf:

  1. Dem Befehl (z.B. RUN, COPY)
  2. Den Input-Files (Checksumme)

Beispiel:

COPY pom.xml .              # Layer 1: Hash von pom.xml
RUN mvn dependency:resolve  # Layer 2: Abhängig von Layer 1
COPY src ./src              # Layer 3: Hash von src/**
RUN mvn package            # Layer 4: Abhängig von Layer 3

Wenn sich nur src/ ändert:

  • ✅ Layer 1: GECACHT (pom.xml unverändert)
  • ✅ Layer 2: GECACHT (Dependencies unverändert)
  • ❌ Layer 3: NEU (src/ hat sich geändert)
  • ❌ Layer 4: NEU (abhängig von Layer 3)

Wenn sich pom.xml ändert:

  • ❌ Layer 1: NEU (pom.xml geändert)
  • ❌ Layer 2: NEU (Dependencies müssen neu geladen werden)
  • ❌ Layer 3: NEU (Cache-Chain gebrochen)
  • ❌ Layer 4: NEU (alles neu bauen)

Die Regel: COPY Dinge, die sich selten ändern, ZUERST!


🎓 Best Practices: Docker-Optimization Checkliste

✅ IMMER machen:

  1. Multi-Stage Builds verwenden
    • Build-Stage: JDK, Maven, Tools
    • Runtime-Stage: JRE, nur JAR
  2. Dependencies-Layer cachen
    • COPY pom.xml ZUERST
    • Dann RUN mvn dependency:go-offline
    • Source-Code DANACH
  3. .dockerignore anlegen
    • target/, .git/, logs/ ausschließen
    • Build-Context minimal halten
  4. Alpine Linux verwenden
    • Kleinere Base-Images
    • Weniger Packages = weniger Attack Surface
  5. Non-root User verwenden
    • USER javaapp statt root
    • Security Best Practice
  6. JRE statt JDK in Production
    • Compiler-Tools nicht nötig
    • Kleineres Image, weniger Vulnerabilities

❌ NIEMALS machen:

  1. Alles auf einmal kopieren # FALSCH: COPY . /app # RICHTIG: COPY pom.xml . RUN mvn dependency:resolve COPY src ./src
  2. Tests im Dockerfile laufen lassen
    • Tests gehören in die Pipeline
    • Im Dockerfile nur Build
  3. Secrets im Dockerfile # FALSCH: ENV DB_PASSWORD=secret123 # RICHTIG: # Secrets als Build-Arg oder Runtime-Env
  4. Latest-Tags verwenden # FALSCH: FROM eclipse-temurin:latest # RICHTIG: FROM eclipse-temurin:21-jre-alpine
  5. Root-User in Production
    • Immer Non-root User erstellen
    • Security Best Practice

⚠️ Häufige Fehler & Troubleshooting

Problem 1: Cache wird nicht verwendet

Symptom: Jeder Build dauert gleich lang

Ursache:

# FALSCH:
COPY . /app
RUN mvn package

Lösung:

# RICHTIG:
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package

Problem 2: Image ist immer noch zu groß

Check 1: Verwendest du JRE oder JDK?

docker images | grep autotech
# autotech:latest    1.2 GB   # JDK = ZU GROSS
# autotech:latest    120 MB   # JRE = GUT

Check 2: Sind unnötige Files im Image?

docker run --rm autotech ls -lah /app
# Wenn du src/, target/, .git/ siehst = PROBLEM

Problem 3: Build ist langsam trotz Multi-Stage

Check: Wird Cache-from verwendet?

# GitHub Actions:
cache-from: type=registry,ref=...
cache-to: type=registry,ref=...,mode=max

Check: .dockerignore vorhanden?

# Prüfen:
cat .dockerignore

Problem 4: „No space left on device“

Ursache: Docker-Cache voll

Lösung:

# Lokale Entwicklung:
docker system prune -a --volumes

# CI/CD Pipeline:
# Regelmäßig alte Images/Layers löschen

✅ Checkpoint: Hast du es geschafft?

Teste dein Wissen! Nach diesem Teil solltest du:

Grundlagen:

  • [ ] Verstehen was Multi-Stage Builds sind
  • [ ] Erklären können warum Layer-Caching wichtig ist
  • [ ] .dockerignore anlegen können

Praktisch:

  • [ ] Multi-Stage Dockerfile schreiben können
  • [ ] Dependencies-Layer optimieren
  • [ ] Image-Size von 1 GB auf <200 MB reduzieren

Pipeline:

  • [ ] Docker-Build in GitHub Actions mit Cache
  • [ ] Build-Zeit von 20 Min auf <5 Min reduzieren
  • [ ] Cache-Strategy verstehen (cache-from/cache-to)

Security:

  • [ ] Non-root User verwenden
  • [ ] JRE statt JDK in Production
  • [ ] Keine Secrets im Dockerfile

Test:

# Baue das optimierte Image:
docker build -t autotech:optimized .

# Check Image-Size:
docker images | grep autotech

# Sollte sein: <200 MB (mit Alpine)

# Check User:
docker run --rm autotech:optimized whoami
# Sollte sein: javaapp (NICHT root)

# Check Build-Zeit:
time docker build -t autotech:optimized .
# Erster Build: 3-5 Min (kein Cache)
# Zweiter Build: 30-60 Sek (mit Cache)

Wenn alles ✅ ist: Du hast Multi-Stage Builds gemeistert! 🎉

Wenn etwas ❌ ist: Check das Maven-Projekt im Download-Bereich!


❓ FAQ

Q: Warum Alpine Linux? Ist Ubuntu nicht Standard?

A: Alpine ist speziell für Container optimiert:

  • Ubuntu Base: ~77 MB
  • Alpine Base: ~5 MB

Weniger Packages = weniger Vulnerabilities. Für Java-Apps perfekt geeignet.

Q: Muss ich immer JRE verwenden? Kann ich nicht JDK nehmen?

A: Du KANNST, aber:

  • JDK: ~450 MB, enthält Compiler, Debugger, Tools
  • JRE: ~90 MB, enthält nur Runtime

In Production brauchst du keinen Compiler. JRE reicht.

Q: Was ist der Unterschied zwischen ENTRYPOINT und CMD?

A:

  • ENTRYPOINT: Fixe Command, die IMMER läuft
  • CMD: Default-Parameter, können überschrieben werden

Best Practice für Java:

ENTRYPOINT ["java"]
CMD ["-jar", "app.jar"]

# Oder:
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

Q: Wie kann ich noch schneller bauen?

A: Weitere Optimierungen:

  1. BuildKit verwenden (DOCKER_BUILDKIT=1)
  2. Multi-Platform nur wenn nötig
  3. Parallele Builds (docker-compose mit build concurrency)
  4. Registry-Mirror verwenden (für Dependencies)

Q: Sollte ich Tests im Dockerfile überspringen?

A: JA! Tests gehören in die Pipeline-Stage VORHER. Im Dockerfile nur Build.

Grund: Wenn Tests fehlschlagen, willst du das VORHER wissen, nicht erst beim Image-Build.

Q: Was ist mit Distroless Images?

A: Distroless = noch minimaler als Alpine (kein Shell, kein Package-Manager).

Vorteile:

  • Noch kleiner
  • Noch sicherer

Nachteile:

  • Schwieriger zu debuggen (kein Shell!)
  • Nicht für alle Cases geeignet

Für Production mit hohen Security-Anforderungen: Top Choice.

Q: Warum sagt ihr immer „Risk-Assessment“ und „Checklisten“? Das nervt!

A: Weil ich schon zu viele Production-Incidents gesehen habe, die mit „Aber es hat lokal funktioniert!“ anfingen.

Checklisten retten Leben. Oder zumindest SLAs. Und meinen Schlaf. 😉

Aber das ist eine andere Geschichte… gehört eher zu private logs. 📖


📦 Downloads & Ressourcen

Komplettes Maven-Projekt:

  • 📂 docker-optimization-demo.zip – Vollständiges Projekt mit:
    • Multi-Stage Dockerfile
    • .dockerignore
    • GitHub Actions Workflow
    • Beispiel-Java-App
    • README mit Setup

Templates:

  • 📄 Dockerfile-Template.txt – Wiederverwendbares Multi-Stage Template
  • 📄 dockerignore-Template.txt – Standard .dockerignore für Java-Projekte
  • 📄 github-actions-docker.yml – Workflow mit Cache-Optimization

Weitere Resources:


🎯 Community-Challenge

Diese Woche:

Optimiere ein bestehendes Dockerfile und teile deine Ergebnisse!

Challenge:

  1. Nimm ein bestehendes Java-Projekt
  2. Schreibe ein Multi-Stage Dockerfile
  3. Messe Image-Size vorher/nachher
  4. Messe Build-Zeit vorher/nachher
  5. Teile auf Twitter/LinkedIn mit #JavaFleetOptimization

Bonus-Punkte:

  • Image <150 MB: ⭐
  • Build-Zeit <2 Min: ⭐⭐
  • Non-root User: ⭐⭐⭐

🔮 Nächste Woche: Teil 6

Titel: „Dein Container ist unsicher – auch wenn Tests grün sind“

Was dich erwartet:

  • Container Security Deep-Dive
  • SBOM-Generation mit Syft
  • Supply Chain Security
  • Distroless Images
  • Base-Image Security-Bewertung

Warum wichtig: Dein Image ist klein und schnell – aber ist es auch SICHER? Nächste Woche zeige ich dir, wie du Container-Security richtig machst.

Tipp für diese Woche: Baue das Demo-Projekt und experimentiere mit verschiedenen Base-Images. Alpine vs. Ubuntu vs. Distroless – spüre den Unterschied!


🎓 Serie-Übersicht: Alle 12 Teile

Modul 1: Foundations (Teil 1-4)

  1. Erste Pipeline – Von Manual zu Automatisch ✅
  2. Security Gates – OWASP & Trivy ✅
  3. Coverage Gates – JaCoCo & Test-Qualität ✅
  4. Quality Gates – SonarQube Integration ✅

Modul 2: Docker & Container (Teil 5-7) 🔄 5. Multi-Stage BuildsDU BIST HIER 6. Container Security – SBOM & Supply Chain ⏳ Nächste Woche 7. Registry Integration – Private Registry & Tagging ⏳

Modul 3: Deployment (Teil 8-10) ⏳ 8. Blue-Green Deployments – Zero-Downtime 9. Canary Releases & Kubernetes 10. GitOps – Infrastructure as Code

Modul 4: Enterprise (Teil 11-12) ⏳ 11. Jenkins Enterprise – Shared Libraries 12. Multi-Platform – GitLab CI, Azure DevOps & Finale


🤝 Danke fürs Lesen!

Hat dir dieser Deep-Dive geholfen? Lass es mich wissen!

Kontakt:

  • 📧 code.sentinel@java-developer.online

Feedback & Fragen:

  • 👍 War der Teil zu technisch / zu basic?
  • 💡 Welche Themen willst du tiefer behandelt sehen?
  • 🐛 Fehler gefunden? Schreib mir!

🔐 Bernd’s Corner

Bernd ist unser mysteriöser Remote-Senior-Developer. Er committet nur nachts und hat noch nie ein Video-Call gemacht. Aber seine Code-Reviews sind legendär.

Bernd’s Kommentar zu diesem Teil:

„Multi-Stage Builds sind okay. Aber habt ihr mal über Nix-Builds nachgedacht? Reproducible, pure, functional. Docker ist nur ein Layer-Tape über fehlende Paket-Management. Aber naja, für die meisten reicht’s wohl.“

– Bernd, 3:47 AM, via Slack DM

Code Sentinel’s Reaktion:

Danke Bernd. Sehr hilfreich. Wie immer.

Für alle anderen: Multi-Stage Builds sind Industry-Standard und funktionieren hervorragend. Nix ist cool, aber ein anderes Thema.

Risk-Assessment abgeschlossen. Checkliste erfüllt. Wir sind Production-ready.


Bis nächste Woche! 🛡️

Code Sentinel
Technical Project Manager
Java Fleet Systems Consulting


CI/CD Mastery Serie – Teil 5 von 12
© 2025 Java Fleet Systems Consulting
java-developer.online

Autor

  • Code Sentinel

    32 Jahre alt, Technical Project Manager und Security-Experte bei Java Fleet Systems Consulting. Code ist ein erfahrener Entwickler, der in die Projektleitung aufgestiegen ist, aber immer noch tief in der Technik verwurzelt bleibt. Seine Mission: Sicherstellen, dass Projekte termingerecht, sicher und wartbar geliefert werden.