全部產品
Search
文件中心

Container Registry:使用Jenkins實現鏡像的CI/CD

更新時間:Sep 25, 2024

若您期望實現從原始碼自動構建、推送鏡像到最終部署應用的一體化自動化操作。您可以使用Jenkins實現鏡像的CI/CD,只要您在GitLab中提交原始碼,容器鏡像會自動使用原始碼構建鏡像,Container Service會自動拉取鏡像部署應用,並自動發送事件通知到DingTalk群。

前提條件

使用Jenkins實現鏡像的CI

只要您在GitLab中提交原始碼,容器鏡像會自動使用原始碼構建鏡像,然後您可以對鏡像進行漏洞掃描,鏡像掃描完成後,將自動發送事件通知到DingTalk群。

  1. 在GitLab中建立專案。

    1. 登入GitLab。

    2. 在頂部導覽列中,選擇Projects > Your projects

    3. Projects頁面單擊右上方的New Project,單擊Create blank project

    4. Create blank project版面設定Project nameProject URLProject slug,設定Visibility LevelPrivate,然後單擊Create project

      建立Project

    5. 使用以下內容,在本地建立Dockerfilepom.xmlDemoApplication.javaHelloController.java檔案。

      • 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. 執行以下命令,上傳構建檔案至GitLab。

      cd java-web  #進入構建檔案所在目錄。
      git remote set-url origin http://8.218.20*.***/shoppingmall/java-web.git
      git push origin master
      * [new branch]      master -> master
  2. 在Jenkins配置構建鏡像的流水線。

    1. 在Jenkins配置GitLab的SSH Key。

      1. 登入Jenkins。

      2. 在Jenkins左側導覽列單擊系統管理

      3. 安全地區單擊Manage Credentials

      4. Stores scoped to Jenkins地區單擊儲存列下的Jenkins,然後單擊全域憑據

      5. 在左側導覽列單擊添加憑據

      6. 設定類型為SSH Username with private key,然後輸入描述Username,選中Enter directly,然後單擊確定

        全域憑據頁面會自動產生憑據ID,儲存該憑據ID。

    2. 建立流水線。

      1. 在Jenkins左側導覽列單擊建立任務

      2. 輸入任務名稱,選中流水線,單擊確定

      3. 單擊構建觸發器頁簽,選中Build when a change is pushed to GitLab,然後選中Push Events

        Build when a change is pushed to GitLab右側記錄Webhook的地址。

      4. 單擊進階,單擊Secret token右下角的Generate

        Jenkins會產生一個Secret token,儲存該Secret token。

      5. 單擊流水線頁簽,根據實際情況修改以下模板,然後將內容複寫到文字框中,然後單擊儲存

        def git_auth_id = "6d5a2c06-f0a7-43c8-9b79-37b8c266****"  #憑據ID
        def git_branch_name = "master" #分支名
        def git_url = "git@172.16.1*.***:shoppingmall/java-web.git"   #GitLab倉庫地址
        def acr_url = "s*****-devsecops-registry.cn-hongkong.cr.aliyuncs.com"  #鏡像倉庫地址
        def acr_username = "acr_test_*****@test.aliyunid.com"   #容器鏡像使用者名稱
        def acr_password = "HelloWorld2021"   #容器鏡像密碼
        def acr_namespace = "ns"    #命名空間
        def acr_repo_name = "test"   #鏡像倉庫名稱
        def tag_version = "0.0.1"   #鏡像版本
        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. 添加Webhook地址到GitLab中。

    1. 登入GitLab。

    2. Projects頁面單擊上文建立的Project名稱。

    3. 在左側導覽列選擇Settings > Webhooks,輸入Webhook地址和Secret token,取消選中Enable SSL verification,然後單擊Add webhooks

  4. 建立事件通知。

    1. 登入Container Registry控制台

    2. 在頂部功能表列,選擇所需地區。

    3. 在左側導覽列,選擇執行個體列表

    4. 執行個體列表頁面單擊目標企業版執行個體。

    5. 在執行個體詳情頁面左側導覽列選擇執行個體管理 > 事件通知

    6. 事件規則頁簽下單擊建立規則

    7. 事件範圍設定精靈中設定規則名稱事件類型鏡像掃描完成,選中掃描完成,設定生效範圍命名空間,選擇命名空間為ns,然後單擊下一步

    8. 事件通知設定精靈中設定通知方式DingTalk,輸入DingTalk的Webhook地址和加簽密鑰,然後單擊儲存

  5. 觸發鏡像構建。

    執行以下命令,修改HelloController.java檔案,提交檔案到GitLab中,從而觸發鏡像構建。

    vim java/com/example/demo/HelloController.java #根據實際情況在本地修改HelloController.java檔案
    git add . && git commit -m 'commit' && git push origin #提交檔案到GitLab

    稍等一段時間,在企業版執行個體詳情頁面左側導覽列選擇倉庫管理 > 鏡像倉庫,在右側頁面單擊目標倉庫test,在倉庫管理頁面左側導覽列單擊鏡像版本,可以看到鏡像版本頁面產生一個鏡像。

  6. 設定漏洞掃描。

    1. 在鏡像版本頁面單擊目標鏡像右側操作下的安全掃描

    2. 安全掃描頁面,單擊立即掃描

      待鏡像掃描完成後,您可以在DingTalk群裡收到通知。

使用Jenkins實現鏡像的CD

只要您在GitLab中提交原始碼,容器鏡像會自動用原始碼構建鏡像,鏡像構建成功後,自動觸發執行交付鏈,待交付鏈運行完成後,將自動發送HTTP請求至Jenkins,然後觸發ACK的Deployment重新拉取鏡像部署應用。

  1. 建立應用。

    1. 登入Container Service管理主控台

    2. 在控制台左側導覽列,單擊叢集

    3. 叢集列表頁面,單擊目的地組群名稱或者目的地組群右側操作列下的詳情

    4. 在叢集管理頁左側導覽列,選擇工作負載 > 無狀態

    5. 無狀態頁面單擊右上方的使用YAML建立資源

    6. 建立頁面頂部選擇命名空間,設定樣本模板自訂,然後複製以下內容到模板中,然後單擊建立

      說明

      沒有設定免密拉取鏡像,您需要在Container Registry中開啟公網訪問,並設定鏡像為公開鏡像。具體操作,請參見配置公網的存取控制

      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. 無狀態頁面單擊目標應用demo,單擊訪問方式頁簽。

      訪問方式頁簽下擷取外部端點地址。

    8. 在本地hosts綁定以下內容。

      <外部端點地址> app.demo.example.com
    9. 在瀏覽器中輸入app.demo.example.com

      應用看到以上頁面,說明應用部署成功。

  2. 建立觸發器。

    1. 在無狀態頁面單擊目標應用demo的名稱。

    2. 在應用詳情頁面單擊觸發器頁簽,單擊建立觸發器

    3. 建立觸發器對話方塊設定觸發器行為重新部署,然後單擊確定

      觸發器頁簽下擷取觸發器連結。

  3. 建立流水線。

    1. 登入Jenkins。

    2. 在左側導覽列單擊建立任務

    3. 輸入任務名稱,單擊流水線

    4. 單擊構建觸發器頁簽,選中Generic Webhook Trigger

      Generic Webhook Trigger下可以擷取HTTP請求觸發地址為JENKINS_URL/generic-webhook-trigger/invoke,本文設定Generic Webhook tokenhelloworld2021,因此Webhook地址為JENKINS_URL/generic-webhook-trigger/invoke?token=helloworld2021

    5. 單擊流水線頁簽,根據實際情況修改以下模板中的Generic Webhook token和觸發器連結,然後將內容複寫到文字框中,然後單擊儲存

      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,請根據實際情況替換。
           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.aliyun.com/hook/trigger?token=g****'  #觸發器連結,請根據實際情況替換。
              sh "echo 'done'"
            }
          }
        }
      }
  4. 建立交付鏈。具體操作。請參見建立交付鏈

  5. 建立事件規則。

    1. 在企業版執行個體管理頁面左側導覽列中選擇執行個體管理 > 事件通知

    2. 事件規則頁簽下單擊建立規則

    3. 事件範圍設定精靈中設定規則名稱事件類型交付鏈處理完成,選中成功,設定生效範圍命名空間,選擇命名空間為ns,然後單擊下一步

    4. 事件通知設定精靈中設定通知方式HTTP,輸入步驟3擷取的Webhook地址,然後單擊儲存

  6. 執行以下命令,修改HelloController.java檔案,提交代碼到GitLab中,從而觸發鏡像構建。

    vim java/com/example/demo/HelloController.java #根據實際情況在本地修改HelloController.java檔案。
    git add . && git commit -m 'add update' && git push origin   #提交檔案到GitLab中。

    鏡像構建成功後,觸發執行交付鏈,交付鏈執行完畢後,觸發ACK的Deployment重新拉取鏡像部署應用。

  7. 執行以下命令,驗證應用是否重新部署。

    curl app.demo.example.com

    可以看到輸出內容發生了變化, 說明應用重新部署成功。