Updated on 2025-01-08 GMT+08:00

Implementing Continuous Integration and Deployment

To implement this solution, Jenkins must be triggered for compilation and packaging via a code push event. Once the request is approved via email, the application can be deployed in a Kubernetes cluster.

Installing Jenkins Plugins

In addition to the default plugins installed during Jenkins installation, you also need to install the GitLab, Kubernetes CLI, and Email Extension Template plugins. For details, see the Jenkins official documentation.

On the Jenkins dashboard page, click Manage Jenkins on the left and choose System Configuration > Manage Plugins. On the Available tab, search for GitLab, Kubernetes CLI, and Email Extension Template, and install them.

The versions of the preceding plugins may change over time.

Configuring GitLab Hooks

Once you push your code, GitLab will notify Jenkins of the event using webhooks. To ensure this process runs smoothly, you must first configure GitLab hooks.

  1. Log in to Jenkins, click New Item, and create a pipeline.

  2. Copy the URL and click Advanced.

  3. Click Generate to generate a token, record it, retain the default values for other parameters, and save the changes.

  4. Log in to GitLab and enable webhooks.

    Allow requests to local network. To enhance security, GitLab 10.6 and later versions prohibit webhook requests from being sent to the local network.

  5. Log in to the java-demo project on GitLab, choose Settings > Webhooks, and enter the values recorded in Jenkins in URL and Secret token.

  6. At the bottom of the page, confirm that the webhook is added and perform tests.

Configuring Email Notifications

Jenkins often uses email for message notifications and approvals. This solution also employs email as the approval method.

  1. On the Manage Jenkins page, select System.

  2. Configure basic mailbox information and enter the email address of the administrator.

    The password is not the email password but the email authorization code.

Configuring a Credential

Accessing Kubernetes clusters through HTTPS is crucial for maintaining security. To achieve this, you must configure the credentials for accessing the clusters on Jenkins.

  1. Obtain the kubeconfig configuration of the Kubernetes cluster client. For details, see Connecting to a Cluster Using kubectl.
  2. Log in to Jenkins, click Manage Jenkins, choose Manage Credentials under Security, and create a cluster credential using the secret file.

  3. Repeat the preceding steps to create an access credential for the production cluster.

Writing Pipeline Scripts

Pipeline is a workflow framework that operates within Jenkins. It links tasks that would typically run independently on one or more nodes, allowing for the orchestration and visualization of complex processes that cannot be completed by a single task. As the primary feature of Jenkins 2.X, it enables Jenkins to transition from CI to CD and DevOps. Consequently, the writing of pipeline scripts is crucial to the successful implementation of the entire solution.

The following shows the concepts of pipeline scripts:

  • Node

    A node is a machine which is part of the Jenkins environment and is capable of executing a pipeline.

  • Stage

    A stage block defines a group of specific tasks to be executed in different stages such as the build, test, and deploy stages through the entire pipeline.

  • Step

    A step is a single task in a stage, such as running a test or deploying code. It tells Jenkins what to do at a specific time, for example, to execute the shell command. (For more Jenkins pipeline syntax, see the Jenkins official documentation.)

  1. Go to the Jenkins pipeline and click Configuration in the navigation pane.
  2. Configure the pipeline scripts. The following pipeline scripts are for reference only. You can customize the scripts based on your service requirements.

    Some parameters in the example need to be changed:

    • git_url: specifies the SSH address of the code repository in GitLab. You need to replace it with the actual value.
    • swr_login: The login command is the command obtained in 3.
    • swr_region: specifies the region of SWR. You need to specify the region as needed.
    • organization: specifies the actual organization name in SWR.
    • build_name: specifies the name of the created image.
    • credential: specifies the testing cluster credential added to Jenkins. You need to enter the credential ID. To deploy the service in another cluster, add the access credential of the cluster to Jenkins again. For details, see cluster access credential configurations.
    • prod_credential: specifies the production cluster credential added to Jenkins. You need to enter the credential ID. To deploy the service in another cluster, add the access credential of the cluster to Jenkins again. For details, see cluster access credential configurations.
    • test_apiserver: specifies the API server address of the testing cluster. For details, see Connecting to a Cluster Using kubectl. You have to ensure that the address can be accessed from the Jenkins cluster.
    • prod_apiserver: specifies the API server address of the production cluster. For details, see Connecting to a Cluster Using kubectl. You have to ensure that the address can be accessed from the Jenkins cluster.
    • test_email: specifies the email address of the test personnel.
    • admin_email: specifies the email address of the approver.
    #!groovy
    //Define the code repository address.
    def git_url = 'ssh://git@xxxx:222/ccedemo/java-demo.git' 
    //Define the SWR login command.
    def swr_login = 'docker login -u cn-north-4@xxxx -p xxxxxx swr.cn-north-4.myhuaweicloud.com'
    //Define the SWR region.
    def swr_region = 'cn-north-4'
    // Specify the name of an SWR organization to which images are pushed.
    def organization = 'testapp'
    //Define the image name.
    def build_name = 'demo01'
    //Certificate ID of the testing cluster
    def test_credential = 'test_config'
    //Certificate ID of the production cluster
    def prod_credential = 'prod_config'
    //API server address of the testing cluster. You have to ensure that the address can be accessed from the Jenkins cluster.
    def test_apiserver = 'https://xxx:5443'
    //API server address of the production cluster. You have to ensure that the address can be accessed from the Jenkins cluster.
    def prod_apiserver = 'https://xxxx:5443'
    // Email addresses
    def test_email="xxxxx@xx.com"
    def admin_email="xxxx@xx.com"
    
    pipeline{
    agent any
    stages{
        stage('Git code'){
            steps{
                echo "1. Git code" 
                git url: git_url
                script { 
                    // Specify the return value of git rev-parse --short HEAD as the commit ID, which is then used as the image tag.
                    build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim() 
                    image_url = "swr.${swr_region}.myhuaweicloud.com/${organization}/${build_name}:${build_tag}"  
                    } 
                }
        }
        stage('Build') {
            steps{
                echo "2. Build Docker Image Stage and Push Image" 
                sh "docker build -t  ${image_url} ." 
                sh swr_login
                sh "docker push ${image_url}"
                // Replace the image URL with that in the Kubernetes resource file.
                sh  "sed -i 's+demo01:v1+${image_url}+g' ./demo01.yaml"
            }
        }
        stage('Deploy Test Enviroment') {
            steps{
                // Configure the testing environment certificate.
                echo "3. Deploy Test Enviroment"
                script {
                    try {
                        withKubeConfig([credentialsId: test_credential, serverUrl: test_apiserver]) {
                            sh 'kubectl apply -f ./demo01.yaml'
                            //The YAML file is stored in the code repository. It is only used as an example here, so you need to replace it as required.
                        }
                        println "deploy success"
                        // Send an email to the test personnel.
                        mail subject: "[Please Test] The application has been deployed in the test environment. Please start the test.",
                        body: """After the test is passed, <a href="${BUILD_URL}input">click the link and use the account to log in to the system. The test is successful.</h3>""",
                        charset: 'utf-8',
                        mimeType: 'text/html',
                        to: "$test_email"
                    } catch (e) {
                        RUN_FLAG = false
                        println "deploy failed!"
                        println e
                    }
                }
            }
        }
        stage('Test'){
            // Wait for the test personnel to make confirmation.
            input{ 
                message "Test Passed or Not"
                submitter "admin"
            }
            steps{
                script{
                    println "4. Test Passed"
                    // Send an email to the administrator.
                    mail subject: "[Please Approve] Release to the production environment",
                    body: """The test is passed, <a href="${BUILD_URL}input">click the link and use the account to log in to the system for approval.</h3>""",
                    charset: 'utf-8',
                    mimeType: 'text/html',
                    to: "$test_email"
                }
            }
        }
        stage('Approve'){
            input{ 
                message "Release to Production Environment or Not"
                submitter "admin" 
            }
            steps{
                script{
                    println "5. Approved and release it to the production environment."
                }
            }
        }
        stage('Deploy Produce Enviroment'){
            steps{
                echo "6. Deploy Produce Enviroment"
                script {
                    try {
                        withKubeConfig([credentialsId: prod_credential, serverUrl: prod_apiserver]) {
                            sh 'kubectl apply -f ./demo01.yaml'
                            //The YAML file is stored in the code repository. It is only used as an example here, so you need to replace it as required.
                        }
                        println "deploy success"
                    } catch (e) {
                        println "deploy failed!"
                        println e
                    }
                }
            }
        }
    }

  3. Save the changes to complete the configurations of the entire project.

Configuring Continuous Build and Deployment

  1. Modify the local code and submit it to trigger compilation.

    git add . && git commit -m "add template" && git push

  2. Go back to the Jenkins page.

    You can see that the project has automatically triggered compilation and building.

  3. Wait a few minutes for the email notification confirming the test.

  4. Log in to the testing cluster and verify that the java-demo workload has been created.

  5. Click the link in the email to confirm the test. (In this example, the upgrade test is considered to pass.)

  6. (For the approver) Receive an email requesting approval.

  7. (For the approver) Determine that the service can be deployed in the production environment, click the link, and agree to the request.

  8. Access the production cluster console and verify that the java-demo workload has been created and released in the production environment.