All Products
Search
Document Center

Container Registry:CI/CD for images with Jenkins

Last Updated:Apr 25, 2026

This tutorial shows you how to create a fully automated workflow that builds an image from source code, pushes the image to a repository, and deploys the application. Using Jenkins with GitLab, Container Registry (ACR), and Container Service for Kubernetes (ACK), you can automatically build images when source code is committed, deploy applications, and send event notifications to a DingTalk group.

Prerequisites

  • Git, GitLab, and Jenkins are installed.

    Note

    GitLab requires JDK 8. Some plugins do not run on JDK 11.

  • You have created an ACR Enterprise Edition instance and enabled internet access. For more information, see Create an Enterprise Edition instance and Configure internet access.

  • You have created an ACK cluster that is in the same region as your ACR instance. For more information, see Create an ACK managed cluster.

  • You have created a DingTalk chatbot and recorded its webhook URL and secret token. For more information, see Step 1: Create a DingTalk chatbot.

  • To use the delivery chain feature of Container Registry (ACR), you must upgrade your instance to the Advanced Edition. For more information, see Billing.

CI for images with Jenkins

When you commit source code to GitLab, Container Registry (ACR) automatically builds an image. You can then run a security scan on the image. After the scan is complete, an event notification is sent to your DingTalk group.

  1. Create a project in GitLab.

    1. Log on to GitLab.

    2. In the top navigation bar, choose Projects > Your projects.

    3. On the Projects page, click New Project in the upper-right corner, and then click Create blank project.

    4. On the Create blank project page, set Project name, Project URL, and Project slug. Set Visibility Level to Private, and then click Create project.

      创建Project

    5. Use the following content to create the Dockerfile, pom.xml, DemoApplication.java, and HelloController.java files on your local computer.

      • Dockerfile

        FROM registry.cn-hangzhou.aliyuncs.com/public-toolbox/maven:3.8.3-openjdk-8-aliyun AS build
        COPY src /home/app/src
        COPY pom.xml /home/app
        RUN ["/usr/local/bin/mvn-entrypoint.sh","mvn","-f","/home/app/pom.xml","clean","package","-Dmaven.test.skip=true"]
        
        FROM registry.cn-hangzhou.aliyuncs.com/public-toolbox/openjdk:8-jdk-alpine
        COPY --from=build /home/app/target/demo-0.0.1-SNAPSHOT.jar /usr/local/lib/demo-0.0.1-SNAPSHOT.jar
        EXPOSE 8080
        ENTRYPOINT ["java","-jar","/usr/local/lib/demo-0.0.1-SNAPSHOT.jar"]
      • pom.xml

        <?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
            <modelVersion>4.0.0</modelVersion>
            <parent>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>2.6.1</version>
                <relativePath/> <!-- lookup parent from repository -->
            </parent>
            <groupId>com.example</groupId>
            <artifactId>demo</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <name>demo</name>
            <description>Demo project for Spring Boot</description>
            <properties>
                <java.version>1.8</java.version>
            </properties>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-freemarker</artifactId>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
        
                <dependency>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                    <optional>true</optional>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-test</artifactId>
                    <scope>test</scope>
                </dependency>
                <dependency>
                    <groupId>org.apache.logging.log4j</groupId>
                    <artifactId>log4j-core</artifactId>
                    <version>2.13.2</version>
                </dependency>
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <excludes>
                                <exclude>
                                    <groupId>org.projectlombok</groupId>
                                    <artifactId>lombok</artifactId>
                                </exclude>
                            </excludes>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        
        </project>
      • DemoApplication.java

        package com.example.demo;
        
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        
        import java.util.TimeZone;
        
        @SpringBootApplication
        public class DemoApplication {
        
            public static void main(String[] args) {
                TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
                SpringApplication.run(DemoApplication.class, args);
            }
        
        }
      • HelloController.java

        package com.example.demo;
        
        import lombok.extern.slf4j.Slf4j;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.RestController;
        
        import javax.servlet.http.HttpServletRequest;
        import java.text.SimpleDateFormat;
        import java.util.Date;
        
        @RestController
        @Slf4j
        public class HelloController {
        
            @RequestMapping({"/hello", "/"})
            public String hello(HttpServletRequest request) {
                return "Hello World at " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            }
        }
    6. Run the following command to upload the build files to GitLab.

      cd java-web  # Go to the directory where the build files are located.
      git remote set-url origin http://8.218.20*.***/shoppingmall/java-web.git
      git push origin master
      * [new branch]      master -> master
  2. Configure a pipeline in Jenkins to build the image.

    1. Configure the GitLab SSH key in Jenkins.

      1. Log on to Jenkins.

      2. In the left-side navigation pane, click Manage Jenkins.

      3. In the Security section, click Manage Credentials.

      4. In the Stores scoped to Jenkins section, click Jenkins in the Store column, and then click Global credentials.

      5. In the left-side navigation pane, click Add Credentials.

      6. Set Kind to SSH Username with private key. Enter a Description and Username. For the private key, select Enter directly, and then click OK.

        On the Global credentials page, an ID is automatically generated for the credential. Save this ID for later use.

    2. Create a pipeline.

      1. In the left-side navigation pane of the Jenkins dashboard, click New Item.

      2. Enter a name for the item, select Pipeline, and then click OK.

      3. Click the Build Triggers tab. Select Build when a change is pushed to GitLab, and then select Push Events.

        To the right of Build when a change is pushed to GitLab, copy the webhook URL.

      4. Click Advanced, and then click Generate next to Secret token.

        Jenkins generates a secret token. Save this token for later use.

      5. Click the Pipeline tab. In the following template, replace the placeholder values with your own information. Then, copy the content into the text box and click Save.

        def git_auth_id = "6d5a2c06-f0a7-43c8-9b79-37b8c266****"  # Credential ID.
        def git_branch_name = "master" # Branch name.
        def git_url = "git@172.16.1*.***:shoppingmall/java-web.git"   # GitLab repository URL.
        def acr_url = "s*****-devsecops-registry.cn-hongkong.cr.aliyuncs.com"  # Image repository URL.
        def acr_username = "acr_test_*****@test.aliyunid.com"   # Container Registry username.
        def acr_password = "HelloWorld2021"   # Container Registry password.
        def acr_namespace = "ns"    # Namespace.
        def acr_repo_name = "test"   # Image repository name.
        def tag_version = "0.0.1"   # Image tag.
        node {
        
            stage('checkout git repo') {
                checkout([$class: 'GitSCM', branches: [[name: "*/${git_branch_name}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth_id}", url: "${git_url}"]]])
            }
            stage('build image') {
                sh "sudo docker build -t java-web:${tag_version} ."
                sh "sudo docker tag java-web:${tag_version} ${acr_url}/${acr_namespace}/${acr_repo_name}:${tag_version}"
            }
            stage('push image') {
                sh "sudo docker login --username=${acr_username} --password=${acr_password} ${acr_url}"
                sh "sudo docker push ${acr_url}/${acr_namespace}/${acr_repo_name}:${tag_version}"
            }
        }
  3. Add the webhook URL to GitLab.

    1. Log on to GitLab.

    2. On the Projects page, click the project that you created.

    3. In the left-side navigation pane, choose Settings > Webhooks. Enter the webhook URL and secret token. Clear the Enable SSL verification checkbox, and then click Add webhooks.

  4. Create an event notification rule.

    1. Log on to the Container Registry console.

    2. In the top navigation bar, select a region.

    3. In the left-side navigation pane, click Instances.

    4. On the Instances page, click the Enterprise Edition instance that you want to manage.

    5. In the left-side navigation pane of the instance details page, choose Instances > Event Notification.

    6. On the Event Rules tab, click Create Rule.

    7. In the Event Scope step, set Rule Name. Set Event Type to The image is scanned. and select Scanned.. Set Effective Scope to Namespaces, select the ns namespace, and then click Next.

    8. In the Event Notification step, set Notification Method to DingTalk. Enter the webhook URL and secret token of your DingTalk chatbot, and then click Save.

  5. Trigger an image build.

    Run the following command to modify the HelloController.java file and commit it to GitLab. This triggers an image build.

    vim java/com/example/demo/HelloController.java # Modify the HelloController.java file locally based on your needs.
    git add . && git commit -m 'commit' && git push origin # Commit the file to GitLab.

    Wait for a moment. On the details page of the Enterprise Edition instance, select Repository > Repositories in the left navigation bar. On the page that appears, click the target repository test. On the Repository page, click Tags in the left navigation bar. You can see that an image is generated on the Tags page.

  6. Set up a security scan.

    1. On the Security Scan page, find the target image tag and click Security Scan in the Security Scan column.

    2. On the Security Scan page, click Scan.

      After the security scan is complete, you receive a notification in your DingTalk group.

CD for images with Jenkins

Committing source code to GitLab automatically builds an image in Container Registry (ACR). The completed build triggers a delivery chain. After the delivery chain is complete, an HTTP request is sent to Jenkins, which triggers the ACK deployment to pull the latest image and redeploy the application.

  1. Create an application.

    1. Log on to the Container Service Management Console.

    2. In the left navigation pane, click Cluster.

    3. On the Cluster List page, click the name of the destination cluster or click Details in the Actions column.

    4. In the left navigation pane of the cluster management page, choose Workload > Deployments.

    5. On the Deployments page, select a Namespace and click Create from YAML.

    6. On the Create from YAML panel, set Sample Template to Custom. Copy the following code into the template, and then click Create.

      Note

      If you do not configure password-free image pulling, you must enable internet access for Container Registry (ACR) and set the image repository to public. For more information, see Configure internet access.

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        creationTimestamp: null
        labels:
          app: demo
        name: demo
      spec:
        replicas: 3
        minReadySeconds: 5
        progressDeadlineSeconds: 60
        revisionHistoryLimit: 5
        selector:
          matchLabels:
            app: demo
        strategy:
          rollingUpdate:
            maxUnavailable: 1
          type: RollingUpdate
        template:
          metadata:
            annotations:
              prometheus.io/port: "9797"
              prometheus.io/scrape: "true"
            creationTimestamp: null
            labels:
              app: demo
          spec:
            containers:
            - image: s*****-devsecops-registry.cn-hongkong.cr.aliyuncs.com/ns/test:0.0.1 
              imagePullPolicy: Always
              name: demo
              ports:
              - containerPort: 8080
                name: http
                protocol: TCP
              readinessProbe:
                initialDelaySeconds: 5
                tcpSocket:
                  port: 8080
                timeoutSeconds: 5
              resources:
                limits:
                  cpu: "2"
                  memory: 512Mi
                requests:
                  cpu: 100m
                  memory: 64Mi
      status: {}
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: demo-svc
      spec:
        selector:
          app: demo
        ports:
          - protocol: TCP
            port: 80
            targetPort: 8080
      ---
      apiVersion: extensions/v1beta1
      kind: Ingress
      metadata:
        name: demo
        labels:
          app: demo
      spec:
        rules:
          - host: app.demo.example.com
            http:
              paths:
                - backend:
                    serviceName: demo-svc
                    servicePort: 80
      ---
                                      
    7. On the Deployments page, click the application demo, and then click the Access Method tab.

      On the Access Method tab, obtain the external endpoint.

    8. Add the following entry to your local hosts file.

      <external endpoint address> app.demo.example.com
    9. Enter app.demo.example.com in your browser's address bar.

      ApplicationThe page shown above indicates that the application is successfully deployed.

  2. Create a trigger.

    1. On the Deployments page, click the demo application.

    2. On the application details page, click the Triggers tab, and then click Create Trigger.

    3. In the Create Trigger dialog box, set Action to Redeploy and click OK.

      On the Triggers tab, obtain the trigger URL.

  3. Create a pipeline.

    1. Log on to Jenkins.

    2. In the left-side navigation pane, click New Item.

    3. Enter a name for the item, select Pipeline, and then click OK.

    4. Click the Build Triggers tab and select Generic Webhook Trigger.

      In the Generic Webhook Trigger section, the HTTP request trigger URL is JENKINS_URL/generic-webhook-trigger/invoke. In this tutorial, the Generic Webhook token is set to helloworld2021. Therefore, the webhook URL is JENKINS_URL/generic-webhook-trigger/invoke?token=helloworld2021.

    5. Click the Pipeline tab. In the following template, replace the placeholder Generic Webhook token and trigger URL with your actual values. Copy the modified content into the text box, and then click Save.

      pipeline {
        agent any
        triggers {
          GenericTrigger(
           genericVariables: [
            [key: 'InstanceId', value: '$.data.InstanceId'],   
            [key: 'RepoNamespaceName', value: '$.data.RepoNamespaceName'],
            [key: 'RepoName', value: '$.data.RepoName'],
            [key: 'Tag', value: '$.data.Tag']
           ],
           causeString: 'Triggered on $ref',
           token: 'helloworld2021',   # Generic Webhook token. Replace it with your actual token.
           tokenCredentialId: '',
           printContributedVariables: true,
           printPostContent: true,
           silentResponse: false,
           regexpFilterText: '$ref'
          )
        }
        stages {
          stage('Some step') {
            steps {
              sh "echo 'will print post content'"
              sh "echo $InstanceId"
              sh "echo $RepoNamespaceName"
              sh "echo $RepoName"
              sh "echo $Tag"
              sh "echo 'redeploy to ACK or you can deoloy to other platforms use before message'"
              sh "curl 'https://cs.console.alibabacloud.com/hook/trigger?token=g****'  # Trigger URL. Replace it with your actual URL.
              sh "echo 'done'"
            }
          }
        }
      }
  4. Create a delivery chain. For more information, see Create a delivery chain.

  5. Create an event rule.

    1. On the management page of the ACR Enterprise Edition instance, choose Instances > Event Notification in the left-side navigation pane.

    2. On the Event Rules tab, click Create Rule.

    3. In the Event Scope step, set Rule Name. Set Event Type to The delivery chain is processed. and select Success. Set Effective Scope to Namespaces, select the ns namespace, and then click Next.

    4. In the Event Notification step, set Notification Method to HTTP. Enter the webhook URL that you obtained in Step 3, and then click Save.

  6. Run the following command to modify the HelloController.java file and commit the code to GitLab. This triggers an image build.

    vim java/com/example/demo/HelloController.java # Modify the HelloController.java file locally based on your needs.
    git add . && git commit -m 'add update' && git push origin   # Commit the file to GitLab.

    The image build triggers the delivery chain. When the chain is complete, the ACK deployment is triggered to pull the new image and redeploy the application.

  7. Run the following command to verify that the application is redeployed.

    curl app.demo.example.com

    If the output changes, the application is successfully redeployed.