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.
NoteGitLab 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.
Create a project in GitLab.
Log on to GitLab.
In the top navigation bar, choose Projects > Your projects.
On the Projects page, click New Project in the upper-right corner, and then click Create blank project.
On the Create blank project page, set Project name, Project URL, and Project slug. Set Visibility Level to Private, and then click Create project.

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()); } }
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
Configure a pipeline in Jenkins to build the image.
Configure the GitLab SSH key in Jenkins.
Log on to Jenkins.
In the left-side navigation pane, click Manage Jenkins.
In the Security section, click Manage Credentials.
In the Stores scoped to Jenkins section, click Jenkins in the Store column, and then click Global credentials.
In the left-side navigation pane, click Add Credentials.
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.
Create a pipeline.
In the left-side navigation pane of the Jenkins dashboard, click New Item.
Enter a name for the item, select Pipeline, and then click OK.
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.
Click Advanced, and then click Generate next to Secret token.
Jenkins generates a secret token. Save this token for later use.
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}" } }
Add the webhook URL to GitLab.
Log on to GitLab.
On the Projects page, click the project that you created.
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.
Create an event notification rule.
Log on to the Container Registry console.
In the top navigation bar, select a region.
In the left-side navigation pane, click Instances.
On the Instances page, click the Enterprise Edition instance that you want to manage.
In the left-side navigation pane of the instance details page, choose .
On the Event Rules tab, click Create Rule.
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
nsnamespace, and then click Next.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.
Trigger an image build.
Run the following command to modify the
HelloController.javafile 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 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.
Set up a security scan.
On the Security Scan page, find the target image tag and click Security Scan in the Security Scan column.
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.
Create an application.
Log on to the Container Service Management Console.
In the left navigation pane, click Cluster.
On the Cluster List page, click the name of the destination cluster or click Details in the Actions column.
In the left navigation pane of the cluster management page, choose .
On the Deployments page, select a Namespace and click Create from YAML.
On the Create from YAML panel, set Sample Template to Custom. Copy the following code into the template, and then click Create.
NoteIf 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 ---On the Deployments page, click the application
demo, and then click the Access Method tab.On the Access Method tab, obtain the external endpoint.
Add the following entry to your local hosts file.
<external endpoint address> app.demo.example.comEnter app.demo.example.com in your browser's address bar.
The page shown above indicates that the application is successfully deployed.
Create a trigger.
On the Deployments page, click the
demoapplication.On the application details page, click the Triggers tab, and then click Create Trigger.
In the Create Trigger dialog box, set Action to Redeploy and click OK.
On the Triggers tab, obtain the trigger URL.
Create a pipeline.
Log on to Jenkins.
In the left-side navigation pane, click New Item.
Enter a name for the item, select Pipeline, and then click OK.
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, theGeneric Webhook tokenis set tohelloworld2021. Therefore, the webhook URL isJENKINS_URL/generic-webhook-trigger/invoke?token=helloworld2021.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'" } } } }
Create a delivery chain. For more information, see Create a delivery chain.
Create an event rule.
On the management page of the ACR Enterprise Edition instance, choose in the left-side navigation pane.
On the Event Rules tab, click Create Rule.
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
nsnamespace, and then click Next.In the Event Notification step, set Notification Method to HTTP. Enter the webhook URL that you obtained in Step 3, and then click Save.
Run the following command to modify the
HelloController.javafile 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.
Run the following command to verify that the application is redeployed.
curl app.demo.example.comIf the output changes, the application is successfully redeployed.