Skip to main content

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

docker run
command
Creates and starts a new container from an image
--name Jenkins
string
Names the container “Jenkins” for easy identification and management
-d
flag
Runs the container in detached mode (background process)
-p 80:3000
port-mapping
Maps host port 80 to container port 3000
nodejs-demo-app:latest
image
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

Internal Container Port

Port: 3000Purpose: The Node.js application listens on this port inside the container.Configuration: Defined in the Dockerfile:
EXPOSE 3000
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.

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

docker ps

View Container Logs

docker logs Jenkins

Stop and Remove Container

docker stop Jenkins

Troubleshooting

Common Deployment Issues

Error: bind: address already in useSolution 1: Check what’s using port 80
sudo lsof -i :80
# or
sudo netstat -tlnp | grep :80
Solution 2: Use a different port
docker 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 container
docker rm -f Jenkins
Solution 2: Use a unique name
docker run --name Jenkins-$(date +%s) -d -p 80:3000 $IMAGE_NAME:latest
Solution 3: Add cleanup to pipeline
stage('Deploy') {
    steps {
        sh 'docker rm -f Jenkins || true'
        sh 'docker run --name Jenkins -d -p 80:3000 $IMAGE_NAME:latest'
    }
}
Troubleshooting Steps:
  1. Check container is running:
    docker ps | grep Jenkins
    
  2. Check container logs:
    docker logs Jenkins
    
    Look for: App running on port 3000
  3. Test from inside container:
    docker exec Jenkins curl http://localhost:3000
    
  4. Test from host:
    curl http://localhost:80
    
  5. 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

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

1

Container Status

docker ps | grep Jenkins
Verify container is running
2

Application Logs

docker logs Jenkins
Check for startup messages: “App running on port 3000”
3

Health Check

curl http://localhost:80
Should return: “Hello, Elevate Labs, This is After pushing code commits to GitHub”
4

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

Build docs developers (and LLMs) love