DEV Community

Cover image for Jenkins CI/CD with Docker for a Jira Clone: Setup and Challenges
Haripriya Veluchamy
Haripriya Veluchamy

Posted on

1 1 1

Jenkins CI/CD with Docker for a Jira Clone: Setup and Challenges

Image description

Introduction

Recently, I embarked on setting up a CI/CD pipeline for my Jira clone project. While I was familiar with Azure DevOps and Azure Pipelines, I wanted to explore something new, so I opted for Jenkins running in a Docker container. This post details my journey, including the setup process, challenges I encountered, and how I resolved them.

Project Context

Before diving into the Jenkins setup, here's some context about my project:

  • Built a Jira clone with modern web technologies
  • Infrastructure provisioned with Terraform
  • Wanted a robust CI/CD pipeline for automated testing and deployment
  • Needed to work with Docker images as part of the pipeline

Setting Up Jenkins with Docker

1. Running Jenkins in a Docker Container

The first step was to run Jenkins in a Docker container with access to the Docker daemon:

docker run -p 8080:8080 -p 50000:50000 \
  -v jenkins_home:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  jenkins/jenkins:lts 
Enter fullscreen mode Exit fullscreen mode

This command:

  • Exposes Jenkins on port 8080
  • Maps the Jenkins agent port (50000)
  • Creates a persistent volume for Jenkins data
  • Mounts the Docker socket to allow Docker commands within Jenkins

2. Fixing Docker Socket Permissions

One of the first issues I encountered was permission problems with the Docker socket. To fix this, I ran:

sudo chmod 666 /var/run/docker.sock
Enter fullscreen mode Exit fullscreen mode

3. Retrieving the Jenkins Admin Password

To complete the Jenkins setup, I needed the initial admin password:

docker exec ${CONTAINER_ID} cat /var/jenkins_home/secrets/initialAdminPassword
Enter fullscreen mode Exit fullscreen mode

4. Installing Docker CLI Inside the Jenkins Container

For Docker commands to work inside the Jenkins container, I needed to install the Docker CLI:

# Log in as root
docker exec -it -u root ${CONTAINER_ID} bash

# Install Docker CLI
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce-cli

# Add Jenkins user to the docker group
groupadd -f docker
usermod -aG docker jenkins

# Exit container
exit
Enter fullscreen mode Exit fullscreen mode

5. Restarting the Jenkins Container

After making these changes, I restarted the container:

docker restart ${CONTAINER_ID}
Enter fullscreen mode Exit fullscreen mode

Jenkins Configuration

With the container set up, I moved on to configuring Jenkins itself:

6.1 Installing Required Plugins

I installed the following plugins:

  • NodeJS Plugin (for my JavaScript-based project)
  • Docker Pipeline Plugin (for Docker integration in pipelines)

6.2 Configuring NodeJS

This is where I encountered a significant challenge. Even after installing the NodeJS plugin, I needed to explicitly configure it in the Tools section:

  1. Go to "Manage Jenkins" > "Tools"
  2. Enable NodeJS
  3. Add a NodeJS installation with version 18.17 or higher
  4. Save the configuration

Important: I discovered that it's not enough to just install the NodeJS plugin. You must also select the NodeJS version in the Tools section, and then explicitly reference this NodeJS installation in your Jenkinsfile with the nodejs wrapper.

6.3 Setting Up Credentials

For my project, I needed several credentials:

  1. Go to "Manage Jenkins" > "Manage Credentials"
  2. Add the following as "Secret text":
    • DATABASE_URL_CREDENTIAL: PostgreSQL Neon database URL
    • CLERK_SECRET_KEY_CREDENTIAL: Clerk secret key
    • NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY_CREDENTIAL: Clerk publishable key
    • DOCKER_CREDENTIALS: Docker Hub credentials (Username with password)

Image description
Image description

Challenges Faced and Solutions

1. Docker Socket Permission Issues in WSL

Since I was using WSL (Windows Subsystem for Linux), I encountered occasional issues with Docker socket permissions. This happened because permissions sometimes reset after system reboots.

Solution: I created a small script to check and fix permissions at startup:

#!/bin/bash
if [ "$(stat -c %a /var/run/docker.sock)" != "666" ]; then
  sudo chmod 666 /var/run/docker.sock
  echo "Fixed Docker socket permissions"
fi
Enter fullscreen mode Exit fullscreen mode

2. Docker Network Issues with "Docker-in-Docker"

I faced networking challenges when trying to connect containers created by Jenkins to other containers.

Solution: I adopted a "Docker-outside-of-Docker" approach by mounting the host's Docker socket rather than running Docker inside Docker. This way, all containers are created on the host's Docker network.

3. NodeJS Configuration Issues

As mentioned earlier, I discovered that installing the NodeJS plugin wasn't enough. The build would fail with errors about missing Node or npm commands.

Solution:

  1. Explicitly configure NodeJS in the Tools section
  2. Reference this specific NodeJS installation in the Jenkinsfile:
pipeline {
    agent any
    tools {
        nodejs 'NodeJS 18.17.0' // Must match the name given in Tools configuration
    }
    stages {
        stage('Build') {
            steps {
                sh 'node --version'
                sh 'npm --version'
                sh 'npm install'
                // Rest of build steps
            }
        }
        // Other stages
    }
}
Enter fullscreen mode Exit fullscreen mode

My Jenkinsfile

Here's a simplified version of the Jenkinsfile I'm using for my Jira clone project:

pipeline {
    agent any

    tools {
        nodejs 'NodeJS 18.17.0'
    }

    environment {
        DOCKER_REGISTRY = 'docker.io'
        DOCKER_IMAGE_NAME = 'my-jira-clone'
        DOCKER_IMAGE_TAG = "${env.BUILD_NUMBER}"
        DATABASE_URL = credentials('DATABASE_URL_CREDENTIAL')
        CLERK_SECRET_KEY = credentials('CLERK_SECRET_KEY_CREDENTIAL')
        NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY = credentials('NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY_CREDENTIAL')
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Install Dependencies') {
            steps {
                sh 'npm install'
            }
        }

        stage('Run Tests') {
            steps {
                sh 'npm test'
            }
        }

        stage('Build Docker Image') {
            steps {
                sh "docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} ."
            }
        }

        stage('Push Docker Image') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'DOCKER_CREDENTIALS', usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
                    sh "echo ${DOCKER_PASSWORD} | docker login ${DOCKER_REGISTRY} -u ${DOCKER_USERNAME} --password-stdin"
                    sh "docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}"
                }
            }
        }

        stage('Deploy') {
            steps {
                // Deployment steps - in my case, updating Terraform or triggering a deployment script
                echo "Deploying version ${DOCKER_IMAGE_TAG}"
                // Additional deployment commands
            }
        }
    }

    post {
        always {
            sh 'docker logout ${DOCKER_REGISTRY}'
            cleanWs()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Setting up Jenkins with Docker for my Jira clone project was an educational journey. While I encountered several challenges, particularly around Docker permissions, networking, and NodeJS configuration, the solutions I found have resulted in a stable and efficient CI/CD pipeline.

The key takeaways from my experience:

  1. Always explicitly configure tools in Jenkins, even after installing plugins
  2. Be aware of permission issues when mounting the Docker socket
  3. Consider the networking implications when working with Docker in CI/CD
  4. Document your setup process (as I'm doing here!) to make future maintenance easier

If you're considering Jenkins for your CI/CD needs, especially in a Docker environment, I hope my experience helps you avoid some of the pitfalls I encountered.

Have you set up Jenkins for your projects? What challenges did you face? I'd love to hear about your experiences in the comments!


This post is part of my series on building and deploying a Jira clone application. Check out my profile for more posts in this series.

Top comments (0)