Yesterday, I had all three containers running with Docker Compose; frontend, backend, and PostgreSQL.
But there was still one manual step: every time I changed code, I had to rebuild and restart containers manually.
Today, I fixed that forever.
I installed Jenkins — an automation server that watches my GitHub repository and runs tasks automatically when code changes. This is the heart of CI/CD (Continuous Integration/Continuous Deployment).
First: What is Jenkins?
In one sentence: Jenkins is a tool that automatically runs tasks when your code changes.
The Problem Jenkins Solves
Without Jenkins (where I was):
- Write code
git push- Manually run
docker-compose up --build - Wait
- Repeat for every change
With Jenkins:
- Write code
git push- Jenkins AUTOMATICALLY builds and deploys
- Done!
Analogy
| Without Jenkins | With Jenkins |
|---|---|
| You bake bread from scratch every morning | Bread machine bakes automatically when you add ingredients |
| Manual, repetitive, error-prone | Automatic, consistent, reliable |
Step 1: Running Jenkins in Docker
Since my entire stack is already containerized, running Jenkins in Docker made perfect sense.
Creating the Jenkins Docker Compose File
cd ~/Desktop/Production-Ready-Microservices-Platform
mkdir jenkins
cd jenkins
nano docker-compose.yml
The docker-compose.yml for Jenkins
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts
container_name: jenkins
restart: always
ports:
- "8081:8080"
- "50000:50000"
volumes:
- jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DOCKER_HOST=unix:///var/run/docker.sock
volumes:
jenkins_home:
Understanding the Configuration
| Line | What it does | Why it matters |
|---|---|---|
image: jenkins/jenkins:lts |
Uses the Long-Term Support version | Stable, reliable |
ports: - "8081:8080" |
Maps host port 8081 → container port 8080 | Access Jenkins at localhost:8081 |
volumes: - jenkins_home:/var/jenkins_home |
Persists Jenkins data | Jobs, settings survive container restarts |
volumes: - /var/run/docker.sock:/var/run/docker.sock |
Mounts Docker socket | Jenkins can run Docker commands! |
DOCKER_HOST=unix:///var/run/docker.sock |
Tells Jenkins where Docker is | Allows building images inside Jenkins |
Starting Jenkins
sudo docker-compose up -d
What I saw:
[+] Running 2/2
✔ Network jenkins_default Created
✔ Container jenkins Started
Step 2: Accessing Jenkins Web Interface
Check Jenkins is Running
sudo docker ps
Output:
CONTAINER ID IMAGE COMMAND STATUS PORTS
xxxxxx jenkins/jenkins:lts ... Up ... 0.0.0.0:8081->8080/tcp
Open Jenkins
In your browser: http://localhost:8081
Step 3: Unlocking Jenkins
Jenkins requires an initial admin password.
Get the Password
sudo docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
Output: A long string of letters and numbers (copy this!)
Paste the Password
- On the Jenkins web page, paste the password
- Click "Continue"
Step 4: Installing Plugins
Jenkins asked which plugins to install. I chose "Install suggested plugins"
What are plugins? Extensions that add features to Jenkins:
- Git integration
- Docker pipeline
- Blue Ocean (pretty UI)
- Many more
Step 5: Creating Admin User
After plugins installed, I created my admin account:
| Field | What I entered |
|---|---|
| Username | admin |
| Password | (created a strong password) |
| Full name | My name |
| My email |
Click "Save and Continue"
Step 6: Jenkins is Ready!
After confirming the URL (default is fine), I clicked "Start using Jenkins"
I saw the Jenkins dashboard!
Step 7: My First Pipeline Job
Creating a New Job
- Click "New Item" on the left menu
- Enter name:
my-first-pipeline - Select "Pipeline"
- Click OK
Writing the Pipeline Script
In the "Pipeline" section, I selected "Pipeline script" and added:
pipeline {
agent any
stages {
stage('Hello') {
steps {
echo 'Hello from Jenkins!'
}
}
stage('Date') {
steps {
sh 'date'
}
}
stage('Who Am I') {
steps {
sh 'whoami'
}
}
stage('Docker Version') {
steps {
sh 'docker --version'
}
}
}
}
What This Pipeline Does
| Stage | What it does | Output example |
|---|---|---|
| Hello | Prints a greeting | Hello from Jenkins! |
| Date | Runs date command |
Tue Apr 28 14:30:00 EAT 2026 |
| Who Am I | Shows user Jenkins runs as |
root (or jenkins) |
| Docker Version | Checks Docker is available | Docker version 28.5.2 |
Running the Pipeline
- Click "Save"
- Click "Build Now" on the left menu
- Click on build #1
- Click "Console Output"
What I saw:
[Pipeline] Start of Pipeline
[Pipeline] stage
[Pipeline] { (Hello)
[Pipeline] echo
Hello from Jenkins!
[Pipeline] }
[Pipeline] stage
[Pipeline] { (Date)
[Pipeline] sh
+ date
Tue Apr 29 10:30:00 EAT 2026
[Pipeline] }
[Pipeline] stage
[Pipeline] { (Docker Version)
[Pipeline] sh
+ docker --version
Docker version 28.5.2, build 9cc6dea35e
[Pipeline] }
[Pipeline] End of Pipeline
Finished: SUCCESS
It worked! Jenkins successfully ran my pipeline!
Jenkins vs Docker Compose (Understanding the Difference)
| Tool | What it does | When to use |
|---|---|---|
| Docker Compose | Runs multiple containers together | Starting your app locally |
| Jenkins | Automates tasks when code changes | CI/CD, automatic builds, testing |
They work TOGETHER:
You push code → Jenkins sees it → Jenkins runs Docker Compose → Your app updates
Issues I Ran Into (And Fixed)
Issue 1: Docker Pull Timeout
Error:
dial tcp: lookup registry-1.docker.io: i/o timeout
Cause: DNS configuration issue with Docker.
Fix:
# Create Docker daemon config
sudo nano /etc/docker/daemon.json
# Add DNS servers
{
"dns": ["8.8.8.8", "1.1.1.1"]
}
# Restart Docker
sudo systemctl restart docker
Issue 2: Port Already in Use
Error:
Bind for 0.0.0.0:8080 failed: port is already allocated
Cause: Something else was using port 8080 (maybe another Jenkins or web server).
Fix: Used port 8081 instead of 8080.
Issue 3: Jenkins Container Not Starting
Fix: Check logs:
sudo docker logs jenkins
Docker Commands for Jenkins
| Command | What it does |
|---|---|
sudo docker-compose up -d |
Start Jenkins in background |
sudo docker-compose down |
Stop Jenkins |
sudo docker logs jenkins |
View Jenkins logs |
sudo docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword |
Get admin password |
Pipeline Syntax Basics
| Groovy Element | What it does |
|---|---|
pipeline { } |
Wraps the entire pipeline |
agent any |
Run on any available agent |
stages { } |
Contains all stages |
stage('name') { } |
A named step in the pipeline |
steps { } |
Contains the actual commands |
echo 'text' |
Print text to console |
sh 'command' |
Run a shell command |
Key Takeaways
- Jenkins automates repetitive tasks — No more manual builds
- CI/CD = Continuous Integration/Continuous Deployment — Automate from code push to deployment
- Jenkins runs in Docker too — Consistent with our containerized stack
- Plugins extend Jenkins — Git, Docker, Slack, etc.
- Pipeline as Code — Your build process lives in code, not click-ops
Resources
Let's Connect!
Have you used Jenkins before? What CI/CD tool do you prefer — Jenkins, GitHub Actions, GitLab CI, or something else?
Drop a comment or connect on LinkedIn. Let's learn together!
Top comments (0)