代码拉取完成,页面将自动刷新
同步操作将从 杜宽/spring-boot-project 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
pipeline {
agent {
kubernetes {
cloud 'kubernetes' #指定要连接yun的名称
slaveConnectTimeout 1200 #超时时间
workspaceVolime hostPathWorkspaceVolume(hostPath: "/opt/workspace",readOnly: false) #将构建的临时目录进行持久化(在node节点上,要注意权限),否则pod删除了,npm或mvn编译是下载的module就会消失,只要值针对npm。
#workspace 必须要进行持久化,因为不光可以保存 npm编译时候的依赖包,还保存 git拉取的代码,持久化后git fetch就可以使用浅克隆拉取少量的代码,优化速度。
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\'] #第一个容器
image: 'registry.cn-beijing.aliyuncs.com/citools/jnlp:alpine'
name: jnlp
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/etc/hosts"
name: "volume-hosts"
readOnly: false
- command: #第二个容器
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
image: "atlassian/maven:3.5-jdk-8-alpine" #版本要配合开发的版本
imagePullPolicy: "IfNotPresent"
name: "build"
tty: true
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/root/.m2/" #将构建时的插件进行持久化
name: "volume-maven-repo"
readOnly: false
- mountPath: "/etc/hosts"
name: "volume-hosts"
readOnly: false
- command: #第三个容器
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
image: "registry.cn-beijing.aliyuncs.com/citools/kubectl:self-1.17"
imagePullPolicy: "IfNotPresent"
name: "kubectl"
tty: true
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/var/run/docker.sock"
name: "volume-docker"
readOnly: false
- mountPath: "/etc/hosts"
name: "volume-hosts"
readOnly: false
- command: #第四个容器。如果k8s的runc时containerd,还是需要在机器上安装docker,需要借助docker打镜像。docker in docker的形式,绑定宿主机的docker.sock
还有一种解决方案, kaniko,也可以根据dockerfile进行构建镜像,这种更加安全。 可以直接替换镜像为kaniko,利用kaniko命令打镜像
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
image: "registry.cn-beijing.aliyuncs.com/citools/docker:19.03.9-git"
imagePullPolicy: "IfNotPresent"
name: "docker"
tty: true
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/var/run/docker.sock" #在容器中执行docker命令的时候需要借助宿主机docker
name: "volume-docker"
readOnly: false
- mountPath: "/etc/hosts"
name: "volume-hosts"
readOnly: false
restartPolicy: "Never"
nodeSelector:
build: "true"
securityContext: {}
volumes:
- hostPath:
path: "/var/run/docker.sock"
name: "volume-docker"
- hostPath:
path: "/usr/share/zoneinfo/Asia/Shanghai"
name: "volume-2"
- hostPath:
path: "/etc/hosts"
name: "volume-hosts"
- name: "volume-maven-repo"
hostPath:
path: "/opt/m2"
'''
}
}
options {
timestamps() // 设置在项目打印日志时带上对应时间
disableConcurrentBuilds() // 不允许同时执行流水线,被用来防止同时访问共享资源等
timeout(time: 5, unit: 'MINUTES') // 设置流水线运行超过n分钟,Jenkins将中止流水线
buildDiscarder(logRotator(numToKeepStr: '5')) // 表示保留n次构建历史
}
environment {
CommitID = ''
TAG = ""
HARBOR_ADDRESS = "www.harbor.com"
NAMESPACE= "1111"
IMAGE_NAME = "qwewqe"
REGISTRY_DIR = "231" #HARBOR仓库中的地址
GIT_TAG= "" #GIT_TAG = sh(returnStdout: true,script: 'git describe --tags --always').trim() #获取当前分支的tag,将master的tag作为镜像分支,拉取代码的时候还是指定分支,自动触发时候的配置也不变还是根据env.gitlabBranch进行判断,只不过在gitlab中将触发构建的条件改成tag push.
}
parameters {
gitParameter(name: 'BRANCH',branch: '',branchFilter: 'origin/.*'),defaultValue: '',description:"分支名称" ,quickFilterEnabled: false,selectedValue: 'NONE', sortMode: 'NONE',tagFilter: '*',type: 'PT_BRANCH')
#选择分支,会出现列表让你选择
}
triggers{ #触发器,这个类型是triggerOnMergeRequest可以替换成别的类型
gitlab(triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: 'All', secretToken: "${env.GIT_TOKEN}") // 预留Gitlab提交自动构建
}
stages {
stage('pulling Code') {
parallel { #并非执行,根据when条件判断执行哪一个
stage('pulling Code') {
when {
expression {
env.gitlabBranch == null #当时在jenkins web界面手动构建时,这个变量的值会是空的
}
}
steps {
git(changelog:true,poll:true,branch: "${BRANCH}", credentialsId: '5db8da30-664c-4d26-8801-d688304e9925', url: "${REPO_URL}")#${BRANCH}变量为参数传值,指明要拉取的分支 ${REPO_URL}变量为参数传值,要去拉取哪个url
script {
CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
TAG = BUILD_TAG + '-' + COMMIT_ID
GIT_TAG = sh(returnStdout: true,script: 'git describe --tags --always').trim()
println "Current branch is ${BRANCH},Commit ID is ${COMMIT_ID},Image TAG is ${TAG}"
#上面是演示,真正环境的TAG = test + BRANCH + CommitID
#如果要集成私有部署环境 私有部署环境会有一个单独的分支。master-私有部署,开发都会向这个分支进行合并,
tag= test + BRANCH + CommitID + git_tag(tag获取的只是当前分支的最新tag)
但是如果集成了私有部署则可能部署的时候需要根据定义para来进行区分,比如在部署环节使用 when 判断para如果是私有部署环境,可以部署到其他集群或者不进行部署(只需要在部署环节采用不同的kubeconfig即可,kubectl --kubeconfig使用另一个集群的)
建议私有部署环境和主环境分割开来,单独的一套代码库,单独的jenkins
}
}
}
stage('pulling Code by trigger') { #jenkins监控master分支变化,如果开发往master分支pull或者meraged则会触发自动构建,如果是开发要进行测试,则需要单独扯出来一个分支,或者是自己的分支,构建的时候就需要手动进行选择分支。
#使用的是tag的监控,gitlab中设定只有当推送tag的时候才会调用jenkins的webhook进行触发,在jenkins的触发器配置拉取master代码进行构建,git的tag也可以通过命令进行获取,拉取代码的时候会知道最新的git tag是哪一个,可以通过命令获取到GIT_TAG = sh(returnStdout: true,script: 'git describe --tags --always').trim()。将这个定义镜像tag的时候将git tag添加进去。 通过推送tag触发的流程是真正要部署在生产环境中的,在生产环境中的pipline中,会定义一个parameters,列出harbor中的镜像tag列表。
when { #注意这个触发器是通过手动在jenkins web界面上添加到
expression {
env.gitlabBranch != null #当是通过webhook调用时,这个变量的值不是空的
}
}
steps {
git(url: "${REPO_URL}", branch: env.gitlabBranch, credentialsId: 'gitlab-key') #${REPO_URL}变量为参数传值,要去拉取哪个url
script {
CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim() #用标准输出配置环境变量
GIT_TAG = sh(returnStdout: true,script: 'git describe --tags --always').trim()。#获取当前分支的最新tag
TAG = CommitID + "-" + BRANCH + "-" + GIT_TAG #BUILD_TAG为jenkins的变量,有唯一性
println "Current branch is ${env.BRANCH},Commit ID is ${COMMIT_ID},Image TAG is ${TAG}"
#上面是演示,真正环境的TAG = prod-uat + GIT_TAG (+ BRANCH + CommitID)可以不加
}
}
}
}
}
//分支逻辑:只管master分支,将master分支做成自动触发,jenkins中指定target branch为master,自动触发的条件为gitlab中设置 tag push,只有在推送tag的时候,会自动拉取master代码,并获取到这个分支的最新tag值,那么生成的镜像tag为tag+master+CommitID+prod
其他分支,需要开发手动进行更新,镜像tag为分支名+commitid+test
在往生成环境部署的时候,使用tag的动态参数列表,让用户选择,同时使用filter过滤出prod结尾的tag
#拉取指定分支的tag https://plugins.jenkins.io/git-parameter/
#单元测试可以和代码检查并行执行
#jenkins中需要安装juint插件,如果单元测试没通过会报错,那么就不会继续像下执行 https://www.tapd.cn/help/show#1120003271001000231
stage('单元测试') {
steps {
echo "starting unitTest......"
container("maven") {
mvn clean test -Dautoconfig.skip=true -Dmaven.test.skip=false -Dmaven.test.failure.ignore=false #值为true,测试报错忽略,这种情况下如果单元测试失败,pipline不会失败,会继续向下执行,所以需要将这个值改为false遇到错误则终止流水线并报错
mvn surefire-report:report-only #这个插件的作用是生成html的测试报告,如果需要使用可以在应用的pom.xml文件中加入 surefire-report插件的配置
}
post {
// 总数发布测试情况
always {
junit '**/target/surefire-reports/*.html'
}
}
}
}
https://blog.csdn.net/qq_31977125/article/details/100138701
stage('SonarQube analysis') {
// 这里是判断环境变量 CHECK 为 true 的时候才执行后面的步骤
when {
environment name: 'CHECK', value: 'true'
}
steps{
echo "starting codeAnalyze with SonarQube......"
// 这里的 sonarqube 就是我们前面配置的名称sonarqube
withSonarQubeEnv('sonarqube') { //在jenkins中下载sonarqueb scanner插件,在jenkins配置中配置sonarqube server的地址(server需要自己安装) 其中name为”sonarqube”,这个名称被 withSonarQubeEnv引用,还需要创建一个sonarqube token的secert,jenkins插件通过这个secert与sonarqube server通信
在项目的跟路径pom.xml同级目录创建sonar-project.properties,配置中指定了projectName(sonarqube中)、language=java等信息,配置信息也可以做在jenkins job中.还需要在sonarqube中配置webhook,供进入SonarQube ,选择菜单“配置配置-> 网络调用( Webhooks)- > 新建网络调用”,设置webhook的作用是为了让sonarqube将测试结果告知jenkins,通知(sonarqube中可以设置质量阀代码重复度等)
// 这里使用名字叫做maven的容器运行
container("maven") {
sh 'mvn sonar:sonar'
}
}
script {
timeout(10) {
//利用sonar webhook功能通知pipeline代码检测结果,未通过质量阈,pipeline将会fail,webhook地址为jenkins地址+sonarqube-webhook,这个是jenkins中sonarqube scanner插件提供的,由sonarqube server通过webhook通知jenkins,同时还行要在sonarqube server中配置质量阀门
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "未通过Sonarqube的代码质量阈检查,请及时修改!failure: ${qg.status}"
}
}
}
}
https://blog.csdn.net/jiangjunsss/article/details/119918932
https://qa.1r1g.com/sf/ask/3810007981/ #直接在pipline中指定sonar的配置,
https://www.jianshu.com/p/7901471371ab
https://www.cnblogs.com/cay83/p/7537843.html
https://blog.csdn.net/qq_31977125/article/details/100138701
}
stage('Building') {
parallel {
stage('Building') {
steps {
container(name: 'build') {
sh """
echo "Building Project..."
mvn clean install -DskipTests -DproxyHost=https://repo1.maven.org/maven2 -DproxyPort=80 #编译的命令,需要和开发确认,也可以用参数替代 ${BUILD_COMMAND}
#mvn clean package -DskipTests 执行编译测试类,但是跳过执行测试过程。;mvn package -Dmaven.test.skip=true 完全跳过测试编译。建议使用这个
"""
}
}
}
stage('Build image') {
enviorment{
HARBOR_USER = credentials('HARBOR_ACCOUNT') #引用jenkins配置的凭据,将值给变量
}
steps {
#GROOVY语法引用凭据 withCredentials([usernamePassword(credentialsId: '1e04fe2e-0835-4a90-be12-0d9f7a10cf58', passwordVariable: 'Password', usernameVariable: 'Username')]) {
container(name: 'docker') {
sh """
echo ${HARBOR_USER_USR} ${HARBOR_USER_PSW} ${TAG}
docker build -t ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} .
docker login -u ${HARBOR_USER_USR} -p ${HARBOR_USER_PSW} ${HARBOR_ADDRESS}
docker push ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG}
"""
}
}
}
}
stage('Deploy') {
enenvironment {
MY_KUBECONFIG = crcredentials('study-k8s-kconfig') #引用kubeconfig的凭据
}
when {
expression{
DEPLOY != false #DEPLOY为变量,可以通过参数创建
}
}
steps {
container(name: 'kubectl') {
sh """
/usr/local/bin/kubectl --kubeconfig=${MY_KUBECONFIG} set image deployment -l ${DEPLOY_LABEL} ${IMAGE_NAME}=${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} -n ${NAMESPACE} --record
注:命令中所有参数都可以改为变量的形式,变量可以由web界面提供也可以由para参数在file中定义
if kubectl rollout status deployment -n ${NAMESPACE} ${IMAGE_NAME} --timeout=60s --kubeconfig $MY_KUBECONFIG #这个命令也是查看更新状态的,超时了自动退出结果就是 1不是0 ;then
echo ok
else
kubectl rollout undo deployment -n ${NAMESPACE} ${IMAGE_NAME} -kubeconfig $MY_KUBECONFIG
echo "部署失败,已经自动回滚"
exit 2
fi
#这里可以模拟gitops的概念,将更新后的deployment,生成yaml,将yaml推送到gitlab中
kubectl get deployment xxx -o yaml >
git add .
.....
"""
}
}
}
}
post{. #可以在jenkins中安装微信插件或者叮叮插件
always {
script{
println("always")
sh 'pwd'
}
}
success {
script{
currentBuild.description += "\n 构建成功"
}
}
failure{
script{
currentBuild.description += "\n 构建失败"
}
}
aborted {
script{
currentBuild.description += "\n 构建取消"
}
}
}
}
=============
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。