Deployment Overview
The deployment stage runs the containerized Node.js application using Docker and exposes it on port 80 for external access.
Deployment Command
The pipeline executes this Docker command to deploy the application:
docker run --name Jenkins -d -p 80:3000 nodejs-demo-app:latest
Command Breakdown
Creates and starts a new container from an image
Names the container “Jenkins” for easy identification and management
Runs the container in detached mode (background process)
Maps host port 80 to container port 3000
The Docker image to deploy (built in the Build stage)
Port Mapping Architecture
Port Configuration
┌─────────────────────────────────────────────────────────┐
│ Host Machine │
│ │
│ Port 80 (External) ──────────────────────┐ │
│ │ │
│ ┌────────────────────────────────────────▼──────────┐ │
│ │ Docker Container "Jenkins" │ │
│ │ │ │
│ │ Port 3000 (Internal) ◄─── Node.js App │ │
│ │ │ │
│ │ CMD: node index.js │ │
│ │ Image: nodejs-demo-app:latest │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Port Details
Container Port 3000
Host Port 80
Internal Container Port Port : 3000Purpose : The Node.js application listens on this port inside the container.Configuration : Defined in the Dockerfile:Application Code : The Express app binds to port 3000:const express = require ( 'express' );
const app = express ();
app . get ( '/' , ( req , res ) => res . send ( 'Hello, Elevate Labs, This is After pushing code commits to GitHub' ));
app . listen ( 3000 , () => console . log ( 'App running on port 3000' ));
This port is only accessible from within the container unless explicitly mapped to a host port.
External Host Port Port : 80Purpose : Allows external users to access the application via standard HTTP.Access URLs :
http://your-server-ip:80
http://your-server-ip (port 80 is default)
http://localhost:80 (local access)
Why Port 80?
Standard HTTP port
No need to specify port in URL
Professional production deployment
Port 80 requires root/administrator privileges. Ensure Jenkins has proper permissions or use an alternative port like 8080.
Deployment Pipeline Stage
The complete Deploy stage in the Jenkinsfile:
stage( 'Deploy' ) {
steps {
echo 'Deploying Docker container...'
sh 'docker run --name Jenkins -d -p 80:3000 $IMAGE_NAME:latest'
echo 'App deployed on port 80!'
}
}
Environment Variables
The $IMAGE_NAME variable is defined in the pipeline environment:
environment {
IMAGE_NAME = 'nodejs-demo-app'
}
This expands to nodejs-demo-app:latest during execution.
Container Management
Check Container Status
List Running Containers
Filter by Name
Detailed Information
View Container Logs
All Logs
Follow Logs
Last 100 Lines
Stop and Remove Container
Stop Container
Remove Container
Force Remove Running Container
Troubleshooting
Common Deployment Issues
Error : bind: address already in useSolution 1 : Check what’s using port 80sudo lsof -i :80
# or
sudo netstat -tlnp | grep :80
Solution 2 : Use a different portdocker run --name Jenkins -d -p 8080:3000 $IMAGE_NAME :latest
Solution 3 : Stop the conflicting service# For Apache
sudo systemctl stop apache2
# For Nginx
sudo systemctl stop nginx
Error : container name "Jenkins" already in useCause : A container with the same name already exists.Solution 1 : Remove the existing containerSolution 2 : Use a unique namedocker run --name Jenkins- $( date +%s ) -d -p 80:3000 $IMAGE_NAME :latest
Solution 3 : Add cleanup to pipelinestage( 'Deploy' ) {
steps {
sh 'docker rm -f Jenkins || true'
sh 'docker run --name Jenkins -d -p 80:3000 $IMAGE_NAME:latest'
}
}
Container Starts but Application Not Accessible
Troubleshooting Steps :
Check container is running :
Check container logs :
Look for: App running on port 3000
Test from inside container :
docker exec Jenkins curl http://localhost:3000
Test from host :
Check firewall rules :
sudo ufw status
sudo ufw allow 80/tcp
Error : permission denied while trying to connect to the Docker daemonCause : Jenkins user doesn’t have Docker permissions.Solution :# Add Jenkins user to docker group
sudo usermod -aG docker jenkins
# Restart Jenkins
sudo systemctl restart jenkins
# Verify
sudo -u jenkins docker ps
Production Deployment Best Practices
Enhanced Deployment Configuration
stage( 'Deploy' ) {
steps {
sh '''docker run --name Jenkins -d \
-p 80:3000 \
--restart=unless-stopped \
$IMAGE_NAME:latest'''
}
}
Restart Policies :
no: Never restart (default)
on-failure: Restart only on failure
always: Always restart
unless-stopped: Restart unless manually stopped
stage( 'Deploy' ) {
steps {
sh '''docker run --name Jenkins -d \
-p 80:3000 \
--health-cmd="curl -f http://localhost:3000 || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
$IMAGE_NAME:latest'''
}
}
Check Health Status :docker inspect --format= '{{.State.Health.Status}}' Jenkins
stage( 'Deploy' ) {
steps {
sh '''docker run --name Jenkins -d \
-p 80:3000 \
--memory="512m" \
--memory-swap="1g" \
--cpus="1.0" \
--pids-limit=100 \
$IMAGE_NAME:latest'''
}
}
Resource Limits :
--memory: Maximum memory
--memory-swap: Total memory (RAM + swap)
--cpus: CPU allocation
--pids-limit: Max processes
stage( 'Deploy' ) {
steps {
sh '''docker run --name Jenkins -d \
-p 80:3000 \
-e NODE_ENV=production \
-e PORT=3000 \
-e LOG_LEVEL=info \
$IMAGE_NAME:latest'''
}
}
Environment Variables :
Set runtime configuration
Override default settings
Pass secrets (use Docker secrets in production)
stage( 'Deploy' ) {
steps {
sh '''docker run --name Jenkins -d \
-p 80:3000 \
-v /var/log/app:/app/logs \
-v /etc/app-config:/app/config:ro \
$IMAGE_NAME:latest'''
}
}
Volume Benefits :
Persistent data storage
Log collection
Configuration management
Data sharing between containers
Complete Production Deploy Stage
stage( 'Deploy' ) {
steps {
echo 'Stopping existing container if running...'
sh 'docker rm -f Jenkins || true'
echo 'Deploying new container...'
sh '''docker run --name Jenkins -d \
-p 80:3000 \
--restart=unless-stopped \
--memory="512m" \
--cpus="1.0" \
--health-cmd="curl -f http://localhost:3000 || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
-e NODE_ENV=production \
$IMAGE_NAME:latest'''
echo 'Waiting for application to start...'
sh 'sleep 10'
echo 'Verifying deployment...'
sh 'curl -f http://localhost:80 || exit 1'
echo 'App deployed successfully on port 80!'
}
}
Security Considerations
Production Security Checklist :
Run containers as non-root user
Use read-only filesystem where possible
Implement network policies
Scan images for vulnerabilities
Use secrets management (not environment variables)
Enable Docker Content Trust
Keep base images updated
Limit container capabilities
Secure Deployment Example
stage( 'Deploy' ) {
steps {
sh '''docker run --name Jenkins -d \
-p 80:3000 \
--restart=unless-stopped \
--user 1000:1000 \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
--security-opt=no-new-privileges \
$IMAGE_NAME:latest'''
}
}
Monitoring and Verification
Post-Deployment Checks
Container Status
Verify container is running
Application Logs
Check for startup messages: “App running on port 3000”
Health Check
Should return: “Hello, Elevate Labs, This is After pushing code commits to GitHub”
Resource Usage
docker stats Jenkins --no-stream
Monitor CPU and memory usage
Pipeline Overview Complete CI/CD workflow
Pipeline Stages Detailed stage documentation
Jenkinsfile Complete pipeline code