Capstone — Full CI/CD for Campus Library
Time for the real thing. This challenge chains everything you learned into one complete CI/CD pipeline. Plan for about one hour.
Goal
By the end, you should have a Jenkins pipeline that automatically builds, tests, Dockerizes, and deploys Campus Library on every push — with branch-based environments and manual production approval.
Step 1 · The App
Create a simple Node.js app:
Create the project
mkdir campus-library-cicd
cd campus-library-cicd
Create server.js
cat > server.js << 'EOF'
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Campus Library v1.0\n');
});
server.listen(3000, () => console.log('Running on 3000'));
EOF
Create package.json
cat > package.json << 'EOF'
{
"name": "campus-library",
"version": "1.0.0",
"scripts": {
"start": "node server.js",
"test": "echo \"All tests passed!\" && exit 0"
}
}
EOF
Dockerfile
cat > Dockerfile << 'EOF'
FROM node:20-alpine
WORKDIR /app
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
EOF
Step 2 · The Jenkinsfile
Jenkinsfile
pipeline {
agent {
docker { image 'node:20-alpine' }
}
environment {
APP_NAME = 'campus-library'
DOCKER_IMAGE = "riya/${APP_NAME}:${env.BUILD_NUMBER}"
}
stages {
stage('Install') {
steps {
sh 'npm ci --ignore-scripts || npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Build Docker Image') {
steps {
sh "docker build -t ${DOCKER_IMAGE} ."
}
}
stage('Push to Docker Hub') {
when { branch 'main' }
steps {
withCredentials([usernamePassword(
credentialsId: 'dockerhub',
usernameVariable: 'USER',
passwordVariable: 'PASS'
)]) {
sh "echo \$PASS | docker login -u \$USER --password-stdin"
sh "docker push ${DOCKER_IMAGE}"
}
}
}
stage('Deploy to Staging') {
when { branch 'develop' }
steps {
sh "kubectl set image deployment/${APP_NAME} web=${DOCKER_IMAGE} --namespace=staging || echo 'Deploy skipped'"
}
}
stage('Deploy to Production') {
when { branch 'main' }
input {
message 'Deploy to production?'
ok 'Deploy!'
}
steps {
sh "kubectl set image deployment/${APP_NAME} web=${DOCKER_IMAGE} --namespace=production || echo 'Deploy skipped'"
}
}
}
post {
always {
sh 'docker rmi ${DOCKER_IMAGE} || true'
}
success {
sh 'echo "Pipeline succeeded!"'
}
failure {
sh 'echo "Pipeline failed!"'
}
}
}
Step 3 · Push and Watch
Initialize Git and push
git init
git add .
git commit -m "Initial commit"
git remote add origin <your-repo-url>
git push -u origin main
Jenkins picks up the push and runs the pipeline:
- Install → dependencies installed
- Test → tests pass
- Build Docker Image → image built with build number tag
- Push → image pushed to Docker Hub
- Deploy to Production → manual approval gate
Step 4 · Create a Feature Branch
Create and push a feature branch
git checkout -b develop
git push -u origin develop
Jenkins creates a separate pipeline run for the develop branch. The Deploy to Staging stage runs instead of Deploy to Production.
Step 5 · Clean Up
Remove Jenkins container
docker stop jenkins
docker rm jenkins
docker volume rm jenkins_home
Remember
This capstone chained: Jenkinsfile → Docker agent → build/test/build-image → push → branch-based deployment → manual approval → cleanup. This is exactly how real CI/CD works.