DevOps三 Harbor与Jenkins流水线介绍
本文介绍了Harbor私有Docker镜像仓库的集成与使用。Harbor相比官方Registry提供更完善的权限管理、安全扫描等功能。文章详细说明了Harbor的安装步骤,包括下载解压、配置修改和启动流程。同时演示了Harbor的核心使用场景:创建用户和私有项目、推送/拉取镜像操作。特别针对Jenkins集成场景,说明了如何让Jenkins容器使用宿主机Docker服务来实现镜像构建和发布。通过H
一 集成Harbor
1.1 Harbor介绍
前面在部署项目时,我们主要采用Jenkins推送jar包到指定服务器,再通过脚本命令让目标服务器对当前jar进行部署,这种方式在项目较多时,每个目标服务器都需要将jar包制作成自定义镜像再通过docker进行启动,重复操作比较多,会降低项目部署时间。
我们可以通过Harbor作为私有的Docker镜像仓库。让Jenkins统一将项目打包并制作成Docker镜像发布到Harbor仓库中,只需要通知目标服务,让目标服务统一去Harbor仓库上拉取镜像并在本地部署即可。
Docker官方提供了Registry镜像仓库,但是Registry的功能相对简陋。Harbor是VMware公司提供的一款镜像仓库,提供了权限控制、分布式发布、强大的安全扫描与审查机制等功能
1.2 Harbor安装
这里采用原生的方式安装Harbor。
-
下载Harbor安装包:https://github.com/goharbor/harbor/releases/download/v2.3.4/harbor-offline-installer-v2.3.4.tgz
-
拖拽到Linux并解压:
tar -zxvf harbor-offline-installer-v2.3.4.tgz -C /usr/local/ -
修改Harbor配置文件:
-
首先复制一份harbor.yml配置
cp harbor.yml.tmpl harbor.yml -
编辑harbor.yml配置文件
配置Harbor文件 
-
-
启动Harbor
./install.sh查看日志 
-
登录Harbor
登录Harbor 
-
首页信息
首页信息 
1.3 Harbor使用方式
Harbor作为镜像仓库,主要的交互方式就是将镜像上传到Harbor上,以及从Harbor上下载指定镜像
在传输镜像前,可以先使用Harbor提供的权限管理,将项目设置为私有项目,并对不同用户设置不同角色,从而更方便管理镜像。
1.3.1 添加用户构建项目
-
创建用户
创建用户 
|
-
构建项目(设置为私有)
构建项目 
-
给项目追加用户
追加用户管理 
-
切换测试用户
切换测试用户 
1.3.2 发布镜像到Harbor
-
修改镜像名称
名称要求:[harbor地址/项目名/镜像名:版本]
修改镜像名称 
-
修改daemon.json,支持Docker仓库,并重启Docker
修改daemon.json,支持Docker仓库 
-
设置登录仓库信息
docker login -u 用户名 -p 密码 Harbor地址 -
推送镜像到Harbor
推送镜像到Harbor 

1.3.3 从Harbor拉取镜像ls
跟传统方式一样,不过需要先配置/etc/docker/daemon.json文件
{
"registry-mirrors": ["https://pee6w651.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.11.11:80"]
}
| 拉取镜像 |
|---|
![]() |
1.3.4 Jenkins容器使用宿主机Docker
构建镜像和发布镜像到harbor都需要使用到docker命令。而在Jenkins容器内部安装Docker官方推荐直接采用宿主机带的Docker即可。
设置Jenkins容器使用宿主机Docker
-
设置宿主机docker.sock权限:
sudo chown root:root /var/run/docker.sock sudo chmod o+rw /var/run/docker.sock -
添加数据卷
version: "3.1" services: jenkins: image: jenkins/jenkins container_name: jenkins ports: - 8080:8080 - 50000:50000 volumes: - ./data/:/var/jenkins_home/ - /usr/bin/docker:/usr/bin/docker - /var/run/docker.sock:/var/run/docker.sock - /etc/docker/daemon.json:/etc/docker/daemon.json
1.3.5 添加构建操作
| 制作自定义镜像 |
|---|
![]() |
1.3.6 编写部署脚本
部署项目需要通过Publish Over SSH插件,让目标服务器执行命令。为了方便一次性实现拉取镜像和启动的命令,推荐采用脚本文件的方式。
添加脚本文件到目标服务器,再通过Publish Over SSH插件让目标服务器执行脚本即可。
-
编写脚本文件,添加到目标服务器
harbor_url=$1 harbor_project_name=$2 project_name=$3 tag=$4 port=$5 imageName=$harbor_url/$harbor_project_name/$project_name:$tag containerId=`docker ps -a | grep ${project_name} | awk '{print $1}'` if [ "$containerId" != "" ] ; then docker stop $containerId docker rm $containerId echo "Delete Container Success" fi imageId=`docker images | grep ${project_name} | awk '{print $3}'` if [ "$imageId" != "" ] ; then docker rmi -f $imageId echo "Delete Image Success" fi docker login -u DevOps -p P@ssw0rd $harbor_url docker pull $imageName docker run -d -p $port:$port --name $project_name $imageName echo "Start Container Success" echo $project_name并设置权限为可执行
chmod a+x deploy.sh如图 
1.3.7 配置构建后操作
| 执行脚本文件 |
|---|
![]() |
二 Jenkins流水线
2.1 Jenkins流水线任务介绍
之前采用Jenkins的自由风格构建的项目,每个步骤流程都要通过不同的方式设置,并且构建过程中整体流程是不可见的,无法确认每个流程花费的时间,并且问题不方便定位问题。
Jenkins的Pipeline可以让项目的发布整体流程可视化,明确执行的阶段,可以快速的定位问题。并且整个项目的生命周期可以通过一个Jenkinsfile文件管理,而且Jenkinsfile文件是可以放在项目中维护。
所以Pipeline相对自由风格或者其他的项目风格更容易操作。
2.2 Jenkins流水线任务
2.2.1 构建Jenkins流水线任务
-
构建任务
构建Jenkins流水线任务 
-
生成Groovy脚本
Hello World脚本生成 
-
构建后查看视图
构建后查看视图 
2.2.2 Groovy脚本
-
Groovy脚本基础语法
// 所有脚本命令包含在pipeline{}中 pipeline { // 指定任务在哪个节点执行(Jenkins支持分布式) agent any // 配置全局环境,指定变量名=变量值信息 environment{ host = '192.168.11.11' } // 存放所有任务的合集 stages { // 单个任务 stage('任务1') { // 实现任务的具体流程 steps { echo 'do something' } } // 单个任务 stage('任务2') { // 实现任务的具体流程 steps { echo 'do something' } } // …… } } -
编写例子测试
pipeline { agent any // 存放所有任务的合集 stages { stage('拉取Git代码') { steps { echo '拉取Git代码' } } stage('检测代码质量') { steps { echo '检测代码质量' } } stage('构建代码') { steps { echo '构建代码' } } stage('制作自定义镜像并发布Harbor') { steps { echo '制作自定义镜像并发布Harbor' } } stage('基于Harbor部署工程') { steps { echo '基于Harbor部署工程' } } } }配置Grovvy脚本 
-
查看效果
查看效果 
|
Ps:涉及到特定脚本,Jenkins给予了充足的提示,可以自动生成命令
| 生成命令位置 |
|---|
![]() |
2.2.3 Jenkinsfile实现
Jenkinsfile方式需要将脚本内容编写到项目中的Jenkinsfile文件中,每次构建会自动拉取项目并且获取项目中Jenkinsfile文件对项目进行构建
-
配置pipeline
配置pipeline 
|
-
准备Jenkinsfile
准备Jenkinsfile文件 
|
-
测试效果
测试效果 
2.3 Jenkins流水线任务实现
2.3.1 参数化构建
添加参数化构建,方便选择不的项目版本
| Git参数化构建 |
|---|
![]() |
2.3.2 拉取Git代码
通过流水线语法生成Checkout代码的脚本
| 语法生成 |
|---|
![]() |
![]() |
将*/master更改为标签${tag}
pipeline {
agent any
stages {
stage('拉取Git代码') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]])
}
}
}
}
2.3.3 构建代码
通过脚本执行mvn的构建命令
pipeline {
agent any
stages {
stage('拉取Git代码') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]])
}
}
stage('构建代码') {
steps {
sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
}
}
}
2.3.4 代码质量检测
通过脚本执行sonar-scanner命令即可
pipeline {
agent any
stages {
stage('拉取Git代码') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]])
}
}
stage('构建代码') {
steps {
sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
}
}
stage('检测代码质量') {
steps {
sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=31388be45653876c1f51ec02f0d478e2d9d0e1fa'
}
}
}
}
2.3.5 制作自定义镜像并发布
-
生成自定义镜像脚本
pipeline { agent any environment{ harborHost = '192.168.11.11:80' harborRepo = 'repository' harborUser = 'DevOps' harborPasswd = 'P@ssw0rd' } // 存放所有任务的合集 stages { stage('拉取Git代码') { steps { checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]]) } } stage('构建代码') { steps { sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests' } } stage('检测代码质量') { steps { sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=31388be45653876c1f51ec02f0d478e2d9d0e1fa' } } stage('制作自定义镜像并发布Harbor') { steps { sh '''cp ./target/*.jar ./docker/ cd ./docker docker build -t ${JOB_NAME}:${tag} ./''' sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost} docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag} docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}''' } } } } -
生成Publish Over SSH脚本
pipeline { agent any environment{ harborHost = '192.168.11.11:80' harborRepo = 'repository' harborUser = 'DevOps' harborPasswd = 'P@ssw0rd' } // 存放所有任务的合集 stages { stage('拉取Git代码') { steps { checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/test.git']]]) } } stage('构建代码') { steps { sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests' } }docker stage('检测代码质量') { steps { sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=7d66af4b39cfe4f52ac0a915d4c9d5c513207098' } } stage('制作自定义镜像并发布Harbor') { steps { sh '''cp ./target/*.jar ./docker/ cd ./docker docker build -t ${JOB_NAME}:${tag} ./''' sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost} docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag} docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}''' } } stage('目标服务器拉取镜像并运行') { steps { sshPublisher(publishers: [sshPublisherDesc(configName: 'testEnvironment', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/usr/bin/deploy.sh $harborHost $harborRepo $JOB_NAME $tag $port ", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)]) } } } }
Ps:由于采用变量,记得使用双引号
2.4 Jenkins流水线整合钉钉
在程序部署成功后,可以通过钉钉的机器人及时向群众发送部署的最终结果通知
-
安装插件
安装插件 
|
-
钉钉内部创建群组并构建机器人
钉钉内部创建群组并构建机器人 


最终或获取到Webhook信息
https://oapi.dingtalk.com/robot/send?access_token=kej4ehkj34gjhg34jh5bh5jb34hj53b4
-
系统配置添加钉钉通知
配置钉钉通知 
|
-
任务中追加流水线配置
pipeline { agent any environment { sonarLogin = '2bab7bf7d5af25e2c2ca2f178af2c3c55c64d5d8' harborUser = 'admin' harborPassword = 'Harbor12345' harborHost = '192.168.11.12:8888' harborRepo = 'repository' } stages { stage('拉取Git代码'){ steps { checkout([$class: 'GitSCM', branches: [[name: '$tag']], extensions: [], userRemoteConfigs: [[url: 'http://49.233.115.171:8929/root/lsx.git']]]) } } stage('Maven构建代码'){ steps { sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests' } } stage('SonarQube检测代码'){ steps { sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=${sonarLogin}' } } stage('制作自定义镜像'){ steps { sh '''cd docker mv ../target/*.jar ./ docker build -t ${JOB_NAME}:$tag . ''' } } stage('推送自定义镜像'){ steps { sh '''docker login -u ${harborUser} -p ${harborPassword} ${harborHost} docker tag ${JOB_NAME}:$tag ${harborHost}/${harborRepo}/${JOB_NAME}:$tag docker push ${harborHost}/${harborRepo}/${JOB_NAME}:$tag''' } } stage('通知目标服务器'){ steps { sshPublisher(publishers: [sshPublisherDesc(configName: 'centos-docker', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/usr/bin/deploy.sh $harborHost $harborRepo $JOB_NAME $tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)]) } } } post { success { dingtalk ( robot: 'Jenkins-DingDing', type:'MARKDOWN', title: "success: ${JOB_NAME}", text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"] ) } failure { dingtalk ( robot: 'Jenkins-DingDing', type:'MARKDOWN', title: "fail: ${JOB_NAME}", text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"] ) } } } -
查看效果
钉钉通知效果 
更多推荐







所有评论(0)