乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • Kubernetes
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • DevOps
  • Kubernetes
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • Docker

  • Golang

  • AIOps

  • Python

  • DevOps

    • Tekton

    • ArgoWorkflow

      • 使用Jenkins和Argocd实现CI_CD
        • 软件安装
        • 在 Jenkins 上安装如下插件
        • 在 Jenkins 上配置 Kubernetes 集群信息
        • 在 Jenkins 上配置邮箱地址
        • 在 Gitlab 上准备一个测试代码
        • 在 Gitlab 上创建一个共享库
        • 在 Gitlab 上创建一个 YAML 管理仓库
        • 在 Jenkins 上配置共享库
        • 编写 Jenkinsfile
        • 在 Jenkins 上配置项目
        • 在 Argocd 上配置 CD 流程
        • 集成 Gitlab,通过 Webhook 触发 Jenkins
        • 写在最后
      • 使用ArgoCD进行持续部署
      • 使用argo-rollouts实现金丝雀发布
      • Jenkins+argocd+argo rollouts实现金丝雀发布
      • Argocd使用优化
    • Gitlab

    • Ansible

  • Kubernetes

  • 专栏
  • DevOps
  • ArgoWorkflow
乔克
2025-07-19
目录

使用Jenkins和Argocd实现CI_CD

CI/CD 并不是陌生的东西,大部分企业都有自己的 CI/CD,不过今天我要介绍的是使用 Jenkins 和 GitOps 实现 CI/CD。

整体架构如下:

e79b4a719430dc657c172f7bea3df03a MD5

涉及的软件以及版本信息如下:

软件 版本
kubernetes 1.17.9
docker 19.03.13
jenkins 2.249.3 (opens new window)
argocd 1.8.0
gitlab 社区版 11.8.1
sonarqube 社区版 8.5.1
traefik 2.3.3
代码仓库 阿里云仓库

涉及的技术:

  • Jenkins shareLibrary
  • Jenkins pipeline
  • Jenkinsfile
  • Argocd
  • sonarqube api 操作

# 软件安装

软件安装我这里不贴具体的安装代码了,所有的代码我都放在了 github 上,地址:https://github.com/cool-ops/kubernetes-software-yaml.git (opens new window)

所以这里默认你已经安装好所以软件了。

# 在 Jenkins 上安装如下插件

  • kubernetes
  • AnsiColor
  • HTTP Request
  • SonarQube Scanner
  • Utility Steps
  • Email Extension Template
  • Gitlab Hook
  • Gitlab

# 在 Jenkins 上配置 Kubernetes 集群信息

在系统管理-->系统配置-->cloud

7f125e4d239f80921aa2c44f48f8d44f MD5

# 在 Jenkins 上配置邮箱地址

系统设置-->系统配置-->Email

(1)设置管理员邮箱

11d3b2c104ddb97a477634e8bf80d3cc MD5

配置 SMTP 服务

81280995e5467605362d2bf7d473a60b MD5

# 在 Gitlab 上准备一个测试代码

我这里有一个简单的 java 测试代码,地址如下:https://gitee.com/jokerbai/springboot-helloworld.git (opens new window)

可以将其导入到自己的 gitlab 仓库。

# 在 Gitlab 上创建一个共享库

首先在 gitlab 上创建一个共享库,我这里取名叫 shareLibrary,如下:

30bad64b3ba0e905345b366f6d2d68f4 MD5

然后创建 src/org/devops 目录,并在该目录下创建一下文件。

69c29cf6aff3f047ceb9ff19409db053 MD5

它们的内容分别如下:

build.groovy

package org.devops

// docker容器直接build
def DockerBuild(buildShell){
    sh """
        ${buildShell}
    """
}

1
2
3
4
5
6
7
8
9

sendEmail.groovy

package org.devops

//定义邮件内容
def SendEmail(status,emailUser){
    emailext body: """
            <!DOCTYPE html>
            <html>
            <head>
            <meta charset="UTF-8">
            </head>
            <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
                <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
                <tr>
		            本邮件由系统自动发出,无需回复!<br/>
		            各位同事,大家好,以下为${JOB_NAME}项目构建信息</br>
		            <td><font color="#CC0000">构建结果 - ${status}</font></td>
		        </tr>

                    <tr>
                        <td><br />
                            <b><font color="#0B610B">构建信息</font></b>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <ul>
                                <li>项目名称:${JOB_NAME}</li>
                                <li>构建编号:${BUILD_ID}</li>
                                <li>构建状态: ${status} </li>
                                <li>项目地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>
                                <li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                            </ul>
                        </td>
                    </tr>
                    <tr>
                </table>
            </body>
            </html>  """,
            subject: "Jenkins-${JOB_NAME}项目构建信息 ",
            to: emailUser

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

sonarAPI.groovy

package ore.devops

// 封装HTTP请求
def HttpReq(requestType,requestUrl,requestBody){
    // 定义sonar api接口
    def sonarServer = "http://sonar.devops.svc.cluster.local:9000/api"
    result = httpRequest authentication: 'sonar-admin-user',
            httpMode: requestType,
            contentType: "APPLICATION_JSON",
            consoleLogResponseBody: true,
            ignoreSslErrors: true,
            requestBody: requestBody,
            url: "${sonarServer}/${requestUrl}"
    return result
}

// 获取soanr项目的状态
def GetSonarStatus(projectName){
    def apiUrl = "project_branches/list?project=${projectName}"
    // 发请求
    response = HttpReq("GET",apiUrl,"")
    // 对返回的文本做JSON解析
    response = readJSON text: """${response.content}"""
    // 获取状态值
    result = response["branches"][0]["status"]["qualityGateStatus"]
    return result
}

// 获取sonar项目,判断项目是否存在
def SearchProject(projectName){
    def apiUrl = "projects/search?projects=${projectName}"
    // 发请求
    response = HttpReq("GET",apiUrl,"")
    println "搜索的结果:${response}"
    // 对返回的文本做JSON解析
    response = readJSON text: """${response.content}"""
    // 获取total字段,该字段如果是0则表示项目不存在,否则表示项目存在
    result = response["paging"]["total"]
    // 对result进行判断
    if (result.toString() == "0"){
        return "false"
    }else{
        return "true"
    }
}

// 创建sonar项目
def CreateProject(projectName){
    def apiUrl = "projects/create?name=${projectName}&project=${projectName}"
    // 发请求
    response = HttpReq("POST",apiUrl,"")
    println(response)
}

// 配置项目质量规则
def ConfigQualityProfiles(projectName,lang,qpname){
    def apiUrl = "qualityprofiles/add_project?language=${lang}&project=${projectName}&qualityProfile=${qpname}"
    // 发请求
    response = HttpReq("POST",apiUrl,"")
    println(response)
}

// 获取质量阈ID
def GetQualityGateId(gateName){
    def apiUrl = "qualitygates/show?name=${gateName}"
    // 发请求
    response = HttpReq("GET",apiUrl,"")
    // 对返回的文本做JSON解析
    response = readJSON text: """${response.content}"""
    // 获取total字段,该字段如果是0则表示项目不存在,否则表示项目存在
    result = response["id"]
    return result
}

// 更新质量阈规则
def ConfigQualityGate(projectKey,gateName){
    // 获取质量阈id
    gateId = GetQualityGateId(gateName)
    apiUrl = "qualitygates/select?projectKey=${projectKey}&gateId=${gateId}"
    // 发请求
    response = HttpReq("POST",apiUrl,"")
    println(response)
}

//获取Sonar质量阈状态
def GetProjectStatus(projectName){
    apiUrl = "project_branches/list?project=${projectName}"
    response = HttpReq("GET",apiUrl,'')

    response = readJSON text: """${response.content}"""
    result = response["branches"][0]["status"]["qualityGateStatus"]

    //println(response)

   return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

sonarqube.groovy

package ore.devops

def SonarScan(projectName,projectDesc,projectPath){
    // sonarScanner安装地址
    def sonarHome = "/opt/sonar-scanner"
    // sonarqube服务端地址
    def sonarServer = "http://sonar.devops.svc.cluster.local:9000/"
    // 以时间戳为版本
    def scanTime = sh returnStdout: true, script: 'date +%Y%m%d%H%m%S'
    scanTime = scanTime - "\n"
    sh """
    ${sonarHome}/bin/sonar-scanner  -Dsonar.host.url=${sonarServer}  \
    -Dsonar.projectKey=${projectName}  \
    -Dsonar.projectName=${projectName}  \
    -Dsonar.projectVersion=${scanTime} \
    -Dsonar.login=admin \
    -Dsonar.password=admin \
    -Dsonar.ws.timeout=30 \
    -Dsonar.projectDescription="${projectDesc}"  \
    -Dsonar.links.homepage=http://www.baidu.com \
    -Dsonar.sources=${projectPath} \
    -Dsonar.sourceEncoding=UTF-8 \
    -Dsonar.java.binaries=target/classes \
    -Dsonar.java.test.binaries=target/test-classes \
    -Dsonar.java.surefire.report=target/surefire-reports -X

    echo "${projectName}  scan success!"
    """
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

tools.groovy

package org.devops

//格式化输出
def PrintMes(value,color){
    colors = ['red'   : "\033[40;31m >>>>>>>>>>>${value}<<<<<<<<<<< \033[0m",
              'blue'  : "\033[47;34m ${value} \033[0m",
              'green' : ">>>>>>>>>>${value}>>>>>>>>>>",
              'green1' : "\033[40;32m >>>>>>>>>>>${value}<<<<<<<<<<< \033[0m" ]
    ansiColor('xterm') {
        println(colors[color])
    }
}


// 获取镜像版本
def createVersion() {
	// 定义一个版本号作为当次构建的版本,输出结果 20191210175842_69
    return new Date().format('yyyyMMddHHmmss') + "_${env.BUILD_ID}"
}


// 获取时间
def getTime() {
	// 定义一个版本号作为当次构建的版本,输出结果 20191210175842
    return new Date().format('yyyyMMddHHmmss')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 在 Gitlab 上创建一个 YAML 管理仓库

我这里创建了一个叫 devops-cd 的共享仓库,如下:

97ac196a04b7455260a92450f2b4ac73 MD5

然后以应用名创建一个目录,并在目录下创建以下几个文件。

97d6173eccb730103b3132f66aa83d21 MD5

它们的内容分别如下。

service.yaml

kind: Service
apiVersion: v1
metadata:
  name: the-service
  namespace: default
spec:
  selector:
    deployment: hello
  type: NodePort
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
1
2
3
4
5
6
7
8
9
10
11
12
13

ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: the-ingress
  namespace: default
spec:
  rules:
    - host: test.coolops.cn
      http:
        paths:
          - backend:
              serviceName: the-service
              servicePort: 8080
            path: /
1
2
3
4
5
6
7
8
9
10
11
12
13
14

deploymeny.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: the-deployment
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      deployment: hello
  template:
    metadata:
      labels:
        deployment: hello
    spec:
      containers:
        - args:
            - -jar
            - /opt/myapp.jar
            - --server.port=8080
          command:
            - java
          env:
            - name: HOST_IP
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.hostIP
          image: registry.cn-hangzhou.aliyuncs.com/rookieops/myapp:latest
          imagePullPolicy: IfNotPresent
          lifecycle:
            preStop:
              exec:
                command:
                  - /bin/sh
                  - -c
                  - /bin/sleep 30
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /hello
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 60
            periodSeconds: 15
            successThreshold: 1
            timeoutSeconds: 1
          name: myapp
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /hello
              port: 8080
              scheme: HTTP
            periodSeconds: 15
            successThreshold: 1
            timeoutSeconds: 1
          resources:
            limits:
              cpu: "1"
              memory: 2Gi
            requests:
              cpu: 100m
              memory: 1Gi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
      dnsPolicy: ClusterFirstWithHostNet
      imagePullSecrets:
        - name: gitlab-registry
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

kustomization.yaml

# Example configuration for the webserver
# at https://github.com/monopole/hello
commonLabels:
  app: hello

resources:
  - deployment.yaml
  - service.yaml
  - ingress.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
  - name: registry.cn-hangzhou.aliyuncs.com/rookieops/myapp
    newTag: "20201127150733_70"
namespace: dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 在 Jenkins 上配置共享库

(1)需要在 Jenkins 上添加凭证

67423cef254b00e23aeb98e0407ae5a2 MD5

(2)在 Jenkins 的系统配置里面配置共享库(系统管理-->系统配置)

c7c7ab07b201d74e5f436ffb6e2d9147 MD5

然后点击应用并保存

然后我们可以用一个简单的 Jenkinsfile 测试一下共享库,看配置是否正确。

在 Jenkins 上创建一个项目,如下:

690c230fa136a09db15281ed3fdaec61 MD5

然后在最地下的 pipeline 处贴入以下代码:

def labels = "slave-${UUID.randomUUID().toString()}"
// 引用共享库
@Library("jenkins_shareLibrary")

// 应用共享库中的方法
def tools = new org.devops.tools()

pipeline {
    agent {
    kubernetes {
        label labels
      yaml """
apiVersion: v1
kind: Pod
metadata:
  labels:
    some-label: some-label-value
spec:
  volumes:
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock
      type: ''
  containers:
  - name: jnlp
    image: registry.cn-hangzhou.aliyuncs.com/rookieops/inbound-agent:4.3-4
  - name: maven
    image: registry.cn-hangzhou.aliyuncs.com/rookieops/maven:3.5.0-alpine
    command:
    - cat
    tty: true
  - name: docker
    image: registry.cn-hangzhou.aliyuncs.com/rookieops/docker:19.03.11
    command:
    - cat
    tty: true
    volumeMounts:
    - name: docker-sock
      mountPath: /var/run/docker.sock
"""
    }
  }
    stages {
        stage('Checkout') {
            steps {
                script{
                	tools.PrintMes("拉代码","green")
                }
            }
        }
        stage('Build') {
            steps {
                container('maven') {
                    script{
                		tools.PrintMes("编译打包","green")
                	}
                }
            }
        }
        stage('Make Image') {
            steps {
                container('docker') {
                    script{
                		tools.PrintMes("构建镜像","green")
                    }
                }
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

然后点击保存并运行,如果看到输出有颜色,就代表共享库配置成功,如下:

8ff5164171ec2831071d575857486b0c MD5

到此共享库配置完成。

# 编写 Jenkinsfile

整个 java 的 Jenkinsfile 如下:

def labels = "slave-${UUID.randomUUID().toString()}"

// 引用共享库
@Library("jenkins_shareLibrary")

// 应用共享库中的方法
def tools = new org.devops.tools()
def sonarapi = new org.devops.sonarAPI()
def sendEmail = new org.devops.sendEmail()
def build = new org.devops.build()
def sonar = new org.devops.sonarqube()

// 前端传来的变量
def gitBranch = env.branch
def gitUrl = env.git_url
def buildShell = env.build_shell
def image = env.image
def dockerRegistryUrl = env.dockerRegistryUrl
def devops_cd_git = env.devops_cd_git



pipeline {
    agent {
    kubernetes {
        label labels
      yaml """
apiVersion: v1
kind: Pod
metadata:
  labels:
    some-label: some-label-value
spec:
  volumes:
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock
      type: ''
  - name: maven-cache
    persistentVolumeClaim:
      claimName: maven-cache-pvc
  containers:
  - name: jnlp
    image: registry.cn-hangzhou.aliyuncs.com/rookieops/inbound-agent:4.3-4
  - name: maven
    image: registry.cn-hangzhou.aliyuncs.com/rookieops/maven:3.5.0-alpine
    command:
    - cat
    tty: true
    volumeMounts:
    - name: maven-cache
      mountPath: /root/.m2
  - name: docker
    image: registry.cn-hangzhou.aliyuncs.com/rookieops/docker:19.03.11
    command:
    - cat
    tty: true
    volumeMounts:
    - name: docker-sock
      mountPath: /var/run/docker.sock
  - name: sonar-scanner
    image: registry.cn-hangzhou.aliyuncs.com/rookieops/sonar-scanner:latest
    command:
    - cat
    tty: true
  - name: kustomize
    image: registry.cn-hangzhou.aliyuncs.com/rookieops/kustomize:v3.8.1
    command:
    - cat
    tty: true
"""
    }
  }

    environment{
        auth = 'joker'
    }

    options {
		timestamps()	// 日志会有时间
		skipDefaultCheckout()	// 删除隐式checkout scm语句
		disableConcurrentBuilds()	//禁止并行
		timeout(time:1,unit:'HOURS') //设置流水线超时时间
	}


    stages {
        // 拉取代码
        stage('GetCode') {
            steps {
                checkout([$class: 'GitSCM', branches: [[name: "${gitBranch}"]],
                    doGenerateSubmoduleConfigurations: false,
                    extensions: [],
                    submoduleCfg: [],
                    userRemoteConfigs: [[credentialsId: '83d2e934-75c9-48fe-9703-b48e2feff4d8', url: "${gitUrl}"]]])
                }
            }

        // 单元测试和编译打包
        stage('Build&Test') {
            steps {
                container('maven') {
                    script{
                        tools.PrintMes("编译打包","blue")
                        build.DockerBuild("${buildShell}")
                    }
                }
            }
        }
        // 代码扫描
        stage('CodeScanner') {
            steps {
                container('sonar-scanner') {
                    script {
                        tools.PrintMes("代码扫描","green")
                        tools.PrintMes("搜索项目","green")
                        result = sonarapi.SearchProject("${JOB_NAME}")
                        println(result)

                        if (result == "false"){
                            println("${JOB_NAME}---项目不存在,准备创建项目---> ${JOB_NAME}!")
                            sonarapi.CreateProject("${JOB_NAME}")
                        } else {
                            println("${JOB_NAME}---项目已存在!")
                        }

                        tools.PrintMes("代码扫描","green")
                        sonar.SonarScan("${JOB_NAME}","${JOB_NAME}","src")

                        sleep 10
                        tools.PrintMes("获取扫描结果","green")
                        result = sonarapi.GetProjectStatus("${JOB_NAME}")

                        println(result)
                        if (result.toString() == "ERROR"){
                            toemail.Email("代码质量阈错误!请及时修复!",userEmail)
                            error " 代码质量阈错误!请及时修复!"

                        } else {
                            println(result)
                        }
                    }
                }
            }
        }
        // 构建镜像
        stage('BuildImage') {
            steps {
                withCredentials([[$class: 'UsernamePasswordMultiBinding',
                credentialsId: 'dockerhub',
                usernameVariable: 'DOCKER_HUB_USER',
                passwordVariable: 'DOCKER_HUB_PASSWORD']]) {
                    container('docker') {
                        script{
                            tools.PrintMes("构建镜像","green")
                            imageTag = tools.createVersion()
                            sh """
                            docker login ${dockerRegistryUrl} -u ${DOCKER_HUB_USER} -p ${DOCKER_HUB_PASSWORD}
                            docker build -t ${image}:${imageTag} .
                            docker push ${image}:${imageTag}
                            docker rmi ${image}:${imageTag}
                            """
                        }
                    }
                }
            }
        }
        // 部署
        stage('Deploy') {
            steps {
                 withCredentials([[$class: 'UsernamePasswordMultiBinding',
                credentialsId: 'ci-devops',
                usernameVariable: 'DEVOPS_USER',
                passwordVariable: 'DEVOPS_PASSWORD']]){
                    container('kustomize') {
                        script{
                            APP_DIR="${JOB_NAME}".split("_")[0]
                            sh """
                            git remote set-url origin http://${DEVOPS_USER}:${DEVOPS_PASSWORD}@${devops_cd_git}
                            git config --global user.name "Administrator"
                            git config --global user.email "coolops@163.com"
                            git clone http://${DEVOPS_USER}:${DEVOPS_PASSWORD}@${devops_cd_git} /opt/devops-cd
                            cd /opt/devops-cd
                            git pull
                            cd /opt/devops-cd/${APP_DIR}
                            kustomize edit set image ${image}:${imageTag}
                            git commit -am 'image update'
                            git push origin master
                            """
                        }
                    }
                }
            }
        }
        // 接口测试
        stage('InterfaceTest') {
            steps{
                sh 'echo "接口测试"'
            }
        }
    }
    // 构建后的操作
	post {
		success {
			script{
				println("success:只有构建成功才会执行")
				currentBuild.description += "\n构建成功!"
				// deploy.AnsibleDeploy("${deployHosts}","-m ping")
				sendEmail.SendEmail("构建成功",toEmailUser)
				// dingmes.SendDingTalk("构建成功 ✅")
			}
		}
		failure {
			script{
				println("failure:只有构建失败才会执行")
				currentBuild.description += "\n构建失败!"
				sendEmail.SendEmail("构建失败",toEmailUser)
				// dingmes.SendDingTalk("构建失败 ❌")
			}
		}
		aborted {
			script{
				println("aborted:只有取消构建才会执行")
				currentBuild.description += "\n构建取消!"
				sendEmail.SendEmail("取消构建",toEmailUser)
				// dingmes.SendDingTalk("构建失败 ❌","暂停或中断")
			}
		}
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231

需要在 Jenkins 上创建两个凭证,一个 id 叫 dockerhub,一个叫 ci-devops,还有一个叫 sonar-admin-user。

dockerhub 是登录镜像仓库的用户名和密码。

ci-devops 是管理 YAML 仓库的用户名和密码。

sonar-admin-user 是管理 sonarqube 的用户名和密码。

然后将这个 Jenkinsfile 保存到 shareLibrary 的根目录下,命名为 java.Jenkinsfile。

9e9d1afc2f04de30a9d30fce96a819eb MD5

# 在 Jenkins 上配置项目

在 Jenkins 上新建一个项目,如下:

97883a25dab431775e6c7abc89000c5a MD5

然后添加以下参数化构建。

dd4807828006e8238e978f65dc1672c3 MD5

a5341b013925a4b1108805c6905d8c5b MD5

a823212398fe416ace50fdbda1d1d31c MD5

20412e94b22de715fe76a4d28d1dbada MD5

ff329c7056d84dc422e9d25ce6de0618 MD5

7f4c35a3784e6fb3f63fc4a0c56d586a MD5

be68f9999f17f766b1683cac35a67f33 MD5

然后在流水线处配置 Pipeline from SCM

c429de2e397da012dc892f7971168bc2 MD5

1b1e1aad2e63aae76bcb52d4da7e4780 MD5

此处需要注意脚本名。

然后点击应用保存,并运行。

dec2a7818bce0d73effb261896365cb6 MD5

也可以在 sonarqube 上看到代码扫描的结果。

a787a178d8a595f3dcfd3158b3dbaf10 MD5

# 在 Argocd 上配置 CD 流程

在 argocd 上添加代码仓库,如下:

fe999ab6451a45fe924a6728eebd013b MD5

15f2f53ab4853752d26e001a8f2852e0 MD5

然后创建应用,如下:

03e05b21219b36bf7d65be1bed051d4c MD5

ad7a6f40242dfdd1a75cc823015731bc MD5

点击创建后,如下:

111f8652c5392cef0d26573027a9d4ec MD5

点进去可以看到更多的详细信息。

fd51eddd30ab66b7c96ce8d8186d3c57 MD5

argocd 有一个小 bug,它 ingress 的健康检查必须要 loadBalance 有值,不然就不通过,但是并不影响使用。

然后可以正常访问应用了。

11d1899c68e1794c9f53bad378e93830 MD5

node 项目的 Jenkinsfile 大同小异,由于我没有测试用例,所以并没有测试。

# 集成 Gitlab,通过 Webhook 触发 Jenkins

在 Jenkins 中选择项目,在项目中配置 gitlab 触发,如下:

995bd8257881c239f1b306f21e187f78 MD5

生成 token,如下

0ed17c97af3876b0cbeadcbfb30b3551 MD5

在 gitlab 上配置集成。进入项目-->项目设置-->集成

e99fcfe9dda14ac82daff81ad59e418d MD5

配置 Jenkins 上生成的回调 URL 和 TOKEN

ead32ba1f16d595b4bf51998b0f48ede MD5

到此配置完成,然后点击下方 test,可以观察是否触发流水线。

6e3c9a4d49a9be0fdac4ebe6275d7a81 MD5

也可以通过修改仓库代码进行测试。

# 写在最后

本片文章是纯操作步骤,大家在测试的时候可能会对 Jenkinsfile 做细微的调整,不过整体没什么问题。

上次更新: 2025/07/19, 11:33:23
Tekton系列之实践篇-Tekton和Argocd的梦幻联动
使用ArgoCD进行持续部署

← Tekton系列之实践篇-Tekton和Argocd的梦幻联动 使用ArgoCD进行持续部署→

最近更新
01
读《额尔古纳河右岸》有感
07-19
02
读《命运》有感
07-19
03
读《月亮与六便士》有感
07-19
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式