Jenkins Project: Building CI/CD Pipeline for Scalable Web Applications

Kubernetes

Demo Configuring Jenkins Pipeline for Kubernetes

In this lesson, you'll learn how to configure a Jenkins pipeline to deploy a Dockerized application to a Kubernetes cluster using AWS EKS. The guide covers setting up Jenkins credentials, creating the pipeline, reviewing the Jenkinsfile, and troubleshooting file permission issues with the kubeconfig file.


1. Configuring Credentials in Jenkins

Begin by navigating to Manage Jenkins → Credentials. Note that Docker credentials are preconfigured. You now need to create a credential for the kubeconfig file, which typically resides in your home directory at .kube/config.

The image shows a Jenkins dashboard displaying a list of credentials, including IDs and names for various global domains.

Click on Add Credentials. Choose the credential type "Secret file". For the file field, enter the full path (for example, /home/username/.kube/config) and assign a credential ID such as kubeconfig-credentials-id.

The image shows a Jenkins interface for creating new credentials, specifically a secret file with fields for scope, file, ID, and description. The "Create" button is visible at the bottom.


2. Creating the Jenkins Pipeline

Next, set up a new pipeline project. Click on New Item, give it a name (for example, "Amazon EKS Pipeline"), and select Pipeline as the project type.

The image shows a Jenkins interface displaying a list of global credentials, including secret texts, SSH keys, and usernames with passwords.

Configure the job by enabling the GitHub hook trigger for Git SCM polling. Under the pipeline configuration, select "Pipeline script from SCM" and set the SCM option to Git. Enter your Git repository URL and select the branch (in this example, main).

The image shows a Jenkins interface for creating a new item, with options to select different project types such as Freestyle project, Pipeline, and Multi-configuration project. The item name "EKS-Pipeline" is entered in the text box.

The image shows a configuration screen for setting up a pipeline, with options to select a source control management (SCM) system, enter a repository URL, and manage credentials. The SCM is set to Git, and there's a prompt to enter a Git repository URL.

The image shows a configuration screen for a pipeline setup, with options to specify branches to build and other repository settings. The branch specifier is set to "*/main".


3. Reviewing and Updating the Jenkinsfile

The Jenkinsfile outlines the environment variables and defines various stages for building, testing, and deploying your application. It includes credentials for the kubeconfig file and AWS keys, which are necessary for working with Amazon EKS.

Below is the enhanced Jenkinsfile that includes stages for environment setup (with troubleshooting for kubeconfig permissions), testing, Docker Hub login, image building and pushing, and deployments to both staging and production clusters.

pipeline {
    agent any

    environment {
        IMAGE_NAME = 'sanjeevkt720/jenkins-flask-app'
        IMAGE_TAG = "${IMAGE_NAME}:${env.GIT_COMMIT}"
        KUBECONFIG = credentials('kubeconfig-credentials-id')
        AWS_ACCESS_KEY_ID = credentials('aws-access-key')
        AWS_SECRET_ACCESS_KEY = credentials('aws-secret-key')
    }

    stages {
        stage('Setup') {
            steps {
                // List kubeconfig file permissions for troubleshooting.
                sh 'ls -la $KUBECONFIG'
                // Adjust file permissions if necessary.
                sh 'chmod 644 $KUBECONFIG'
                sh 'ls -la $KUBECONFIG'
                // Install Python dependencies.
                sh 'pip install -r requirements.txt'
            }
        }
        stage('Test') {
            steps {
                sh 'pytest'
            }
        }
        stage('Login to Docker Hub') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'docker-creds',
                                                  usernameVariable: 'USERNAME', 
                                                  passwordVariable: 'PASSWORD')]) {
                    sh 'echo $PASSWORD | docker login -u $USERNAME --password-stdin'
                    echo 'Docker login successful'
                }
            }
        }
        stage('Build and Push Docker Image') {
            steps {
                sh 'docker build -t $IMAGE_TAG .'
                echo 'Docker image built successfully'
                sh 'docker image ls'
                sh 'docker push $IMAGE_TAG'
                echo 'Docker image pushed successfully'
            }
        }
        stage('Deploy to Staging') {
            steps {
                // Switch Kubernetes context to the staging cluster.
                sh 'kubectl config use-context [email protected]'
                sh 'kubectl config current-context'
                // Update the staging deployment image.
                sh "kubectl set image deployment/flask-app flask-app=$IMAGE_TAG"
                // Retrieve service endpoint and run acceptance tests.
                script {
                    def service = sh(script: "kubectl get svc flask-app-service -o jsonpath='{.status.loadBalancer.ingress[0].hostname}:{.spec.ports[0].port}'", returnStdout: true).trim()
                    echo "Service endpoint: ${service}"
                    sh "k6 run -e SERVICE=${service} acceptance-test.js"
                }
            }
        }
        stage('Deploy to Production') {
            steps {
                // Switch Kubernetes context to the production cluster.
                sh 'kubectl config use-context [email protected]'
                sh 'kubectl config current-context'
                // Update the production deployment image.
                sh "kubectl set image deployment/flask-app flask-app=$IMAGE_TAG"
            }
        }
    }
}

Key highlights of this Jenkinsfile:

  • Setup: Lists and updates kubeconfig file permissions to ensure Jenkins has write access. It then installs the required Python dependencies.
  • Test: Runs the test suite using pytest.
  • Login to Docker Hub: Authenticates with Docker Hub using stored credentials.
  • Build and Push Docker Image: Builds the Docker image, verifies it by listing images, and then pushes it to Docker Hub.
  • Deploy to Staging: Switches to the staging Kubernetes context, updates the deployment's image, retrieves the service endpoint, and runs acceptance tests with K6.
  • Deploy to Production: Switches the Kubernetes context to production and updates the deployment with the new image.

4. Troubleshooting File Permission Issues

During one of the builds, a file permission error occurred when attempting to change the Kubernetes context, indicating that the kubeconfig file was not writable. To resolve this issue, the Jenkinsfile was enhanced with diagnostic commands that:

  • List the kubeconfig file permissions using ls -la $KUBECONFIG.
  • Adjust file permissions with chmod 644 $KUBECONFIG.
  • Confirm the updated permissions before proceeding.

Review the Jenkins build output to verify that the permissions have been updated successfully. Once the permissions are correct, subsequent commands (such as switching contexts with kubectl config use-context) will execute without error.

The image shows a Jenkins dashboard for an "EKS-Pipeline" with build history and status details, including recent build times and outcomes.


5. Updating Application Code

After successfully deploying the initial version, you may update your application code. For example, consider the following HTML snippet for a simple Todo App (version 1):

<html>
<head>
    <style>
        .task-item {
        }
        .task-text {
            margin: 0;
        }
    </style>
</head>
<body>
    <h1>Todo App: v1</h1>
    <!-- Add Task Form -->
    <form method="post">
        <input type="text" name="task_content" placeholder="Enter a new task" />
        <input type="submit" name="add_task" value="Add Task" />
    </form>
    <!-- Display Tasks -->
</body>
</html>

When you update the app to a new version (e.g., version 2) and push the changes to Git, a new build will be triggered. Once the build completes successfully, verify that both the staging and production environments reflect the updated version.


By following these steps, you can implement a robust Jenkins pipeline that automates the build, testing, and deployment of a Dockerized application on Kubernetes using Amazon EKS. This streamlined pipeline also addresses common permission issues, ensuring a smooth continuous delivery workflow.

Key Benefit

Automating the deployment with Jenkins reduces manual errors and accelerates your development pipeline, helping you achieve faster delivery cycles while maintaining consistency across environments.

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
Configuring Jenkins Pipeline for Kubernetes