Skip to content

第8章 Jenkins pipeline 语法-声明式语法和 Script 语法本章所讲内容:

8.1 Jenkins pipeline 语法介绍

8.2 Jenkins pipeline 入门

8.3 Jenkins pipeline 声明式语法

8.4 Pipeline Scripted 语法和声明式语法

8.5 Jenkins+k8s+nexus+sonarqube+gitlab+harbor+springcloud 构建 DevOps

8.1 Jenkins pipeline 语法介绍

​ Jenkins Pipeline 是一种插件,它允许你以代码的方式定义持续集成和持续交付(CI/CD)流程。它基于 Jenkins 的 Groovy DSL(领域特定语言),提供了一种强大的方式来描述和自动化构建、测试和部署软件。

备注:DSL 是什么?

​ DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言(下简称 DSL);而与 DSL 相对的就是 GPL,这里的 GPL 并不是我们知道的开源许可证,而是 General Purpose Language 的简称,即通用编程语言,也就是我们非常熟悉的 Objective-C、Java、Python 以及C 语言等等。

​ Pipeline 脚本可以被定义在 Jenkins 的界面中,也可以作为一个 Jenkinsfile 文件存在于代码仓库中,以使流程定义与代码版本控制一起管理。以下是 Jenkins Pipeline 的基本概述:

1、阶段(Stages): Pipeline 由一个或多个阶段组成。每个阶段代表一个任务,例如构建、测试、部署等。阶段通常按照顺序执行,可以并行执行或顺序执行。

2、步骤(Steps): 每个阶段包含一个或多个步骤。步骤是具体的操作,例如构建代码、运行测试、推送到远程服务器等。Jenkins 提供了一系列内置步骤来完成常见的构建和部署任务,同时还可以使用自定义步骤。

3、代理(Agent): 代理定义了执行阶段的运行环境。它可以是 Jenkins 主节点(master)或一个或多个远程节点(agent)。你可以指定阶段在特定的代理上执行,这使得你可以根据需要进行分布式构建。

4、变量(Variables): 变量允许你在 Pipeline 中存储和操作数据。你可以定义全局变量,也可以在阶段或步骤级别定义局部变量。变量可以用于保存构建号、版本号、环境配置等信息。

5、控制流(Control Flow): Pipeline 提供了条件、循环和错误处理等控制流语句,允许你根据不同的条件执行不同的操作或重试失败的步骤。

下面是一个简单的 Pipeline 示例,展示了基本的语法结构:

pipeline {
    agent any 
    stages {
        stage('Build') { 
            steps {
                // 构建步骤
                sh 'mvn clean package'
            }
        }
        stage('Test') { 
            steps {
                // 测试步骤
                sh 'mvn test'
            }
        }
        stage('Deploy') { 
            steps {
                // 部署步骤
                sh 'mvn deploy'
            }
        }
    }
}
    在这个示例中,Pipeline 定义了三个阶段(Build、Test 和 Deploy),每个阶段包含一个步骤(使
用 Maven 命令构建、测试和部署代码)。agent any 指定在任何可用代理上执行流程。

    这只是一个 Pipeline 的基本介绍,Pipeline 还提供了更多高级功能和灵活性,如并行执行、参数化
构建、异常处理等

8.2 Jenkins pipeline 入门

​ Pipeline 脚本是用 Groovy 语言编写的,但不需要专门学习 Groovy。Groovy 是一种基于 JVM 的敏捷开发语言,它结合了 Python、Ruby 和 Smalltalk 的特性,并且可以与 Java 代码很好地结合,也可以使用其他非 Java 语言编写的库。

Pipeline 支持两种语法:声明式和脚本式。

声明式语法是 Pipeline 的主要语法,它包括以下核心流程

1、pipeline: 声明 Pipeline 脚本的起始点,表明内容为声明式的 Pipeline 脚本。

2、agent: 指定 Pipeline 运行的节点(可以是 slave 或 master 节点)。

3、stages: 包含所有阶段的集合,例如打包、部署等。

4、stage: 定义一个阶段,可以有多个阶段。

5、steps: 定义每个阶段的最小执行单元。

6、post: 定义构建后的操作,根据构建结果执行相应的操作。

下面是一个简单的声明式 Pipeline 的示例:

pipeline {
    agent any 
    stages {
        stage("This is the first stage") { 
            steps {
                echo "I am xuegod"
            }
        }
    }
    post {
        always {
            echo "The process is ending"
        }
    }
}

在这个示例中:

1、pipeline 表示此脚本为声明式 Pipeline 脚本。

2、agent any 表示此 Pipeline 可以在任意可用的节点上运行。

3、stages 包含一个名为"This is the first stage"的阶段。

4、steps 定义阶段的执行步骤,此处使用 echo 命令输出"I am xuegod"。

5、post 定义了构建后的操作,always 表示不管构建成功还是失败,始终输出"The process is ending"。

8.3 Jenkins pipeline 声明式语法

8.3.1 Environment

img

environment 指令用于指定一系列键值对,这些键值对将作为环境变量定义在 Pipeline 的所有步骤或特定阶段的步骤中。具体取决于 environment 指令在 Pipeline 中的位置。

下面是一个示例,展示了 environment 指令的用法:

pipeline {
    agent any
        environment {
            CC = 'clang'
        }
    stages {
        stage('Example') {
            steps {
                sh 'printenv'
            }
        }
    }
}

image-20230909171930928

8.3.2 Options

img

options 指令用于设置 Pipeline 的行为,包括构建丢弃、并发执行、代码检出、超时、重试和时间戳等选项。

备注:

1、什么叫做代码检出?

​ 在 Jenkins Pipeline 中,代码检出是指从源代码版本控制系统(如 Git、Subversion 等)获取代码并将其放置到 Jenkins 代理节点上供后续构建步骤使用的过程。

​ 通常,在 Pipeline 的每个阶段之前,Jenkins 会自动执行默认的代码检出步骤,以确保在每个构建阶段开始之前,代码都是最新的。这样可以确保每个阶段都在相同的代码基础上运行。

​ 然而,有时候可能希望跳过默认的代码检出步骤,而是手动控制代码的获取。这在以下情况下可能有用:

1) 如果 Pipeline 中的某个阶段不需要访问代码库,例如只是执行一些不依赖于代码的操作。

2) 如果希望在 Pipeline 的某个特定阶段之前执行自定义的代码检出逻辑,例如从其他来源获取代码或切换到不同的代码分支。

​ 当使用 options { skipDefaultCheckout() }时,Pipeline 将跳过默认的代码检出步骤。这意味着在 Pipeline 的任何阶段中,需要自行编写代码检出逻辑,以便获取代码并将其放置在适当的位置供后续步骤使用。这样可以完全控制代码的获取方式和时机。

​ 请注意,如果使用了 skipDefaultCheckout(),则在 Pipeline 的任何阶段中,都需要显式地编写代码检出的步骤,否则可能会导致后续步骤无法正常执行,因为它们无法访问到代码。

下面是可用选项:

disableConcurrentBuilds:禁止并发执行 Pipeline,用于防止同时访问共享资源等场景。
    示例:options { disableConcurrentBuilds() }
buildDiscarder:设置 Pipeline 保留的构建数量。可以使用 logRotator 插件配置日志轮换,指定要保留的最大构建数量。
    示例:options { buildDiscarder(logRotator(numToKeepStr: '1')) }
skipDefaultCheckout:跳过默认设置的代码检出步骤。
    示例:options { skipDefaultCheckout() }:
skipStagesAfterUnstable:一旦构建状态进入"Unstable"状态,就跳过之后的所有 stage。
    示例:options { skipStagesAfterUnstable() }:
在 Jenkins 中,构建状态表示构建过程中的结果状态,常见的状态有"成功"(Success)、"失败"(Failure)和"不稳定"(Unstable)。"Unstable"状态表示构建完成,但存在一些非关键性的问题或警告。

使用 options { skipStagesAfterUnstable() }配置后,当 Pipeline 的某个阶段将构建状态设置为"Unstable"时,Jenkins 将立即跳过该阶段之后的所有阶段,直接进入 Pipeline 的结束状态。这样可以提高构建过程的效率,避免在已知构建不稳定的情况下继续执行后续阶段。
    例如,假设有一个 Pipeline 包含三个阶段(stage):A、B 和 C。如果在阶段 B 中设置了一个条件,当某些非关键测试失败时将构建状态设置为"Unstable",那么使用 options { skipStagesAfterUnstable() }后,如果阶段 B 的构建状态为"Unstable",Jenkins 将跳过阶段 C,并直接结束 Pipeline 的执行。
timeout:设置 Pipeline 运行的超时时间,超过超时时间,作业会被自动终止。可以指定时间和单位。
    示例:options { timeout(time: 1, unit: 'HOURS') }
retry:在失败后,重试整个 Pipeline 的次数。可以指定重试次数。
    示例:options { retry(3) }
timestamps:在 Pipeline 生成的所有控制台输出中预定义时间戳。
    示例:options { timestamps() }: 当你在 Pipeline 中执行一系列的步骤和命令时,Jenkins 会在控制台输出中显示每个步骤的执行结果和日志信息。这些输出通常以文本形式显示,其中每行代表一个输出条目。

通过使用 options { timestamps() }配置,Jenkins 会在每个控制台输出的行前添加一个时间戳,以显示该行输出的时间。这样可以帮助你更好地追踪和分析 Pipeline 的执行过程,特别是在需要查找特定输出或分析日志的时间相关性时。
pipeline {
    agent any 
    options {
        timestamps()
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello, World!'
            }
        }
        stage('Example1') {
            steps {
                echo 'Hello!!!!'
            }
        }
    }
}

上述示例中,当执行 Pipeline 时,每个控制台输出行前将显示一个时间戳。例如:

image-20230909175107992

8.3.3 Parameters

img

​ Parameters: 美 [pəˈræmətərz]

​ parameters 指令用于在 Jenkins Pipeline 中定义参数列表,这些参数允许用户在触发 Pipeline 时提供不同的值。参数值可以通过 params 对象在 Pipeline 的各个阶段中访问和使用。parameters 指令应该位于 Pipeline 的最外层,并且只能在 Pipeline 中出现一次。它定义了在触发 Pipeline 时用户可以提供的参数列表。参数定义的作用域是全局的,可以在整个 Pipeline 中使用。

​ 1、string 参数类型:用于定义字符串类型的参数。可以指定参数的名称、默认值和描述。例如: string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '')

​ 2、booleanParam 参数类型:用于定义布尔类型的参数。您可以指定参数的名称、默认值和描述。例如:booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '')

​ 通过使用 parameters 指令,您可以将 Pipeline 转变为可配置的代码,实现"Pipeline as Code"的概念。参数化构建使得 Pipeline 的执行过程更加灵活和可重用,同时也增强了可维护性。

pipeline{
    agent any
    parameters {
        string(name: 'xuegod', defaultValue: 'my name is xuegod', description: 'My name is xuegod')
        booleanParam(name: 'pod', defaultValue: true, description: 'This is my name')
    }
    stages{
        stage("stage1"){ steps{
                echo "$xuegod"
                echo "$pod"
            }
        }
    }
}

​ 在示例 Pipeline 中,使用 parameters 指令定义了两个参数:xuegod 和 pod。这些参数可以在Pipeline 的任何阶段中使用,通过${params.<参数名称>}的方式引用其值。在 stage1 阶段的步骤中, 使用 echo 命令输出了这两个参数的值。

image-20230909180407578

开始构建

控制台输出观察构建结果:

image-20230909180449810

8.3.4 Triggers

img

​ triggers 指令定义了 Pipeline 自动化触发的方式。目前有三个可用的触发器:cron 和 pollSCM upstream。

​ 作用域:被 pipeline 包裹,在符合条件下自动触发 pipeline

1、cron:

​ 接受一个 cron 风格的字符串来定义 Pipeline 触发的时间间隔,例如:

## 每周一到周五,每天中,每四个小时执行一次
triggers { cron('H */4 * * 1-5')}

cron 表达式的各个字段:

H:代表 Hashed 值,用于避免多个任务同时触发。在每个小时内,相同的 H 值只会触发一个任务。这可以确保任务在指定的时间范围内只执行一次。

*/4:时,每四个小时。

*:日,每天。

*:月,每个月。

1-5:表示工作日字段,指定工作日为周一到周五。

## 每十五分钟一次(可能在 :07, :22, :37, :52):
H/15 * * * *
## 每小时前半段每隔十分钟(三次,可能在 :04, :14, :24):
H(0-29)/10 * * * *
## 每个工作日上午 9:45 开始至下午 3:45 结束,每两小时一次:
45 9-16/2 * * 1-5
## 每个工作日上午 8 点到下午 4 点之间每两小时一次(可能是上午 9:38、上午 11:38、下午 1:38、下午 3:38):
H H(8-15)/2 * * 1-5
## 除 12 月外,每月 1 日和 15 日每天一次:
H H 1,15 1-11 *
pipeline{
    agent any
    triggers{
        cron('H */4 * * 1-5')
    }
    stages {
        stage ('Example'){
            steps {
                echo 'Hello World!'
            }
        }
    }
}

2、pollSCM

接收 cron 样式的字符串来定义一个固定的间隔,在这个间隔中,Jenkins 会检查新的源代码更新。如果存在更改, 流水线就会被重新触发。例如: triggers { pollSCM('H */4 * * 1-5') }

pollSCM 只在Jenkins 2.22 及以上版本中可用

3、upstream

接受逗号分隔的工作字符串和阈值。 当字符串中的任何作业以最小阈值结束时,流水线被重新触发。例如: triggers { upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS) }

8.3.5 Input

​ stage 的 input 指令允许你使用 input step 提示输入。 在应用了 options 后,进入 stage 的agent 或评估 when 条件前,stage 将暂停。 如果 input 被批准, stage 将会继续。 作为 input 提交的一部分的任何参数都将在环境中用于其他 stage

配置项:

message

必需的。 这将在用户提交 input 时呈现给用户。

id

input 的可选标识符, 默认为 stage 名称。

ok

input表单上的"ok" 按钮的可选文本。

submitter

可选的以逗号分隔的用户列表或允许提交 input 的外部组名。默认允许任何用户。

submitterParameter

环境变量的可选名称。如果存在,用 submitter 名称设置。

parameters

提示提交者提供的一个可选的参数列表。

pipeline {
    agent any
    stages {
        stage('Example') {
            input {
                message "Should we continue?"
                ok "Yes, we should."
                submitter "xuegod,lucky"
                parameters {
                    string(name: 'PERSON', defaultValue: 'xuegod', description: 'Who should I say hello to?')
                }
            }
            steps {
                echo "Hello, ${PERSON}, nice to meet you."
            }
        }
    }
}

构建时间相差8小时问题

Jenkins 构建时间相差8小时问题 - 林余 - 博客园 (cnblogs.com)

浏览器进入URL:Jenkins访问地址/script

执行:System.setProperty('org.apache.commons.jelly.tags.fmt.timeZone','Asia/Shanghai')

或者:

image-20230910200920247

8.3.6 Parallel

​ Declarative Pipeline 近期新增了对并行嵌套 stage 的支持,对耗时长,相互不存在依赖的 stage 可以使用此方式提升运行效率。除了 parallel stage,单个 parallel 里的多个 step 也可以使用并行的方式运行。

pipeline {
    agent any
    stages {
        stage('Non-Parallel Stage') {
            steps {
                echo 'This stage will be executed first.'
            }
        }
        stage('Parallel Stage') {
            when {
                branch 'master'
            }
            parallel { 
                stage('Branch A') {
                    agent {
                        label "for-branch-a"
                    }
                    steps {
                        echo "On Branch A"
                    }
                }
                stage('Branch B') {
                    agent {
                        label "for-branch-b"
                    }
                    steps {
                        echo "On Branch B"
                    }
                }
            }
        }
    }
}

8.4 Pipeline Scripted 语法和声明式语法

8.4.1 Declarative pipeline 和 Scripted pipeline 的比较

​ Declarative Pipeline 是一种基于 Groovy 的声明式语法,提供一种更简单、更结构化的方式来定义流水线。它更加注重流水线的整体结构,以及声明所需的阶段和步骤。

​ script Pipeline 提供了一组预定义的指令和块,使得构建、测试、部署等常见任务的编写变得更加容易。这种语法风格非常适合于简单到中等复杂度的流水线,并且可读性较高。它的主要优点是易于上手、易于理解和维护,并且具有一定的安全性,可以限制流水线的操作范围。

​ 选择 Declarative Pipeline 还是 Scripted Pipeline 取决于你的具体需求。如果你的流水线相对简单,且易于使用和理解,则 Declarative Pipeline 是一个不错的选择。如果你需要更高级的功能和更大的灵活性,或者需要与外部系统进行复杂的交互,则 Scripted Pipeline 可能更适合你的需求。

node('testhan') {
    stage('Clone') {
        echo "1.Clone Stage"
        git url: "https://gitee.com/qingcaihub/jenkins-sample"
        script {
            build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
        }
    }
    stage('Test') {
      echo "2.Test Stage"

    }
    stage('Build') {
        echo "3.Build Docker Image Stage"
        sh "docker build -t 192.168.20.206/jenkins-demo/jenkins-demo:${build_tag} ."
    }
    stage('Push') {
       echo "4.Push Docker Image Stage"
       withCredentials([usernamePassword(credentialsId: 'dockerharbor',passwordVariable: 'dockerHubPassword', usernameVariable: 'dockerHubUser')]) {
           sh "docker login 192.168.20.206 -u ${dockerHubUser} -p ${dockerHubPassword}"
           sh "docker push 192.168.20.206/jenkins-demo/jenkins-demo:${build_tag}"
       }
    }
    stage('Deploy to dev') {
        echo "5. Deploy DEV"
           sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-dev-harbor.yaml "
        sh "kubectl apply -f k8s-dev-harbor.yaml  --validate=false"
    }   
    stage('Promote to qa') {    
        def userInput = input(
            id: 'userInput',

            message: 'Promote to qa?',
            parameters: [
                [
                    $class: 'ChoiceParameterDefinition',
                    choices: "YES\nNO",
                    name: 'Env'
                ]
            ]
        )
        echo "This is a deploy step to ${userInput}"
        if (userInput == "YES") {
            sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-qa-harbor.yaml "
            sh "kubectl apply -f k8s-qa-harbor.yaml --validate=false"
            sh "sleep 6"
            sh "kubectl get pods -n qatest"
        } else {
            //exit
        }
    }
    stage('Promote to pro') {   
        def userInput = input(

            id: 'userInput',
            message: 'Promote to pro?',
            parameters: [
                [
                    $class: 'ChoiceParameterDefinition',
                    choices: "YES\nNO",
                    name: 'Env'
                ]
            ]
        )
        echo "This is a deploy step to ${userInput}"
        if (userInput == "YES") {
            sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-prod-harbor.yaml "
            sh "kubectl apply -f k8s-prod-harbor.yaml --record --validate=false"
        }
    }
}

扩展:上面 jenkins 构建 devops 的 pipeline 变成声明式语法

pipeline {
    agent {
        node {
            label 'testhan'
        }
    }
    stages {
        stage('Clone') {
            steps {
                echo "1.Clone Stage"
                git url: "https://gitee.com/qingcaihub/jenkins-sample"
                script {
                    build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
                }
            }
        }
        stage('Test') {
            steps {
                echo "2.Test Stage"
            }
        }
        stage('Build') {
            steps {
                echo "3.Build Docker Image Stage"
                sh "docker build -t 192.168.20.206/jenkins-demo/jenkins-demo:${build_tag} ."
            }
        }
        stage('Push') {
            steps {
                echo "4.Push Docker Image Stage"
                withCredentials([usernamePassword(credentialsId: 'dockerharbor',passwordVariable: 'dockerHubPassword', usernameVariable: 'dockerHubUser')]) {
                    sh "docker login 192.168.20.206 -u ${dockerHubUser} -p ${dockerHubPassword}"
                    sh "docker push 192.168.20.206/jenkins-demo/jenkins-demo:${build_tag}"
                }
            }
        }
        stage('Deploy to dev') {
            steps {
                echo "5. Deploy DEV"
                sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-dev-harbor.yaml"
                sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s-dev-harbor.yaml"
                sh "kubectl apply -f k8s-dev-harbor.yaml  --validate=false"
            }
        }
        stage('Promote to qa') {
            steps {
                def userInput = input (
                    id: 'userInput',
                    message: 'Promote to qa?',
                    parameters: [
                        choice(
                            choices: "YES\nNO",
                            description: 'Select an option',
                            name: 'Env'
                        )
                    ]
                )
                echo "This is a deploy step to ${userInput}"
                when {
                    expression {
                        userInput == 'YES'
                    }
                }
                steps {
                    sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-qa-harbor.yaml"
                    sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s-qa-harbor.yaml"
                    sh "kubectl apply -f k8s-qa-harbor.yaml --validate=false"
                    sh "sleep 6"
                    sh "kubectl get pods -n qatest"
                }
            }
        }
        stage('Promote to pro') {
            steps {
                def userInput = input (
                    id: 'userInput',
                    message: 'Promote to pro?',
                    parameters: [
                        choice(
                            choices: "YES\nNO",
                            description: 'Select an option',
                            name: 'Env'
                        )
                    ]
                )
                echo "This is a deploy step to ${userInput}"
                when {
                    expression {
                        userInput == 'YES'
                    }
                }
                steps {
                    sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-prod-harbor.yaml "
                    sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s-prod-harbor.yaml"
                    sh "cat k8s-prod-xuegod.yaml"
                    sh "kubectl apply -f k8s-prod-harbor.yaml --record --validate=false"
                }
            }
        }
    }
}

8.5 Jenkins+k8s+nexus++gitlab+harbor+sonarqube 构建 DevOps

下面实验需要的镜像包下载地址:

链接:https://caiyun.139.com/m/i?145C7wpAowQO8 提取码:MShu

复制内容打开移动云盘 PC 客户端,操作更方便哦

8.5.1 安装 sonarqube

在 新机器 上操作:

需要先安装 docker: 修改内核参数

cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1 
EOF

modprobe br_netfilter 
sysctl --system

yum install -y docker-ce -y
systemctl enable docker && systemctl start docker

#查看 docker 状态,如果状态是 active(running),说明 docker 是正常运行状态

systemctl status docker

修改 docker 配置文件

cat > /etc/docker/daemon.json <<EOF
{
 "registry-mirrors":["https://vh3bm52y.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hub-mirror.c.163.com"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "insecure-registries":["192.168.2.206","harbor"]
}

EOF

注:上面配置的是 docker 镜像加速器

重启 docker 使配置生效

systemctl restart docker

在/etc/sysctl.conf 文件最后添加一行

vm.max_map_count=262144

执行如下命令使配置生效:

sysctl -p /etc/sysctl.conf
docker load -i postgres.tar.gz
docker load -i sonarqube.tar.gz

sysctl -w vm.max_map_count=262144

运行容器:

docker run -d  --name postgres10  -p 5432:5432  -e POSTGRES_USER=sonar -e POSTGRES_PASSWORD=123456 postgres

docker run -d --name sonarqube7.9 -p 9000:9000 --link postgres10 -e SONARQUBE_JDBC_URL=jdbc:postgresql://postgres10:5432/sonar  -e SONARQUBE_JDBC_USERNAME=sonar -e SONARQUBE_JDBC_PASSWORD=123456  -v sonarqube_conf:/opt/sonarqube/conf -v sonarqube_extensions:/opt/sonarqube/extensions -v sonarqube_logs:/opt/sonarqube/logs -v sonarqube_data:/opt/sonarqube/data sonarqube

在 jenkins 中安装 sonarqube 插件:

系统管理->插件管理->可选插件:搜索 sonar,找到 Sonarqube Scanner->选择 Sonarqube Scanner 直接安装,安装之后重启 jenkins 即可:

192.168.1.63:30002/restart

登录 sonarqube http://192.168.1.35:9000/

默认用户名和密码是 admin

img

在 sonarqube 的 web 界面创建一个 token:

img

img

选择 Generate 出现如下:

image-20230910173126694

把 copy 后面的一串 token 记录下来:

c304b9bc5c45418bd4175be5ff59b856f16f2550

回到 k8s 的控制节点:

cd /root/microservic-test

mvn sonar:sonar -Dsonar.host.url=http://192.168.2.202:9000 -Dsonar.login=c304b9bc5c45418bd4175be5ff59b856f16f2550

这样就可以把代码上传到 sonarqube 了

代码目前不支持这个版本,所以这个上传到 sonarqube 是有问题的,结果大家可以不用看,会用就可以

8.5.2 Jenkins 界面添加 harbor 凭据

需要自己找机器安装好 harbor,harbor 机器 ip:192.168.1.62,可参考中级班课件 harbor 私有仓库安装 harbor

1.添加凭据

首页------>系统管理à管理凭据------- >点击 Stores scoped to Jenkins 下的第一行 jenkins,显

img

示如下

点击这个全局凭据,出现如下------- >

img

点击左侧的添加凭据,出现如下------- >

img

username:admin

password:Harbor12345

ID:dockerharbor

描述:随意

上面改好之后选择确定即可

8.5.3 安装 nexus

概念:

​ Nexus 服务器是一个代码包管理的服务器,可以理解 Nexus 服务器是一个巨大的 Library 仓库。Nexus 可以支持管理的工具包括 Maven , npm 等,对于 JAVA 开发来说,只要用到 Maven 管理就可以了。

​ Nexus 服务器作用:因为传统的中央仓库在国外,其地理位置比较远,下载速度比较缓慢。因此, 当公司开发人员数量越来越多时,如果不架设一台自己的 Nexus 服务器,会产生大量的流量阻塞带宽,

​ 并且在出现一些不可抗原因(光缆被挖断)导致无法连接到中央仓库时,开发就会因为无法下载相关依赖包而进度停滞。因此在本地环境部署一台私有的 Nexus 服务器来缓存所有依赖包,并且将公司内部开发的私有包也部署上去,方便其他开发人员下载,是非常有必要的。因为 Nexus 有权限控制,因此外部人员是无法得到公司内部开发的项目包的。

下面将介绍如何将自己的 maven 构件发布到nexus 私服 上呢?

在 新机器上安装:

docker load -i nexus3.tar.gz

docker run -d -p 81:8081 -p 82:8082 -p 83:8083 -v /etc/localtime:/etc/localtime --name nexus3 sonatype/nexus3

在日志中,您会看到一条消息: Started Sonatype Nexus OSS 3.20.1-01 这意味着您的 Nexus Repository Manager 可以使用了。现在转到浏览器并打开

http://192.168.2.202:81/

第一步:

1、在 pom.xml 文件中声明发布的宿主仓库和 release 版本发布的仓库。

<!-- 发布构件到 Nexus -->
    <distributionManagement>
        <repository>
            <id>releases</id>
            <name>nexus-releases</name>
            <url>http://192.168.2.202:81/repository/maven-releases/</url>
        </repository>
        <snapshotRepository>
            <id>snapshots</id>
            <name>nexus-snapshots</name>
            <url>http://192.168.2.202:81/repository/maven-snapshots/</url>
        </snapshotRepository>
    </distributionManagement>

第二步:在 settings.xml 文件中配置

由于用 Maven 分发构件到远程仓库需要认证,须要在~/.m2/settings.xml 或者中加入验证信息:

<servers>
    <server>
        <id>public</id>
        <username>admin</username>
        <password>123456</password>
    </server>
    <server>
        <id>releases</id>
        <username>admin</username>
        <password>123456</password>
    </server>
    <server>
        <id>snapshots</id>
        <username>admin</username>
        <password>123456</password>
    </server>
</servers>

注意: settings.xml 中 server 元素下 id 的值必须与 POM 中 repository 或snapshotRepository 下 id 的值完全一致 。

8.5.4 安装 gitlab

在新机器上安装 gitlab

docker load -i gitlab.tar.gz

docker run -d -p 443:443 -p 80:80 -p 222:22 --name gitlab --restart always -v /home/gitlab/config:/etc/gitlab -v /home/gitlab/logs:/var/log/gitlab -v /home/gitlab/data:/var/opt/gitlab gitlab/gitlab-ce

改配置:

vim /home/gitlab/config/gitlab.rb

增加如下三行:

external_url = 'http://192.168.2.202'
gitlab_rails['gitlab_ssh_host'] = '192.168.2.202'
gitlab_rails['gitlab_shell_ssh_port'] = 222

重启 docker:

docker restart gitlab

登录 192.168.1.35 即可登录:

第一次登录注册账号密码之后,报错如下:

Your account is pending approval from your GitLab administrator and hence bl

可通过如下方法实现:

[root@xuegod63 ~]# docker exec -it gitlab sh 

root@1f682047a6ea:/## gitlab-rails console


irb(main):001:0> u=User.where(id:1).first
=> #<User id:1 @root>
irb(main):002:0> u.password='12345678'
=> "12345678"
irb(main):003:0> u.password_confirmation='12345678'
=> "12345678"
irb(main):004:0> u.save!
=> true
irb(main):005:0> exit

再次登录 http://192.168.2.202

用户名是 root

密码是 12345678

## -d:后台运行

## -p:将容器内部端口向外映射## --name:命名容器名称

## -v:将容器内数据文件夹或者日志、配置等文件夹挂载到宿主机指定目录

在 Jenkins 安装 git 插件

img

系统管理-插件管理-可选插件-搜索 git 安装即可

在 Jenkins 上添加 gitlab 凭据

Jenkins-凭据-全局凭据

image-20230910180810388

在 gitlab 上新建项目:

image-20230910180905169

image-20230910180925316

img

image-20230910181045622

到gitlab所在物理中,创建密钥对:

ssh-keygen -t rsa -b 2048 #一路回车

获取公钥,上传:

$ cat /root/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLYLFmBkMCk0nB/SU0s03YdPaqWcdC5WkPJsHgWW7rz5QWu8jYqguH2qVAV1AwStmYi0PwEniHWj/nriRVhxzehY58MAB7E/PczrHsMH/TEJtQYV0RPtpN7JsljGWSb2ZhOMqed2mVsiUJjqLuyKgK085M5CM6NY3c9XhAXFU2gAwA/R+pS+sjYahY71tS17ARGnKgljX2NsfWKbxtyp38gc8kS0XgPUSo0/woc8lMMpIMrfuW1FQtn/rFoJyA4NR8JlHMRScc26s3ep1hO2gd3kP7ysFyG3snSzL7Fld7wTa+xSOS6VwXC+16/rEZ5jmLe3y12EwVQdDhhkA4gCjV root@nfs-mariab-pinpoint

http://192.168.2.202/-/profile/keys

image-20230910182110625

image-20230910181947381

提交本地代码到 gitlab:

$ yum install git -y 
$ unzip microservic-test.zip 
$ cd microservic-test
$ rm -rf .git/

#建仓
$ git init

#把当前文件夹所有代码提交
$ git add *

#代码提交到缓冲区
$ git commit -m "add microservice-test"

若提交代码到缓冲区出现以下报错:

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'root@nfs-mariab-pinpoint.(none)')

根据提示执行两个命令即可:

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"
$ pwd
/root/springcloud/microservic-test

$ git remote add origin http://192.168.2.202/root/microservice-test.git

代码提交到远程仓库

$ git push -u origin master

最后一步 push 推送过去,push 的时候,会让你输入账号和密码

这里的用户名:root

密码: 12345678

image-20230910184952599

回到 gitlab 首页,可以看到,已经有项目了:

8.6 jenkins-k8s-harbor-gitlab-将springcloud开发的代码自动化部署到K8S集群

8.6.1 工作节点上传镜像:

jenkins-maven.tar.gz 这个压缩包封装的镜像带有 mvn 命令,

[root@k8s-node02 ~]# docker load -i jenkins-maven.tar.gz

8.6.2 修改jenkins的pod模板镜像

在 http://192.168.2.201:30002/configureClouds/,把 Container Template 镜像改成

jenkins/jenkins-maven:v1

img

jenkins-jnlp-v2.tar.gz 压缩包解压之后的镜像 jenkins/jenkins-maven:v1

8.6.3 修改 gitlab 上 portal.yaml 文件:

img

把 image 镜像变成:

192.168.2.206/microservice/jenkins-demo:v1

portal.yaml 文件如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: portal 
  namespace: ms 
spec:
  ingressClassName: nginx
  rules:
    - host: portal.ctnrs.com 
      http:
        paths:
        - path: /
          pathType:  Prefix
          backend:
            service: 
              name: portal 
              port: 
                number: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: portal
  namespace: ms
spec:
  ports:
  - port: 8080
    name: portal 
  selector:
    project: ms
    app: portal
---
apiVersion: apps/v1
kind: Deployment 
metadata:
  name: portal
  namespace: ms 
spec:
  replicas: 1
  selector:
    matchLabels:
      project: ms
      app: portal
  template:
    metadata:
      labels:
        project: ms 
        app: portal
    spec:
      imagePullSecrets:
      - name: registry-pull-secret
      containers:
      - name: portal
        image: 192.168.2.206/microservice/jenkins-demo:v1
        imagePullPolicy: Always
        ports:
          - protocol: TCP
            containerPort: 8080 
        resources:
          limits:
            cpu: 1
            memory: 1Gi
        readinessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 60
          periodSeconds: 10
        livenessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 60
          periodSeconds: 10

8.6.4 jenkins流水线部署

打开 Jenkins,新建流水线,流水线名字随便起一个

比方说构建的流水线任务名是 jenkins-spingcloud-k8s,在 pipeline 里, /workspace/jenkins-spingcloud-k8s/这个位置,workspace 下的目录名字也要叫作 jenkins-spingcloud-k8s

在 Pipeline Script 处输入如下内容:

node('testhan') {
    stage('Clone') {
        echo "1.Clone Stage"
        git credentialsId: 'gitlab', url: 'http://192.168.2.202/root/microservice-test.git'
            script {
                build_tag = sh(returnStdout: true, script: 'git rev-parse --shortHEAD').trim()
            }
        }

    stage('Test') {
        echo "2.Test Stage"
    }

    stage('mvn') {
        sh "mvn clean package -D maven.test.skip=true"
    }

    stage('Build') {
        echo "3.Build Docker Image Stage"
        sh "cd /home/jenkins/agent/workspace/jenkins-spingcloud-k8s/portal-service"
        sh "docker build --tag 192.168.2.206/microservice/jenkins-demo:v1 /home/jenkins/agent/workspace/jenkins-spingcloud-k8s/portal-service/"
    }

    stage('Push') {
        echo "4.Push Docker Image Stage"
        withCredentials([usernamePassword(credentialsId: 'dockerharbor',passwordVariable: 'dockerHubPassword', usernameVariable: 'dockerHubUser')]){
            sh "docker login 192.168.2.206 -u ${dockerHubUser} -p ${dockerHubPassword}"
            sh "docker push 192.168.2.206/microservice/jenkins-demo:v1"
        }
    }

    stage('Promoteto pro') {
        sh "kubectl apply -f /home/jenkins/agent/workspace/jenkins-spingcloud-k8s/k8s/portal.yaml"
    }
}

立即构建即可,注意事项

        git credentialsId: 'gitlab', url: 'http://192.168.2.202/root/microservice-test.git'

参数化构建可参数:https://plugins.jenkins.io/git-parameter/

8.6.5 验证:

构建完成后:

image-20230910194944813

[root@k8s-master01 microservic-test-dev1]# kubectl get pod -nms
NAME                     READY   STATUS    RESTARTS   AGE
portal-67859894f-7prsp   1/1     Running   0          86s