To design and implement a complete CI/CD pipeline using Jenkins, integrating source code from GitHub, and building & pushing Docker images to Docker Hub.
What is Jenkins? Jenkins is a web-based GUI automation server used to build applications, test code, and deploy software. It provides a browser-based dashboard, a rich plugin ecosystem (GitHub, Docker, etc.), and supports Pipeline as Code via a Jenkinsfile.
What is CI/CD?
Workflow Overview:
Developer → GitHub → Webhook → Jenkins → Build → Docker Hub
Repository created on GitHub: my-app
my-app/
├── app.py
├── requirements.txt
├── Dockerfile
├── Jenkinsfile
├── docker-compose.yml
📸 Screenshot – GitHub repository structure:

app.py:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "Hello from CI/CD Pipeline!"
app.run(host="0.0.0.0", port=80)
requirements.txt:
flask
FROM python:3.10-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 80
CMD ["python", "app.py"]
pipeline {
agent any
environment {
IMAGE_NAME = "divyanshu2104/myapp"
}
stages {
stage('Clone Source') {
steps {
git 'https://github.com/DivKiller1/my-app.git'
}
}
stage('Build Docker Image') {
steps {
sh 'docker build -t $IMAGE_NAME:latest .'
}
}
stage('Login to Docker Hub') {
steps {
withCredentials([string(credentialsId: 'dockerhub-token', variable: 'DOCKER_TOKEN')]) {
sh 'echo $DOCKER_TOKEN | docker login -u divyanshu2104 --password-stdin'
}
}
}
stage('Push to Docker Hub') {
steps {
sh 'docker push $IMAGE_NAME:latest'
}
}
}
}
git branch -M main
git push -u origin main
📸 Screenshot – code pushed to GitHub:

docker-compose.yml:
services:
jenkins:
image: jenkins/jenkins:lts
container_name: jenkins
restart: always
ports:
- "8080:8080"
- "50000:50000"
volumes:
- jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
user: root
volumes:
jenkins_home:
docker compose up -d
📸 Screenshot – Jenkins container started via docker compose:

docker exec -it jenkins cat /var/jenkins_home/secrets/initialAdminPassword
📸 Screenshot – initial admin password retrieved:

Access Jenkins at http://localhost:8080 and paste the password:
📸 Screenshot – Unlock Jenkins browser page:

Select Install suggested plugins and create the admin user.
📸 Screenshot – Install suggested plugins page:

Path: Manage Jenkins → Credentials → Add Credentials
dockerhub-token📸 Screenshot – dockerhub-token credential added:

New Item → Pipeline → Name: ci-cd-pipeline
📸 Screenshot – new pipeline job creation:

Configure the pipeline:
https://github.com/DivKiller1/my-app.gitJenkinsfile📸 Screenshot – pipeline SCM configuration:

Path: Repository Settings → Webhooks → Add Webhook
http://192.168.29.11:8080/github-webhook/application/x-www-form-urlencoded📸 Screenshot – webhook payload URL and event configuration:

📸 Screenshot – webhook Active and Add webhook button:

Push an empty commit to verify the webhook triggers a Jenkins build automatically:
git commit --allow-empty -m "trigger"
git push
📸 Screenshot – empty commit pushed to trigger webhook:

Jenkins receives the webhook event and executes all stages:
📸 Screenshot – build #5 successful execution:

📸 Screenshot – Jenkins console output showing pipeline stages:

📸 Screenshot – divyanshu2104/myapp image pushed to Docker Hub:

pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'echo Hello'
}
}
}
}
| Term | Meaning |
|---|---|
pipeline {} |
Root block — everything is written inside this |
agent any |
Run on any available node (in this case, same Docker host) |
stages {} |
Groups all phases of the pipeline |
stage('Name') |
A single phase — visible in Jenkins GUI as a block |
steps {} |
Contains the actual commands to execute |
// Clone code from GitHub
git 'https://github.com/user/repo.git'
// Run a shell command
sh 'docker build -t myapp .'
// Print to console log
echo "Build started"
withCredentials Block ExplainedwithCredentials([string(credentialsId: 'dockerhub-token', variable: 'DOCKER_TOKEN')]) {
sh 'echo $DOCKER_TOKEN | docker login -u divyanshu2104 --password-stdin'
}
| Part | Meaning |
|---|---|
string |
Type of secret (plain text token) |
credentialsId |
ID used to identify the secret in Jenkins |
variable |
Temporary env variable name injected at runtime |
--password-stdin |
Secure login method (no plaintext password in command) |
The secret exists only inside the block — it is never exposed in logs and disappears after use.
Common Mistakes:
// Wrong: hardcoded password
sh 'docker login -u user -p mypassword'
// Wrong: wrong credential ID
credentialsId: 'wrong-name'
// Wrong: using variable outside the block
echo $DOCKER_TOKEN // won't work here
Successfully implemented a complete CI/CD pipeline where:
pipeline → stages → stage → steps is the core structuresh runs shell commands, git fetches codewithCredentials securely injects secrets at runtime