若您期望實現從原始碼自動構建、推送鏡像到最終部署應用的一體化自動化操作。您可以使用Jenkins實現鏡像的CI/CD,只要您在GitLab中提交原始碼,容器鏡像會自動使用原始碼構建鏡像,Container Service會自動拉取鏡像部署應用,並自動發送事件通知到DingTalk群。
前提條件
已安裝Git、GitLab和Jenkins。
說明GitLab需要安裝JDK8,部分外掛程式不能在JDK11上運行。
已建立ACK叢集,且與ACR執行個體位於同一地區。具體操作,請參見建立Kubernetes託管版叢集。
已建立DingTalk機器人,並記錄下Webhook地址和加簽密鑰。具體操作,請參見步驟一:建立DingTalk機器人。
使用ACR的交付鏈功能,需要您升級至ACR進階版執行個體。具體操作,請參見計費說明。
使用Jenkins實現鏡像的CI
只要您在GitLab中提交原始碼,容器鏡像會自動使用原始碼構建鏡像,然後您可以對鏡像進行漏洞掃描,鏡像掃描完成後,將自動發送事件通知到DingTalk群。
在GitLab中建立專案。
登入GitLab。
在頂部導覽列中,選擇 。
在Projects頁面單擊右上方的New Project,單擊Create blank project。
在Create blank project版面設定Project name、Project URL和Project slug,設定Visibility Level為Private,然後單擊Create project。
使用以下內容,在本地建立Dockerfile、pom.xml、DemoApplication.java和HelloController.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()); } }
執行以下命令,上傳構建檔案至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
在Jenkins配置構建鏡像的流水線。
在Jenkins配置GitLab的SSH Key。
登入Jenkins。
在Jenkins左側導覽列單擊系統管理。
在安全地區單擊Manage Credentials。
在Stores scoped to Jenkins地區單擊儲存列下的Jenkins,然後單擊全域憑據。
在左側導覽列單擊添加憑據。
設定類型為SSH Username with private key,然後輸入描述、Username,選中Enter directly,然後單擊確定。
在全域憑據頁面會自動產生憑據ID,儲存該憑據ID。
建立流水線。
在Jenkins左側導覽列單擊建立任務。
輸入任務名稱,選中流水線,單擊確定。
單擊構建觸發器頁簽,選中Build when a change is pushed to GitLab,然後選中Push Events。
在Build when a change is pushed to GitLab右側記錄Webhook的地址。
單擊進階,單擊Secret token右下角的Generate。
Jenkins會產生一個Secret token,儲存該Secret token。
單擊流水線頁簽,根據實際情況修改以下模板,然後將內容複寫到文字框中,然後單擊儲存。
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}" } }
添加Webhook地址到GitLab中。
登入GitLab。
在Projects頁面單擊上文建立的Project名稱。
在左側導覽列選擇
,輸入Webhook地址和Secret token,取消選中Enable SSL verification,然後單擊Add webhooks。
建立事件通知。
在頂部功能表列,選擇所需地區。
在左側導覽列,選擇執行個體列表。
在執行個體列表頁面單擊目標企業版執行個體。
在執行個體詳情頁面左側導覽列選擇 。
在事件規則頁簽下單擊建立規則。
在事件範圍設定精靈中設定規則名稱,事件類型為鏡像掃描完成,選中掃描完成,設定生效範圍為命名空間,選擇命名空間為ns,然後單擊下一步。
在事件通知設定精靈中設定通知方式為DingTalk,輸入DingTalk的Webhook地址和加簽密鑰,然後單擊儲存。
觸發鏡像構建。
執行以下命令,修改HelloController.java檔案,提交檔案到GitLab中,從而觸發鏡像構建。
vim java/com/example/demo/HelloController.java #根據實際情況在本地修改HelloController.java檔案 git add . && git commit -m 'commit' && git push origin #提交檔案到GitLab
稍等一段時間,在企業版執行個體詳情頁面左側導覽列選擇
,在右側頁面單擊目標倉庫test,在倉庫管理頁面左側導覽列單擊鏡像版本,可以看到鏡像版本頁面產生一個鏡像。設定漏洞掃描。
在鏡像版本頁面單擊目標鏡像右側操作下的安全掃描。
在安全掃描頁面,單擊立即掃描。
待鏡像掃描完成後,您可以在DingTalk群裡收到通知。
使用Jenkins實現鏡像的CD
只要您在GitLab中提交原始碼,容器鏡像會自動用原始碼構建鏡像,鏡像構建成功後,自動觸發執行交付鏈,待交付鏈運行完成後,將自動發送HTTP請求至Jenkins,然後觸發ACK的Deployment重新拉取鏡像部署應用。
建立應用。
在控制台左側導覽列,單擊叢集。
在叢集列表頁面,單擊目的地組群名稱或者目的地組群右側操作列下的詳情。
在叢集管理頁左側導覽列,選擇 。
在無狀態頁面單擊右上方的使用YAML建立資源。
在建立頁面頂部選擇命名空間,設定樣本模板為自訂,然後複製以下內容到模板中,然後單擊建立。
說明沒有設定免密拉取鏡像,您需要在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 ---
在無狀態頁面單擊目標應用demo,單擊訪問方式頁簽。
在訪問方式頁簽下擷取外部端點地址。
在本地hosts綁定以下內容。
<外部端點地址> app.demo.example.com
在瀏覽器中輸入app.demo.example.com。
看到以上頁面,說明應用部署成功。
建立觸發器。
在無狀態頁面單擊目標應用demo的名稱。
在應用詳情頁面單擊觸發器頁簽,單擊建立觸發器。
在建立觸發器對話方塊設定觸發器行為為重新部署,然後單擊確定。
在觸發器頁簽下擷取觸發器連結。
建立流水線。
登入Jenkins。
在左側導覽列單擊建立任務。
輸入任務名稱,單擊流水線。
單擊構建觸發器頁簽,選中Generic Webhook Trigger。
在Generic Webhook Trigger下可以擷取HTTP請求觸發地址為
JENKINS_URL/generic-webhook-trigger/invoke
,本文設定Generic Webhook token
為helloworld2021
,因此Webhook地址為JENKINS_URL/generic-webhook-trigger/invoke?token=helloworld2021
。單擊流水線頁簽,根據實際情況修改以下模板中的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'" } } } }
建立交付鏈。具體操作。請參見建立交付鏈。
建立事件規則。
在企業版執行個體管理頁面左側導覽列中選擇 。
在事件規則頁簽下單擊建立規則。
在事件範圍設定精靈中設定規則名稱,事件類型為交付鏈處理完成,選中成功,設定生效範圍為命名空間,選擇命名空間為ns,然後單擊下一步。
在事件通知設定精靈中設定通知方式為HTTP,輸入步驟3擷取的Webhook地址,然後單擊儲存。
執行以下命令,修改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重新拉取鏡像部署應用。
執行以下命令,驗證應用是否重新部署。
curl app.demo.example.com
可以看到輸出內容發生了變化, 說明應用重新部署成功。