Jenkins (CICD) - On-Premises

·

6 min read

Clone the Jenkins Helm chart to your GitHub repository

git clone https://github.com/jenkinsci/helm-charts

Modify values.yaml to set account information

## Sections to modify

-- Update login information
admin:
  username: "WHAT YOU WANT"  # Set admin username
  password: "WHAT YOU WANT" # Set admin password

...

-- Update the following section to enable login

# Jenkins Config as Code Security Realm-section
securityRealm: |-
  local:
    allowsSignup: false  # Disable user signup
    enableCaptcha: false # Disable captcha
    users:
    - id: "WHAT YOU WANT"      # Set admin user ID
      password: "WHAT YOU WANT" # Set admin user password

ArgoCD - Connect to your Git repository to configure Jenkins CD

Creating a Jenkins Item

Create a new item

  • Select Pipeline

Configure GitHub project

  • Check GitHub project

  • Enter the repository URL

Set build trigger

  • Check GitHub hook trigger for GITScm polling

Define the pipeline

  • Choose either Pipeline script or Pipeline script from SCMCreating the Jenkins Pipeline (CI/CD)

  • Jenkins Pipeline Configuration

      pipeline {
          agent {
              kubernetes {
                  label 'jenkins-agent'
                  yaml """
                  apiVersion: v1
                  kind: Pod
                  spec:
                    containers:
                    - name: jnlp
                      image: jenkins/inbound-agent:latest
                      args: ['\$(JENKINS_SECRET)', '\$(JENKINS_NAME)']
                    - name: docker
                      image: docker:20.10
                      command:
                      - cat
                      tty: true
                      volumeMounts:
                      - name: docker-socket
                        mountPath: /var/run/docker.sock
                    - name: kubectl
                      image: lachlanevenson/k8s-kubectl:latest
                      command:
                      - cat
                      tty: true
                      volumeMounts:
                      - name: kube-config
                        mountPath: /home/jenkins/.kube
                    volumes:
                    - name: docker-socket
                      hostPath:
                        path: /var/run/docker.sock
                        type: Socket
                    - name: kube-config
                      configMap:
                        name: kube-config
                  """
              }
          }
          environment {
              GIT_CREDENTIALS_ID = 'YOUR GIT TOKEN CREDENTAIL ID IN JENKINS'  // GitHub credentials token
              DOCKER_HUB_REPO = 'YOUR REPOSITORY'  // Docker Hub repository
              SLACK_CHANNEL = 'YOUR SLACK CHANNEL'  // Slack notification channel
              SLACK_CREDENTIAL_ID = 'YOUR SLACK TOKEN CREDENTAIL ID IN JENKINS'  // Slack credentials token
              KUBECONFIG_PATH = '/home/jenkins/.kube/kubeconfig'  // Kubernetes config path
          }
    
          stages {
              stage('Clone Repository') {
                  steps {
                      container('jnlp') {
                          git credentialsId: env.GIT_CREDENTIALS_ID, branch: 'main', url: 'https://github.com/hee-bin/frontend-cicd-test.git'  // Clone Git repository
                      }
                  }
              }
    
              stage('Build Docker Image') {
                  steps {
                      container('docker') {
                          script {
                              def customImage = docker.build("${DOCKER_HUB_REPO}:${env.BUILD_ID}")  // Build Docker image
                          }
                      }
                  }
              }
    
              stage('Test Docker Image') {
                  steps {
                      script {
                          def dockerImageTag = "${DOCKER_HUB_REPO}:${env.BUILD_ID}"
                          sh "docker run --rm -d --name test_container ${dockerImageTag} npm run dev"  // Run Docker container
                          sh "docker exec test_container echo 'I am running'"  // Check container status
                          sh "docker stop test_container"  // Stop container
                      }
                  }
              }
    
              stage('Push Docker Image') {
                  steps {
                      container('docker') {
                          script {
                              withCredentials([usernamePassword(credentialsId: 'dockerHub-token', usernameVariable: 'DOCKERHUB_USER', passwordVariable: 'DOCKERHUB_PASS')]) {
                                  sh "echo ${DOCKERHUB_PASS} | docker login -u ${DOCKERHUB_USER} --password-stdin"  // Docker Hub login
                                  sh "docker tag ${DOCKER_HUB_REPO}:${env.BUILD_ID} ${DOCKER_HUB_REPO}:${env.BUILD_ID}"  // Tag Docker image
                                  sh "docker push ${DOCKER_HUB_REPO}:${env.BUILD_ID}"  // Push Docker image
                                  sh "docker tag ${DOCKER_HUB_REPO}:${env.BUILD_ID} ${DOCKER_HUB_REPO}:latest"
                                  sh "docker push ${DOCKER_HUB_REPO}:latest"
                              }
                          }
                      }
                  }
              }
    
              stage('Deploy to Kubernetes') {
                  steps {
                      container('kubectl') {
                          script {
                              withEnv(["KUBECONFIG=${env.KUBECONFIG_PATH}"]) {
                                  def deploymentExists = sh(script: 'kubectl get deployment frontend', returnStatus: true) == 0  // Check if deployment exists
                                  if (deploymentExists) {
                                      sh "kubectl set image deployment/frontend frontend=${DOCKER_HUB_REPO}:${env.BUILD_ID} --record"  // Update existing deployment
                                  } else {
                                      sh 'kubectl apply -f test.yml'  // Apply new deployment
                                  }
                              }
                          }
                      }
                  }
              }
          }
    
          post {
              always {
                  script {
                      slackSend(channel: env.SLACK_CHANNEL, message: "Build ${currentBuild.fullDisplayName} finished with status: ${currentBuild.currentResult}")  // Send Slack notification
                  }
              }
              success {
                  script {
                      slackSend(channel: env.SLACK_CHANNEL, message: "Build ${currentBuild.fullDisplayName} succeeded")  // Send success notification
                  }
              }
              failure {
                  script {
                      slackSend(channel: env.SLACK_CHANNEL, message: "Build ${currentBuild.fullDisplayName} failed")  // Send failure notification
                  }
              }
          }
      }
    
  • Kubeconfig File:

    • Contains information for accessing and interacting with Kubernetes cluster.

    • Includes:

      • Cluster Information: Kubernetes API server address.

      • User Information: Authentication details (certificates, tokens).

      • Context Information: Links users to clusters, facilitates easy switching.

  • Role of KUBECONFIG_PATH:

    • Cluster Authentication:

      • Provides access details to Kubernetes cluster.

      • Ensures authenticated interaction for kubectl commands.

    • Command Execution:

      • Used by kubectl to interact with the cluster.

      • Necessary for checking deployments, applying new ones, etc.

  • Example Usage:

    • Jenkins Pipeline:

        pipeline {
            // Jenkins agent and other settings...
      
            environment {
                GIT_CREDENTIALS_ID = 'YOUR GIT TOKEN CREDENTIAL ID IN JENKINS'
                DOCKER_HUB_REPO = 'YOUR REPOSITORY'
                SLACK_CHANNEL = 'YOUR SLACK CHANNEL'
                SLACK_CREDENTIAL_ID = 'YOUR SLACK TOKEN CREDENTIAL ID IN JENKINS'
                KUBECONFIG_PATH = '/home/jenkins/.kube/kubeconfig'  // Kubernetes config path
            }
      
            stages {
                // Other stages...
      
                stage('Deploy to Kubernetes') {
                    steps {
                        container('kubectl') {
                            script {
                                withEnv(["KUBECONFIG=${env.KUBECONFIG_PATH}"]) {
                                    // Check if Kubernetes deployment exists
                                    def deploymentExists = sh(script: 'kubectl get deployment frontend', returnStatus: true) == 0
                                    if (deploymentExists) {
                                        // Update existing deployment
                                        sh "kubectl set image deployment/frontend frontend=${DOCKER_HUB_REPO}:${env.BUILD_ID} --record"
                                    } else {
                                        // Apply new deployment
                                        sh 'kubectl apply -f test.yml'
                                    }
                                }
                            }
                        }
                    }
                }
            }
      
            // Post actions...
        }
      
  • Key Takeaways:

    • KUBECONFIG_PATH:

      • Specifies the path to the Kubeconfig file.

      • Essential for secure communication and deployment tasks in Kubernetes cluster.

Setting Up Jenkins Credentials

    environment {
        GIT_CREDENTIALS_ID = 'YOUR GIT TOKEN CREDENTAIL ID IN JENKINS'  // GitHub credentials token
        DOCKER_HUB_REPO = 'YOUR REPOSITORY'  // Docker Hub repository
        SLACK_CHANNEL = 'YOUR SLACK CHANNEL'  // Slack notification channel
        SLACK_CREDENTIAL_ID = 'YOUR SLACK TOKEN CREDENTAIL ID IN JENKINS'  // Slack credentials token
        KUBECONFIG_PATH = '/home/jenkins/.kube/kubeconfig'  // Kubernetes config path
    }
  • Git Credentials: Token for GitHub or GitLab

  • Docker Hub Credentials: Token for Docker Hub or GCR

  • Slack Token: Generated upon installing Jenkins CI in Slack

Integrating Jenkins with GitHub Webhook

Jenkins Configuration

Create Item

  • Select GitHub project

  • Enter the repository URL

  • Check Build Triggers for GitHub hook trigger for GITScm polling

GitHub Configuration

Set Up Webhook

  • Navigate to repository > settings > webhooks

  • Set the Payload URL to http://<jenkins-server-url>/github-webhook0

    • /github-webhook !!!!!

    • USE IP instead of DOMAIN

Integrating Jenkins with Slack

Slack Configuration

Install Jenkins CI App in Slack

  • Create and Configure Notification Channel

  • Generate Slack Token

Jenkins Configuration

Install Slack Notification Plugin

  • Manage Jenkins > Manage Plugins > Available > Slack Notification Plugin

Store Credentials

  • Store the generated Slack token as a credential in Jenkins

Configure Slack Notifier in Jenkins

  • Manage Jenkins > Configure System > Slack Notifier

  • Set Workspace and Credential

Pipeline Configuration

  • For Freestyle projects, configure Slack notification in the Post-build Actions section

  • For Pipeline projects, define Slack notification in the Jenkinsfile

    This guide explains how to set up Jenkins using Helm, integrate it with GitHub and Slack for a complete CI/CD pipeline, and automate build, test, and deployment processes using a Jenkins pipeline script.