Production-Style CI/CD Pipeline Using Jenkins and Docker
I built a Jenkins-driven CI/CD pipeline that automatically builds, tests, containerizes, and deploys a Flask application with safe redeployments and health-verified delivery.
Completed🔍 Problem Statement
As part of my DevOps and Cloud career transition, I needed to demonstrate practical CI/CD skills beyond theory.
The goal was to design and implement a realistic CI/CD pipeline that:
- automatically builds and tests an application
- containerizes the application using Docker
- deploys it safely on a Linux host
- validates deployment success through a health check
The solution needed to reflect real-world constraints, such as:
- shared infrastructure
- port conflicts
- idempotent deployments
- clear failure signals
🛠️ Solution Overview
I built a Jenkins-based CI/CD pipeline that automates the entire lifecycle of a Flask application, from source code to a running container.
Key Components
- Source Control: GitHub
- CI/CD Tool: Jenkins (Declarative Pipeline)
- Application: Python Flask app
- Testing: pytest
- Containerization: Docker
- Host OS: Ubuntu Linux
🧱 Architecture Summary
High-Level Flow
- Code is pushed to GitHub
- Jenkins pulls the repository using SCM
- Jenkins builds the application and installs dependencies
- Automated tests are executed
- A Docker image is built
- The container is deployed on an Ubuntu VM
- Jenkins verifies deployment via a health check endpoint
Key Design Decision
- The Flask app listens on port 5000 inside the container
- The container is exposed on port 5001 on the host to avoid conflicts with existing services
This ensured safe coexistence on shared infrastructure.
🔄 CI/CD Pipeline Stages
1️⃣ Checkout
- Jenkins pulls the source code from GitHub
- Correct Jenkinsfile path (
jenkins/Jenkinsfile) is explicitly configured
2️⃣ Build
- A Python virtual environment is created
- Application dependencies are installed from
requirements.txt
3️⃣ Test
- Automated tests are executed using pytest
- Pipeline fails immediately if any test fails
4️⃣ Docker Build
- A Docker image is built using a lightweight Python base image
.dockerignoreis used to reduce build context and improve efficiency
5️⃣ Deploy
- Any existing container is safely removed
- A new container is started with explicit host-to-container port mapping
- Deployment is idempotent and safe to re-run
6️⃣ Health Check
- Jenkins performs an HTTP request to
/health - The pipeline only succeeds if the application responds correctly
⚠️ Challenges & How I Solved Them
-
Jenkinsfile Discovery Failure
Issue: Jenkins failed to locate the Jenkinsfile
Solution: Corrected the SCM script path tojenkins/Jenkinsfile -
Port Collision on Host
Issue: Port 5000 was already in use by another long-running container
Solution: Mapped container port 5000 to host port 5001 instead of stopping the existing service -
Container Networking Failure
Issue: Health check failed due to incorrect port mapping
Solution: Explicitly separated host and container ports and corrected Docker run syntax -
Flask Not Reachable from Container
Issue: Application bound to localhost
Solution: Updated Flask to bind to0.0.0.0to allow external access
✅ Outcome
- Fully automated CI/CD pipeline running successfully
- Reliable container deployment with zero downtime for existing services
- Verified deployment through application-level health checks
- Pipeline consistently produces deterministic, repeatable results
The final pipeline runs green only when the application is truly available, not just when containers start.
🧠 Key Learnings
- Correct Jenkinsfile configuration is critical for SCM-based pipelines
- Docker host and container ports must be treated separately
- Idempotent deployment logic is essential for real-world CI/CD
- Health checks provide meaningful validation beyond container status
- Debugging CI/CD pipelines requires understanding both tooling and runtime environments
🏁 Conclusion
This project demonstrates my ability to design, debug, and deliver a production-style CI/CD pipeline using Jenkins and Docker. It reflects not only tool familiarity, but also engineering judgment, problem-solving, and real-world deployment awareness.