Project 4 of 12 · project brief
CI/CD Pipeline with Jenkins
A declarative Jenkins pipeline: checkout → Maven build and tests → quality gate → Docker image → registry, with credentials handled properly.
The scenario
ShopLite's enterprise customer runs everything on Jenkins and wants their team trained on a modern setup. Your brief: a pipeline-as-code Jenkins setup that builds and tests every branch, publishes images only from main, and never exposes credentials.
Before you start
- CI/CD · Jenkins controller & agents
How Jenkins distributes work.
- CI/CD · Jenkinsfile declarative pipelines
The syntax you'll use.
- CI/CD · Credentials & plugins
Storing and using secrets safely.
Stack
Target architecture
Deliverables and requirements
You will hand in
- Jenkins running in Docker with configuration as code (JCasC) and pinned plugins
- A multibranch pipeline driven by a
Jenkinsfilein the repo - Test reports and coverage published per build
- Images pushed only from main, tagged with version and Git SHA
Functional
- Every push and PR triggers a build via webhook
- Failing tests fail the build and report back to the PR
- Main builds push images to the registry
Non-functional
- No builds on the controller (0 executors)
- Credentials only via Jenkins credentials store and
withCredentials, masked in logs - Pipeline completes in under 10 minutes with Maven dependency caching
Milestones
- 1
Jenkins as code
Done when: A reproducible Jenkins: Docker image + plugins.txt + JCasC YAML.
- Custom image
FROM jenkins/jenkins:lts-jdk21withjenkins-plugin-cli --plugin-file plugins.txt jenkins.yaml(JCasC): security realm, 0 controller executors, credentials from env/secrets, a Docker cloud for agents- Run with Docker Compose; persist
jenkins_homein a volume
Prove it works
terminal$ curl -s -u admin:$PW localhost:8080/api/json?tree=numExecutors── expected output ──{"_class":"hudson.model.Hudson","numExecutors":0} - Custom image
- 2
The Jenkinsfile
Done when: Declarative stages for build, test, and reports, running in a Maven container agent.
agent { docker { image 'maven:3.9-eclipse-temurin-21'; args '-v m2:/root/.m2' } }- Stages: Checkout, Build & Test (
mvn -B verify), Reports (junit,recordCoverage) options { timeout(time: 20, unit: 'MINUTES'); disableConcurrentBuilds() }
Stuck? Hints
- Use
post { always { junit 'target/surefire-reports/*.xml' } }so reports publish even when tests fail.
Prove it works
terminal$ # Jenkins UI → shoplite-api » main » #12 → Console Output (tail)── expected output ──[Pipeline] junitRecording test resultsTests: 148, Failures: 0, Skipped: 2Finished: SUCCESS - 3
Image build, scan, and conditional push
Done when: A Docker image built and scanned for every build, pushed only from main.
- Stage
Image: build with the Git SHA tag - Stage
Scan:trivy image --exit-code 1 --severity CRITICAL - Stage
Pushwithwhen { branch 'main' }andwithCredentials([usernamePassword(credentialsId: 'registry', ...)])
Prove it works
terminal$ # feature branch build log── expected output ──Stage "Push" skipped due to when conditionalFinished: SUCCESS - Stage
- 4
Multibranch + webhooks + shared library
Done when: Every branch and PR builds automatically; common steps live in a shared library.
- Create a Multibranch Pipeline (GitHub Branch Source) with webhook triggers
- Move the image build/scan/push steps into a shared library
vars/dockerImage.groovy - Report build status to GitHub PRs
Prove it works
terminal$ # open a PR with a failing test── expected output ──GitHub PR check: continuous-integration/jenkins/pr-merge — Failure (Tests: 1 failed)
Would you run this in production?
- ☐Controller runs no builds; agents are ephemeral containers
- ☐Configuration and plugins as code; plugins pinned and updated regularly
- ☐Credentials scoped, masked, never echoed; least-privilege registry token
- ☐Build timeouts, concurrency control, and log retention
- ☐Backups of
jenkins_home(or fully reproducible from code)
Stretch goals
- Add a SonarQube quality gate (
waitForQualityGate abortPipeline: true) - Run agents on Kubernetes with the Kubernetes plugin
- Rebuild the same pipeline in GitHub Actions and compare (CI/CD course, phase 2)
Show it off
Résumé bullet
Built a Jenkins multibranch CI/CD pipeline as code (JCasC, shared libraries, ephemeral Docker agents) with test/coverage reporting, Trivy scanning, and gated image publishing from main.
Demo script
- Open a PR with a failing test and show the red check
- Show that a feature-branch build skips Push
- Show the Jenkins config recreated from scratch in minutes
Interview questions about this project
Why shouldn't builds run on the Jenkins controller?
Declarative vs scripted pipelines?