Jenkins Freestyle Project for DevOps Engineers #Day-23

Jenkins Freestyle Project for DevOps Engineers #Day-23

A Guide to Jenkins Freestyle Projects for DevOps Professionals

What is CI/CD?

  • CI (Continuous Integration) is the practice of automating the integration of code changes from multiple developers into a single codebase. It involves developers frequently committing their work into a central code repository (such as GitHub or Stash). Automated tools then build the newly committed code and perform tasks like code review, ensuring that the code is integrated smoothly. The key goals of Continuous Integration are to find and address bugs quickly, make the integration process easier across a team of developers, improve software quality, and reduce the time it takes to release new features.

  • CD (Continuous Delivery) follows Continuous Integration and ensures that new changes can be released to customers quickly and without errors. This includes running integration and regression tests in a staging environment (similar to production) to ensure the final release is stable. Continuous Delivery automates the release process, ensuring a release-ready product at all times and allowing deployment at any moment.

What Is a Build Job?

A Jenkins build job contains the configuration for automating specific tasks or steps in the application building process. These tasks include gathering dependencies, compiling, archiving, transforming code, testing, and deploying code in different environments.

Jenkins supports several types of build jobs, such as freestyle projects, pipelines, multi-configuration projects, folders, multibranch pipelines, and organization folders.

What is a Freestyle Project?

A freestyle project in Jenkins is a type of project that allows you to build, test, and deploy software using various options and configurations. Here are a few tasks you could complete with a freestyle project in Jenkins:

Task 1

  • Create an agent for your app (which you deployed using Docker in a previous task).

  • Create a new Jenkins freestyle project for your app.

  • In the "Build" section of the project, add a build step to run the docker build command to build the image for the container.

  • Add a second step to run the docker run command to start a container using the image created in the previous step.

Step 1: Create an Agent for Your App

  1. Create a Dockerfile for Your App
    Ensure you have a Dockerfile in your application's root directory that specifies how to build your app's Docker image. Here’s an example of a simple Dockerfile:

     FROM python:3.9-slim
    
     WORKDIR /app
    
     COPY . /app
    
     RUN pip install -r requirements.txt
    
     CMD ["python", "app.py"]
    
  2. Build the Docker Image Manually (Optional)
    You can manually test building the Docker image to ensure the Dockerfile works as expected. This step is optional but useful for verifying the Docker configuration.

     docker build -t my-app .
    

Step 2: Set Up Jenkins Freestyle Project

  1. Access Jenkins Dashboard
    Log into your Jenkins instance.

  2. Create a New Freestyle Project

    • Click on "New Item" in the Jenkins dashboard.

    • Enter a name for your project, e.g., MyApp-Docker-Build.

    • Select "Freestyle project" and click "OK".

  3. Configure Source Code Management (Optional)

    • If your code is stored in a version control system like Git, configure the source code management to pull the code.

    • Add the repository URL and credentials, if needed.

Step 3: Add Build Steps

  1. Build the Docker Image

    • In the "Build" section, click on "Add build step" and select "Execute shell".

    • Add the command to build the Docker image:

        docker build -t my-app .
      
  2. Run the Docker Container

    • Add another build step by clicking "Add build step" and selecting "Execute shell" again.

    • Add the command to run the Docker container:

        docker run -d --name my-app-container -p 8000:8000 my-app
      
      • -d: Run the container in detached mode (in the background).

      • --name my-app-container: Name the container.

      • -p 8000:8000: Map the container's port 8000 to the host's port 8000.

      • my-app: The name of the Docker image created in the previous step.

Step 4: Save and Run the Jenkins Job

  1. Save the Configuration

    • Click "Save" to save your Jenkins project configuration.
  2. Build the Project

    • Go back to the Jenkins dashboard and click "Build Now" to run the job.

    • Monitor the console output to ensure the Docker image is built and the container is started successfully.

Step 5: Verify

  1. Check Docker Containers

    • After the build, check if the container is running by executing:

        docker ps
      
  2. Access Your Application

    • Open a web browser and go to http://<your-server-ip>:8000 to access your app.

Jenkinsfile (Groovy Script)

pipeline {
    agent any

    stages {
        stage('Build Docker Image') {
            steps {
                script {
                    // Build the Docker image
                    sh 'docker build -t my-app .'
                }
            }
        }

        stage('Run Docker Container') {
            steps {
                script {
                    // Stop and remove the container if it already exists
                    sh '''
                    docker rm -f my-app-container || true
                    '''

                    // Run the Docker container
                    sh 'docker run -d --name my-app-container -p 8000:8000 my-app'
                }
            }
        }
    }

    post {
        always {
            // Clean up unused Docker images and containers (optional)
            sh 'docker system prune -f'
        }
    }
}

Explanation:

  1. pipeline: Defines the start of the Jenkins pipeline.

  2. agent any: The pipeline can run on any available agent/node.

  3. stages: Contains different stages of the pipeline.

  4. Stage 1: Build Docker Image:

    • sh 'docker build -t my-app .': Runs the Docker build command to create a Docker image tagged as my-app.
  5. Stage 2: Run Docker Container:

    • sh 'docker rm -f my-app-container || true': This command stops and removes any existing container with the name my-app-container if it exists. The || true ensures that the pipeline doesn’t fail if the container doesn't exist.

    • sh 'docker run -d --name my-app-container -p 8000:8000 my-app': Runs a new Docker container named my-app-container in detached mode, mapping port 8000 of the container to port 8000 of the host.

  6. post:

    • always: This block runs after the pipeline finishes, whether it passes or fails.

    • sh 'docker system prune -f': Cleans up unused Docker images and containers to free up space (optional step).

Usage Instructions:

  1. Create a Jenkins Pipeline Project:

    • Go to Jenkins, click on "New Item," and select "Pipeline."

    • Name your project and proceed.

  2. Add the Groovy Script:

    • In the project configuration, under the "Pipeline" section, paste the above Groovy script.
  3. Save and Run:

    • Save the configuration and click "Build Now" to run the pipeline.

This Groovy script will automate the process of building and running a Docker container using Jenkins.

Task 2

  • Create a Jenkins project to run the docker-compose up -d command to start multiple containers defined in the compose file (Hint: use the application and database docker-compose file from Day 19).

  • Set up a cleanup step in the Jenkins project to run the docker-compose down command to stop and remove the containers defined in the compose file.

Step 1: Prepare the Docker Compose File

Ensure you have a docker-compose.yml file that defines your application and database containers. Here's an example docker-compose.yml for reference:

version: '3'
services:
  app:
    image: my-app
    ports:
      - "8000:8000"
    depends_on:
      - db

  db:
    image: postgres:latest
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydatabase
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

Step 2: Create a Jenkins Pipeline Project

  1. Access Jenkins Dashboard
    Log into your Jenkins instance.

  2. Create a New Pipeline Project

    • Click on "New Item" in the Jenkins dashboard.

    • Enter a name for your project, e.g., MyApp-DockerCompose.

    • Select "Pipeline" and click "OK".

  3. Configure the Pipeline

    • Scroll down to the "Pipeline" section.

    • Choose "Pipeline script" from the definition dropdown.

    • In the script box, add the following Groovy script:

Jenkinsfile (Groovy Script)

pipeline {
    agent any

    stages {
        stage('Start Docker Compose') {
            steps {
                script {
                    // Navigate to the directory containing the docker-compose.yml
                    dir('/path/to/your/docker-compose-directory') {
                        // Start the containers in detached mode
                        sh 'docker-compose up -d'
                    }
                }
            }
        }
    }

    post {
        always {
            script {
                // Clean up the Docker containers and networks
                dir('/path/to/your/docker-compose-directory') {
                    sh 'docker-compose down'
                }
            }
        }
    }
}

Explanation:

  1. pipeline: Defines the start of the Jenkins pipeline.

  2. agent any: The pipeline can run on any available agent/node.

  3. stages: Contains different stages of the pipeline.

  4. Stage 1: Start Docker Compose:

    • dir('/path/to/your/docker-compose-directory'): Changes the working directory to the location of your docker-compose.yml file.

    • sh 'docker-compose up -d': Runs docker-compose up in detached mode to start the services defined in the docker-compose.yml.

  5. post:

    • always: This block runs after the pipeline finishes, whether it passes or fails.

    • sh 'docker-compose down': Stops and removes the containers, networks, and volumes defined in the docker-compose.yml.

Step 3: Usage Instructions

  1. Replace the Directory Path:

    • In the dir('/path/to/your/docker-compose-directory') line, replace /path/to/your/docker-compose-directory with the actual path to your docker-compose.yml file on the Jenkins server or node.
  2. Save and Run:

    • Save the pipeline configuration.

    • Click "Build Now" to start the job.

  3. Verify:

    • After the pipeline runs, you can check if the containers are up by running docker ps.

    • The containers should be stopped and removed at the end of the pipeline.

Notes:

  • Ensure Docker and Docker Compose are installed and configured on the Jenkins agent where the pipeline will run.

  • The docker-compose down command in the post block ensures that the containers are cleaned up after the pipeline execution.

Wanderlust Three Tier Application Containerization

Deploying a MERN Stack Project Using Dockerfile and Docker-Compose with Jenkins Job Pipeline Trigger from Master on Agents node.

Pipeline Script

pipeline {
    agent{
        node{
            label "PROD"
        }
    }

    stages {
        stage('Code Clone from GitHub: Step-1') {
            steps {
                echo 'Cloning code from GitHub'
                git url:'https://github.com/nikunjdevcloud/wanderlust.git', branch: 'devops'
            }
        }
        stage('Code Build: Step-2') {
            steps {
                echo 'Building Docker image'
                sh 'docker build -t wanderlust-back-node:v1 .'
                echo 'Backend Docker image build done.'
                sh 'docker build -t wanderlust-front-react:v2 .'
                echo 'Frontend Docker image build done.'
            }
        }
        stage('Image Push to Docker Hub: Step-3') {
            steps {
                withCredentials([usernamePassword(
                    credentialsId: 'DockerHubCredentials',
                    passwordVariable: 'dockerHubPass',
                    usernameVariable: 'dockerHubUser'
                )]) {
                    echo 'Logging in to Docker Hub'
                    sh 'docker login -u ${dockerHubUser} -p ${dockerHubPass}'
                    echo 'Tagging Backend Docker image'
                    sh 'docker tag wanderlust-back-node:v1 ${dockerHubUser}/wanderlust-back-node:Backend'
                    echo 'Pushing Backend Docker image to Docker Hub'
                    sh 'docker push ${dockerHubUser}/wanderlust-back-node:Backend'

                    echo 'Tagging Frontend Docker image'
                    sh 'docker tag wanderlust-front-react:v2 ${dockerHubUser}/wanderlust-front-react:Frontend'
                    echo 'Pushing Frontend Docker image to Docker Hub'
                    sh 'docker push ${dockerHubUser}/wanderlust-back-node:Frontend'
                    echo 'Both Frontend and Backend Docker image Pushed to DockerHub Successfully Completed..!!'                
                }
            }
        }
        stage('Deploy with Docker Compose') {
            steps {
                echo 'Deploying with Docker Compose'
                sh 'docker-compose down'
                sh 'docker-compose up -d'
            }
        }
    }
}

***************************************
Load distributed on each node by steps.
***************************************
pipeline {
    agent none

    stages {
        stage('Code Clone from GitHub: Step-1') {
            agent { label 'DEV' }
            steps {
                echo 'Cloning code from GitHub'
                git url:'https://github.com/nikunjdevcloud/wanderlust.git', branch: 'devops'
            }
        }
        stage('Code Build: Step-2') {
            agent { label 'PROD' }
            steps {
                echo 'Building Docker image'
                sh 'docker build -t wanderlust-back-node:v1 .'
                echo 'Backend Docker image build done.'
                sh 'docker build -t wanderlust-front-react:v2 .'
                echo 'Frontend Docker image build done.'
            }
        }
        stage('Image Push to Docker Hub: Step-3') {
            agent { label 'QA' }
            steps {
                withCredentials([usernamePassword(
                    credentialsId: 'DockerHubCredentials',
                    passwordVariable: 'dockerHubPass',
                    usernameVariable: 'dockerHubUser'
                )]) {
                    echo 'Logging in to Docker Hub'
                    sh 'docker login -u ${dockerHubUser} -p ${dockerHubPass}'
                    echo 'Tagging Backend Docker image'
                    sh 'docker tag wanderlust-back-node:v1 ${dockerHubUser}/wanderlust-back-node:Backend'
                    echo 'Pushing Backend Docker image to Docker Hub'
                    sh 'docker push ${dockerHubUser}/wanderlust-back-node:Backend'

                    echo 'Tagging Frontend Docker image'
                    sh 'docker tag wanderlust-front-react:v2 ${dockerHubUser}/wanderlust-front-react:Frontend'
                    echo 'Pushing Frontend Docker image to Docker Hub'
                    sh 'docker push ${dockerHubUser}/wanderlust-back-node:Frontend'
                    echo 'Both Frontend and Backend Docker image Pushed to DockerHub Successfully Completed..!!'                
                }
            }
        }
        stage('Deploy with Docker Compose: Last-Step') {
            agent { label 'DEV' }
            steps {
                echo 'Deploying with Docker Compose'
                sh 'docker-compose down'
                sh 'docker-compose up -d'
            }
        }
    }
}

***************************************************************
Wanderlust Agent-1 Dev
Wonderlust agent dev environment.

Wanderlust Agent-2 Prod
Wonderlust agent Prod environment.

Wanderlust Agent-3 QA
Wonderlust agent QA environment.

Workspace Created:
/home/ubuntu/app

Conclusion

Jenkins Freestyle Projects offer DevOps engineers a flexible and powerful way to automate the build, test, and deployment processes of their applications. By leveraging Docker and Docker Compose within Jenkins, engineers can ensure consistent and reliable environments for their applications, streamline their CI/CD pipelines, and ultimately deliver high-quality software more efficiently. Whether you're building a simple application or managing complex microservices, Jenkins provides the tools and integrations necessary to support your DevOps practices and enhance your development workflow.

Connect and Follow:

LinkedIn | Twitter | GitHub

Like👍 | Share📲 | Comment💭