1.DevOps和Jenkins
1.1.DevOps
1.1.1.原始软件开发模式
软件开发最开始是由两个团队组成:
- 开发计划由开发团队从头开始设计和整体系统的构建。需要系统不停的迭代更新。
- 运维团队将开发团队的Code进行测试后部署上线。希望系统稳定安全运行。
这看似两个目标不同的团队需要协同完成一个软件的开发。在开发团队指定好计划并完成coding后,需要提供到运维团队。运维团队向开发团队反馈需要修复的BUG以及一些需要返工的任务。这时开发团队需要经常等待运维团队的反馈。这无疑延长了事件并推迟了整个软件开发的周期。会有一种方式,在开发团队等待的时候,让开发团队转移到下一个项目中。等待运维团队为之前的代码提供反馈。
可是这样就意味着一个完整的项目需要一个更长的周期才可以开发出最终代码。
1.1.2.DevOps开发模式
基于现在的互联网现状,更推崇敏捷式开发,这样就导致项目的迭代速度更快,但是由于开发团队与运维团队的沟通问题,会导致新版本上线的时间成本很高。这又违背的敏捷式开发的最初的目的。
那么如果让开发团队和运维团队整合到成一个团队,协同应对一套软件呢?这就被称为DevOps。DevOps,字面意思是Development &Operations的缩写,也就是开发&运维。
虽然字面意思只涉及到了开发团队和运维团队,其实QA测试团队也是参与其中的。
这表明DevOps是一个不断提高效率并且持续不断工作的过程。DevOps的方式可以让公司能够更快地应对更新和市场发展变化,开发可以快速交付,部署也更加稳定。
核心就在于简化Dev和Ops团队之间的流程,使整体软件开发过程更快速。
整体的软件开发流程包括:
- PLAN:开发团队根据客户的目标制定开发计划
- CODE:根据PLAN开始编码过程,需要将不同版本的代码存储在一个库中。
- BUILD:编码完成后,需要将代码构建并且运行。
- TEST:成功构建项目后,需要测试代码是否存在BUG或错误。
- DEPLOY:代码经过手动测试和自动化测试后,认定代码已经准备好部署并且交给运维团队。
- OPERATE:运维团队将代码部署到生产环境中。
- MONITOR:项目部署上线后,需要持续的监控产品。
- INTEGRATE:然后将监控阶段收到的反馈发送回PLAN阶段,整体反复的流程就是DevOps的核心,即持续集成、持续部署。
为了保证整体流程可以高效的完成,各个阶段都有比较常见的工具,如下图:
软件开发过程&涉及工具 |
---|
最终可以给DevOps下一个定义:DevOps 强调的是高效组织团队之间如何通过自动化的工具协作和沟通来完成软件的生命周期管理,从而更快、更频繁地交付更稳定的软件。
自动化的工具协作和沟通来完成软件的生命周期管理
持续集成、持续部署的工具很多,其中Jenkins是一个开源的持续集成平台。
Jenkins涉及到将编写完毕的代码发布到测试环境和生产环境的任务,并且还涉及到了构建项目等任务。
Jenkins需要大量的插件保证工作,安装成本较高,下面会基于Docker搭建Jenkins。
1.2.Jenkins
持续集成、持续部署的工具很多,其中Jenkins是一个开源的持续集成平台。Jenkins涉及到将编写完毕的代码发布到测试环境和生产环境的任务,并且还涉及到了构建项目等任务。
Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具。Jenkins应用广泛,大多数互联网公司都采用Jenkins配合GitLab、Docker、K8s作为实现DevOps的核心工具。
Jenkins最强大的就在于插件,Jenkins官方提供了大量的插件库,来自动化CI/CD过程中的各种琐碎功能。
Jenkins最主要的工作就是将GitLab上可以构建的工程代码拉取并且进行构建,再根据流程可以选择发布到测试环境或是生产环境。
一般是GitLab上的代码经过大量的测试后,确定发行版本,再发布到生产环境。
CI/CD可以理解为:
-
CI过程即是通过Jenkins将代码拉取、构建、制作镜像交给测试人员测试。
-
持续集成(Continuous Integration):持续集成是指开发团队将代码频繁地合并到共享的代码仓库中,并通过自动化的构建和测试流程来验证代码的质量。每当有代码变更时,CI 系统会自动触发构建、运行单元测试和集成测试,以确保新代码与现有代码的兼容性。
让软件代码可以持续的集成到主干上,并自动构建和测试。
-
-
CD过程即是通过Jenkins将打好标签的发行版本代码拉取、构建、制作镜像交给运维人员部署。
-
持续交付(Continuous Delivery):持续交付是在持续集成的基础上,将可部署的软件交付到预生产环境中,以供进一步的测试和验证。在持续交付中,构建的软件包和资产会经过自动化的构建、测试和部署流程,以便随时可以进行交付和部署。
让经过持续集成的代码可以进行手动部署。
-
持续部署(Continuous Deployment):持续部署是在持续交付的基础上,将软件自动部署到生产环境中。在持续部署中,经过测试和验证的软件会自动发布到生产环境,实现快速且可靠的软件交付。
让可以持续交付的代码随时随地的自动化部署。
-
CI、CD |
---|
目前最主流的软件开发流程需要各个的模块:
- GitLab
- Jenkins-Server(Maven,JDK)
- TestServer JDK
2.环境准备
2.1.安装Git
开发环境Git安装,略。
2.2.安装GitLab
2.2.1.GitLab介绍及安装准备
官方网站:https://about.gitlab.com/
安装所需最小配置:内存至少4G
https://docs.gitlab.cn/jh/install/requirements.html
2.2.2.SSH安装GitLab
官方安装文档:https://gitlab.cn/install/?version=ce
2.2.2.1.安装依赖
sudo yum install -y curl policycoreutils-python openssh-server perl
sudo systemctl enable sshd
sudo systemctl start sshd
2.2.2.2.配置镜像
curl -fsSL https://packages.gitlab.cn/repository/raw/scripts/setup.sh | /bin/bash
2.2.2.3.开始安装
sudo EXTERNAL_URL="http://192.168.234.105" yum install -y gitlab-jh
除非您在安装过程中指定了自定义密码,否则将随机生成一个密码并存储在 /etc/gitlab/initial_root_password
文件中(出于安全原因,24 小时后,此文件会被第一次 gitlab-ctl reconfigure
自动删除,因此若使用随机密码登录,建议安装成功初始登录成功之后,立即修改初始密码)。使用此密码和用户名 root
登录。
2.2.3.Docker安装GitLab
2.2.3.1.添加容器
docker run --detach \
--hostname 192.168.234.106 \
--publish 443:443 --publish 80:80 \
--name gitlab \
--restart always \
--volume $GITLAB_HOME/config:/etc/gitlab:Z \
--volume $GITLAB_HOME/logs:/var/log/gitlab:Z \
--volume $GITLAB_HOME/data:/var/opt/gitlab:Z \
--shm-size 256m \
registry.gitlab.cn/omnibus/gitlab-jh:latest
2.2.3.2.查看镜像
docker images
2.2.3.3.启动容器
docker start gitlab
2.2.3.4.查看运行的容器
docker ps -a
2.2.3.5.访问
访问前可检查是否需要求改访问端口
sudo firewall-cmd --add-port=80/tcp --permanent
sudo firewall-cmd --reload
稍微等待访问:http://192.168.234.106
当首次运行出现502错误的时候排查两个原因
- 虚拟机内存至少需要4g
- 稍微再等等刷新一下可能就好了
2.2.3.6.进入容器内部查看密码
用户名:root
密码存在下面文件中,登录后需要改密码不然24小时之后会失效
docker exec -it gitlab /bin/bash
cat /etc/gitlab/initial_root_password #gxLCRamj8bAsKwASVvPdFjZUqhQ/UImimPuv1SCFHYs=
2.2.4.GitLab使用
新建项目
git config --global user.name "Administrator"
git config --global user.email "admin@example.com"
cd existing_folder
git init --initial-branch=main
git remote add origin http://192.168.234.106/root/jenkinstest.git
git add --all
git commit -m "Initial commit"
git push --set-upstream origin main
git config --global credential.helper store #命令的作用是将 Git 的凭据存储方式设置为 "store",以便在进行 Git 操作时记住凭据(例如用户名和密码)。
2.4.安装docker和Docker-compose
在将要安装Jenkins的Linux上安装docker和Docker-compose
2.4.1.安装docker
采用docker容器方式安装Jenkins,因此需要先在Linux上安装docker,过程略。
2.4.2.安装Docker-compose
Docker-compose下载在/usr/local/bin目录下,将软件放在 /usr/local/bin
目录下是为了让它在系统的任何位置都可以运行。
curl -SL https://github.com/docker/compose/releases/download/v2.19.1/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version
2.5.安装Jenkins
2.5.1.为Jenkins准备maven和JDK资源
-
在Docker宿主机创建/usr/local/docker/jenkins_docker,并进入
cd /usr/local/docker/jenkins_docker
-
创建data目录,该目录会和jenkins容器的/var/jenkins_home映射
chmod -R a+w data/
即:
#docker宿主机 jenkins容器 /usr/local/docker/jenkins_docker/data:/var/jenkins_home
-
将maven和jdk的目录拷贝到/usr/local/docker/jenkins_docker/data,并解压
**在将要安装Jenkins的Linux上**安装maven和JDK,用于Jenkins的项目构建;进行如下配置,删除原有压缩包,并在完成后续安装jenkins容器
<!-- 阿里云镜像地址 --> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> <!-- JDK1.8编译插件 --> <profile> <id>jdk8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile>
2.5.2.安装jenkins
-
拉取jenkins镜像
docker pull jenkins/jenkins
-
执行运行镜像命令
docker run -u root --rm -d -p 8080:8080 -p 50000:50000 -v /usr/local/docker/jenkins_docker/data:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock jenkins/jenkins
-
在docker宿主机创建/usr/local/docker/jenkins_docker/data目录,并设置data目录写权限。
-
Jenkins容器创建成功后会在容器内部创建/var/jenkins_home目录,为Jenkinsh后续运行的home目录,运行过程中所产生的所有的插件以及项目都会保存在这里。
-
宿主机的/usr/local/docker/jenkins_docker/data目录和enkins容器内部的/var/jenkins_home目录相互映射。
-
最终效果:
-
-
获取jenkins的初始登录密码
查看启动日志
docker logs -f 67c02ff3dc58
-
如果无法访问可以设置开放端口
sudo firewall-cmd --add-port=8080/tcp --permanent sudo firewall-cmd --reload
-
设置国内镜像源
重新启动Jenkins容器后,由于Jenkins需要下载大量内容,但是由于默认下载地址下载速度较慢,需要重新设置下载地址为国内镜像站
# 修改数据卷中的hudson.model.UpdateCenter.xml文件 <?xml version='1.1' encoding='UTF-8'?> <sites> <site> <id>default</id> <url>https://updates.jenkins.io/update-center.json</url> </site> </sites> # 将下载地址替换为http://mirror.esuni.jp/jenkins/updates/update-center.json <?xml version='1.1' encoding='UTF-8'?> <sites> <site> <id>default</id> <url>http://mirror.esuni.jp/jenkins/updates/update-center.json</url> </site> </sites>
-
访问jenkins的首页
http://192.168.234.101:8080/login?from=%2F
下载默认推荐的文件
-
创建用户
2.6.配置Jenkins
2.6.1.配置maven
将修改好settings.xml的maven目录和JDK复制到docker宿主机的/usr/local/docker/jenkins_docker/data目录下。
根据创建Jenkins镜像时的映射规则会映射到jenkins_docker容器内部的/var/jenkins_home目录。
在宿主机内部查看:
在Jenkins容器内部查看
2.6.2.设置JDK
docker宿主机的/usr/local/docker/jenkins_docker/data目录,根据创建Jenkins镜像时的映射规则会映射到jenkins_docker容器内部的/var/jenkins_home目录。
3.CI/CD入门操作
3.1.CI基础操作
3.1.1.创建Spring Boot项目
3.1.2.确保开发环境下的代码没有问题
http://localhost:8080/test
3.1.3.在Gitlab创建一个项目
3.1.4.把本地测试正常的代码提交到Gitlib
3.1.5.在Jenkins创建任务
-
创建测试任务
-
设置gitlab地址,源码账户,密码,代码分支
尤其注意分支
设置密码
-
创建成功
3.1.6.在Jenkins中完成构建
查看构建生产的日志
3.1.7.进入Jenkins容器内部查看构建的文件
-
进入Jenkins容器内部查看查看/var/jenkins_home,在workspace保存构建的代码
-
进入workspace查看
3.1.8.调用顶层maven构建
3.1.8.1.maven构建的设置
3.1.8.2.使用maven完成项目构建
再次构建,打印的日志如下:
3.1.8.3.构建成功
下载需要的jar包,构建成功
3.1.8.4.查看生成的文件
-
在Jenkins容器的/var/jenkins_home/workspace/jenkinstest/target目录下
-
在docker宿主机的/usr/local/docker/jenkins_docker/data/workspace/jenkinstest目录下
此时target目录并没有生成*.jar包,maven中没有进行打包命令的设置。
3.2.持续集成
3.2.1.修改java项目配置
3.2.1.1.配置dockerfile
FROM adoptopenjdk/openjdk8
COPY myjenkinstest.jar /usr/local/
WORKDIR /usr/local/
CMD java -jar myjenkinstest.jar
3.2.1.2.配置docker-compose.yaml
version: "3.1"
services:
myjenkinstest:
build:
context: ./
dockerfile: Dockerfile
container_name: myJenkinsTest
image: myjenkinstest
ports:
- "8080:8080"
3.2.1.3.配置pom.xml
<build>
<!-- 最终打包后的jar名称-->
<finalName>myjenkinstest</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.stonebridge.jenkinstest.JenkinstestApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
修改后代码提交
3.2.2.配置Publish发布&远程操作
3.2.2.1.安装publish Over SSH
3.2.2.2.配置测试服务器的地址
-
确保在测试服务器安装好docker以及docker-compose
-
在测试服务器安装测试文件存放目录
示例目录为:/usr/local/jenkins_test_dir
-
配置位置
-
配置SSH Server
高级设置中的Jump host必须为空
3.2.3.配置maven构建完成打包
前面的maven配置只是完成maven的对项目的构建,没有打包操作,需要进行配置。
clean package -DskipTests
3.2.4.配置Send build artifacts over SSH
cd /usr/local/jenkins_test_dir/docker #必须是绝对路径
mv ../target/*.jar ./
docker-compose down
docker-compose up -d --build
3.2.5.项目构建
3.2.6.测试服务器查看
-
查看测试服务器的保存测试文件的目录
测试检查测试服务器的/usr/local/jenkins_test_dir目录,发现了target目录,里面有打包好的jar包。
-
查看docker中部署容器的运行情况
-
查看docker的镜像
每构建一次就会产生一次虚悬镜像
解决方式
docker image prune -f
在jenkins的Send build artifacts over SSH增加配置
cd /usr/local/jenkins_test_dir/docker mv ../target/*.jar ./ docker-compose down docker-compose up -d --build docker image prune -f
3.2.7.访问测试环境下的项目
访问:测试服务器地址:port/path
http://47.251.1.32:8080/test
3.3.基于参数构建
通过Git Parameter插件设置tag参数(其他参数也可以),在构建项目时,基于tag的不同拉取不同的分支代码实现项目构建。
3.3.1.安装Git Parameter插件
3.3.2.追加基于参数构建的方式
给构建任务追加基于参数构建的方式
在maven进行build之前从git拉取参数位置进行设置
3.3.3.在gitlab项目增加tag
-
对存在的代码新增一个tag,命名为v1.0.0.。
-
对项目代码进行修改,并提交
此时最新代码是v2.0.0已经提交,在v2.0.0上新增tag v2.0.0
-
构建v.1.0.0
-
选择v.1.0.0
-
根据tag拉取v1.0.0的代码
-
测试结果
-
-
构建v.2.0.0
-
选择v.2.0.0
-
根据tag拉取v2.0.0的代码
-
测试结果
-
4.集成Sonar Qube
4.1.Sonar Qube介绍
Sonar Qube是一个开源的代码分析平台,支持Java、Python、PHP、JavaScript、CSS等25种以上的语言,可以检测出重复代码、代码漏洞、代码规范和安全性漏洞的问题。
Sonar Qube可以与多种软件整合进行代码扫描,比如Maven,Gradle,Git,Jenkins等,并且会将代码检测结果推送回Sonar Qube并且在系统提供的UI界面上显示出来。
Sonar Qube的UI界面
4.2.Sonar Qube环境搭建
Sonar Qube在7.9版本中已经放弃了对MySQL的支持,并且建议在商业环境中采用PostgreSQL,那么安装Sonar Qube时需要依赖PostgreSQL。
4.2.1.拉取镜像
docker pull sonarqube:10.1.0-community
docker pull postgres
4.2.2.docker-compoe.yaml
version: "3.1"
services:
db:
image: postgres
container_name: db
ports:
- 5432:5432
networks:
- sonarnet
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar
sonarqube:
image: sonarqube:10.1.0-community
container_name: sonarqube
depends_on:
- db
ports:
- "9000:9000"
networks:
- sonarnet
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
networks:
sonarnet:
driver: bridge
运行:docker-compose up -d
注意事项:如果启动失败,且提示:bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
解决方式:设置sysctl.conf文件信息
-
设置vm.max_map_count
-
并执行命令刷新
sysctl -p
-
重新启动
重新启动需要一定时间启动,可以可以查看容器日志,看到如下内容代表启动成功
4.2.3.访问首页
4.2.4.Sonar Qube首页
4.2.5.安装中文插件
安装成功后需要重启,安装失败重新点击install重装即可。
安装成功后,会查看到重启按钮,点击即可
中文效果:
4.3.Sonar Qube基本使用
Sonar Qube的使用方式很多,Maven可以整合,也可以采用sonar-scanner的方式,再查看Sonar Qube的检测效果
4.3.1.Maven实现代码检测
-
修改Maven的settings.xml文件配置Sonar Qube信息
<profile> <id>sonar</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <sonar.login>admin</sonar.login> <sonar.password>123456789</sonar.password> <sonar.host.url>http://192.168.11.11:9000</sonar.host.url> </properties> </profile>
-
在代码位置执行命令:mvn sonar:sonar
-
查看Sonar Qube界面检测结果
4.3.2.Sonar-scanner实现代码检测
4.3.2.1.下载Sonar-scanner
https://binaries.sonarsource.com/?prefix=Distribution/sonar-scanner-cli/
下载4.7.x版本即可,要求Linux版本
4.3.2.2.解压并配置sonar服务端信息
-
由于是zip压缩包,需要安装unzip解压插件
yum -y install unzip
-
解压压缩包
unzip sonar-scanner-cli-4.7.0.2747-linux.zip
即将解压后的sonar-scanner移动的Jenkins的映射数据卷中
-
配置SonarQube服务端地址,修改conf下的sonar-scanner.properties
配置
4.3.2.3.使用Sonar-scanner进行检测
-
执行命令检测代码
进入项目的目录后执行
/usr/local/docker/jenkins_docker/data/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=linux-jenkinstest -Dsonar.login=sqa_b6ec85cdb651189861f23ac0bd2a2d20f192e34c -Dsonar.projectKey=linux-jenkinstest -Dsonar.java.binaries=target/
参数说明:
/usr/local/docker/jenkins_docker/data/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=linux-jenkinstest -Dsonar.login=sqa_b6ec85cdb651189861f23ac0bd2a2d20f192e34c -Dsonar.projectKey=linux-jenkinstest -Dsonar.java.binaries=target/
-
在项目所在目录执行检测命令
-
找到sonar-scanner客户端目录下bin目录下的sonar-scanner的绝对地址
-
通过-Dsonar.sources设置检测代码位置
在项目所在目录执行检测命令,即当前目录下。
-Dsonar.sources=./
-
通过-Dsonar.projectname指定现在检测项目名称,可以随意改
-Dsonar.projectname=linux-jenkinstest
-
在SonarQube服务端生成一个token,用于检测,通过-Dsonar.login指定
通过-Dsonar.login设置
-Dsonar.login=sqa_b6ec85cdb651189861f23ac0bd2a2d20f192e34c
-
通过-Dsonar.projectKey执行projectKey
-Dsonar.projectKey
-
通过-Dsonar.java.binaries设置编译后的代码
-Dsonar.java.binaries=target/
-
-
检测结束,在服务端查看
4.4.Jenkins集成Sonar Qube
Jenkins继承Sonar Qube实现代码扫描需要先下载整合插件
4.4.1.Jenkins安装插件
安装成功:
4.4.2.Jenkins配置Sonar Qube
4.4.2.1.开启Sonar Qube权限验证
4.4.2.2.在jenkins进行全局配置Sonar Qube
4.4.2.3.在构建任务中配置Sonar-scanner
在maven构建项目成功后增加Sonar-scanner的操作
4.4.2.4.构建任务成功
5.集成Harbor
5.1.Harbor介绍
前面在部署项目时,我们主要采用Jenkins推送jar包到指定服务器,再通过脚本命令让目标服务器对当前jar进行部署,这种方式在项目较多时,每个目标服务器都需要将jar包制作成自定义镜像再通过docker进行启动,重复操作比较多,会降低项目部署时间。
我们可以通过Harbor作为私有的Docker镜像仓库。让Jenkins统一将项目打包并制作成Docker镜像发布到Harbor仓库中,只需要通知目标服务,让目标服务统一去Harbor仓库上拉取镜像并在本地部署即可。
Docker官方提供了Registry镜像仓库,但是Registry的功能相对简陋。Harbor是VMware公司提供的一款镜像仓库,提供了权限控制、分布式发布、强大的安全扫描与审查机制等功能
5.2.Harbor安装
采用原生的方式安装Harbor
5.2.1.下载Harbor安装包
下载地址:https://github.com/goharbor/harbor/releases
5.2.2.解压到/usr/local目录
tar -zxvf harbor-2.8.2.tar.gz
5.2.3.修改Harbor配置文件
-
首先复制一份harbor.yml配置
cp harbor.yml.tmpl harbor.yml
-
编辑harbor.yml配置文件
5.2.4.启动Harbor
./install.sh
5.2.5.登录Harbor
访问:ip:8090
http://47.251.53.131:8090
5.2.6.首页信息
5.3.Harbor使用方式
Harbor作为镜像仓库,主要的交互方式就是将镜像上传到Harbor上,以及从Harbor上下载指定镜像
在传输镜像前,可以先使用Harbor提供的权限管理,将项目设置为私有项目,并对不同用户设置不同角色,从而更方便管理镜像。
5.3.1 创建项目/仓库
-
创建用户
-
构建项目(设置为私有)
-
给项目追加用户
-
切换测试用户
5.3.2.发布镜像到Harbor
-
修改镜像名称
名称要求:harbor地址/项目名/镜像名:版本
-
修改docker宿主机上的/etc/docker/daemon.json文件,支持Docker仓库,并重启Docker
vim /etc/docker/daemon.json
{ "insecure-registries":["47.251.53.131:8090"] }
重启Docker
systemctl restart docker
-
为镜像添加标签(tag)
docker tag 44dda7c586e8 47.251.53.131:8090/repo/myjenkinstest:v2.8.0
-
设置登录仓库信息
docker login -u 用户名 -p 密码 Harbor地址
或者
docker login -u 用户名 Harbor地址
docker login -u admin 47.251.53.131:8090
-
推送镜像到Harbor
docker push 镜像名:版本
此处镜像名由:harbor地址/项目名/镜像名组成
docker push 47.251.53.131:8090/repo/myjenkinstest:v2.8.0
-
推送成功
5.3.3.指定的目标服务从Harbor拉取镜像
-
设置/etc/docker/daemon.json
-
docker登录
-
拉取
docker pull 47.251.53.131:8090/repo/myjenkinstest:v2.8.0
5.4.Jenkins容器使用宿主机Docker
让Jenkins在其容器内部去制作自定义镜像,然后将其推送到Harbor,并通知测试服务器拉取镜像进行测试。
因此要求Jenkins容器内部必须拥有docker可执行文件的权限。
- 实现方式1:Jenkins容器内部安装docker(不推荐)
- 实现方式2:Jenkins容器使用其宿主机的docker(推荐)
构建镜像和发布镜像到harbor都需要使用到docker命令。而在Jenkins容器内部安装Docker不推荐,官方推荐直接采用宿主机带的Docker即可。
设置Jenkins容器使用宿主机Docker
5.4.1.设置docker宿主机上的docker.sock权限
docker.sock是docker的核心文件,默认文件的拥有者是root用户,所属组是docker。将其改为root用户下的root组下的一个文件,并且要让其他组的成员有读和写的权限。当这个文件有这样的权限后,再去修改数据卷,就可以让docker容器内部拥有这个文件,以及docker可执行文件,最后拥有daemon.json。就可以在jenkins内部执行docker命令,制作容器,并将其推送至Harbor私有仓库中。
sudo chown root:root /var/run/docker.sock
sudo chmod o+rw /var/run/docker.sock
5.4.2.修改docker宿主机上/etc/docker/daemon.json文件
vim /etc/docker/daemon.json
{
"insecure-registries":["47.251.53.131:8090"]
}
5.4.3.修改docker添加数据卷
-
通过docker-compose.yaml文件
version: "3.1" services: jenkins: image: jenkins/jenkins container_name: jenkins ports: - 8080:8080 - 50000:50000 volumes: - /usr/local/docker/jenkins_docker/data:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock - /usr/bin/docker:/usr/bin/docker - /etc/docker/daemon.json:/etc/docker/daemon.json user: root restart: unless-stopped
将其转化为docker命令
docker run -u root --rm -d -p 8080:8080 -p 50000:50000 -v /usr/local/docker/jenkins_docker/data:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v /etc/docker/daemon.json:/etc/docker/daemon.json jenkins/jenkins
-
通过docker命令
docker run -v /host/path:/container/path -d image_name
docker run -v /var/run/docker.sock:/var/run/docker.sock -v /etc/docker/daemon.json:/etc/docker/daemon.json -v /usr/bin/docker:/usr/bin/docker -d jenkins/jenkins
执行后检查是否成功
-
查看挂载
docker inspect CONTAINER_ID
-
进入容器内部执行docker命令
5.5.配置Jenkins整合Harbor
让Jenkins制作自定义镜像,并推送到Harbor。修改Jenkins的构建任务。
原先是Jenkins把jar包推送到目标服务器,然后让目标服务器执行docker-compose制作自定义镜像。
现在是让Jenkin自定义镜像,并推送到Harbor上。制作自定义镜像只需Dockerfile ,不需要docker-compose.yaml,因此来自java项目docker-compose.yaml可以删除。
5.5.1.提交代码,并新增tag
5.5.2.Dockerfile不变
FROM adoptopenjdk/openjdk8
COPY myjenkinstest.jar /usr/local/
WORKDIR /usr/local/
CMD java -jar myjenkinstest.jar
5.5.3.构建镜像后将其推送到Harbor
使用maven构建项目后,Jenkins容器调用其宿主机上的docker构建镜像,并将其推送到Harbor。
mv target/*.jar docker/ # 将target里的jar移动到docker目录
docker build -t ${JOB_NAME}:$tag docker/ # 构建镜像
docker login -u admin -p Harbor12345 47.251.53.131:8090 # 登录Harbor
docker tag ${JOB_NAME}:$tag 47.251.53.131:8090/repo/${JOB_NAME}:$tag # 制作可以推送到Harbor的镜像
docker push 47.251.53.131:8090/repo/${JOB_NAME}:$tag # 推送到Harbor
5.5.4.测试
-
Jenkins容器构建成功
-
Jenkins将容器推送到Harbor
此时Jenkins还没有通知测试服务器从Harbor拉取镜像来执行。
5.6.Jenkins通知测试服务器从Harbor拉取镜像来执行
部署项目需要通过Publish Over SSH插件,让目标服务器执行命令。为了方便一次性实现拉取镜像和启动的命令,推荐采用脚本文件的方式。
添加脚本文件到目标服务器,再通过Publish Over SSH插件让目标服务器执行脚本即可。
在测试服务器准备一个脚本文件,Jenkins通过Publish Over SSH插件传递参数,并执行脚本文件。
脚本文件的功能:
- 告知测试服务器从Harbor拉取哪个镜像
- 判断测试服务器是否正在运行容器,如果有,停止容器运行,并删除容器
- 如果测试服务器已经存在当前镜像,需要删除
- 测试服务器拉取harbor上的镜像
- 将拉取下来的镜像运行成容器
Jenkins通过Publish Over SSH插件传递给测试服务器的参数
- harbor地址
- harbor仓库
- 镜像名
- 镜像版本
- 容器运行的端口号
- docker宿主机运行的端口号
5.6.1.bash脚本文件deloy.sh
# 1.接收参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
container_port=$5
host_port=$6
#2.拼接镜像名
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
#3.测试镜像名拼接
echo &imageName
#4.判断以项目名(project_name)命名的容器是否在运行,如果在运行,则停止运行,并删除该容器
containerId=`docker ps -a | grep ${project_name} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
docker stop $containerId
docker rm $containerId
echo "Delete Container Success"
fi
#5.判断以项目名(project_name)命名的镜像是否存在,如果存在,则删除该镜像
imageId=`docker images | grep ${project_name} | awk '{print $3}'`
if [ "$imageId" != "" ] ; then
docker rmi -f $imageId
echo "Delete Image Success"
fi
# 6.登录harbor
docker login -u admin -p Harbor12345 $harbor_url
# 7.拉取镜像
docker pull $imageName
# 8.运行容器
docker run -d -p $host_port:$container_port --name $project_name $imageName
echo "Start Container Success"
echo $project_name
5.6.2.设置脚本权限为可执行
chmod a+x deploy.sh
将其移动到$PATH下,在任意地方都可以执行了
mv deploy.sh /usr/bin
5.6.3.通过Publish Over SSH执行脚本,并传递参数
deploy.sh 47.251.53.131:8090 repo ${JOB_NAME} $tag $container_port $host_port
deploy.sh 47.251.53.131:8090 repo ${JOB_NAME} $tag 8080 9000
5.6.4.测试
5.6.4.1.Jenkins执行成功
5.6.4.2.Harbor镜像仓库接收到推送的镜像
5.6.4.3.测试服务器拉取到镜像并执行
5.6.4.4.访问服务
6.Jenkins流水线
6.1.Jenkins流水线任务介绍
之前采用Jenkins的自由风格构建的项目,每个步骤流程都要通过不同的方式设置,并且构建过程中整体流程是不可见的,无法确认每个流程花费的时间,并且问题不方便定位问题。
Jenkins的Pipeline可以让项目的发布整体流程可视化,明确执行的阶段,可以快速的定位问题。并且整个项目的生命周期可以通过一个Jenkinsfile文件管理,而且Jenkinsfile文件是可以放在项目中维护。
所以Pipeline相对自由风格或者其他的项目风格更容易操作。
6.2.Jenkins流水线任务
6.2.1.构建Jenkins流水线任务
-
构建任务
-
生成Groovy最简单脚本测试
-
构建后查看视图
6.2.2.Groovy脚本
-
Groovy脚本基础语法
// 所有脚本命令都放在在pipeline中 pipeline { // 指定任务在哪个Jenkins集群节点执行(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 '拉取代码----success' } } stage('通过Maven构建项目') { steps { echo '构建项目----success' } } stage('通过SonarQube检测代码') { steps { echo '检测代码----success' } } stage('通过Docker制作自定义镜像') { steps { echo '通过Docker制作自定义镜像----success' } } stage('将自定义镜像发布到Harbor') { steps { echo '将自定义镜像发布到Harbor----success' } } stage('通过Pushlish Over SSH通知测试服务器部署项目') { steps { echo '通过Pushlish Over SSH通知测试服务器部署项目----success' } } } }
-
将Groovy脚本部署到Jenkins的测试任务中
-
测试结果
6.2.3.Jenkins可以生成常用的操作的命令
涉及到特定脚本,Jenkins给予了充足的提示,可以自动生成命令
-
通过Pipeline Syntax生成
-
选择需要完成的功能
-
设置具体实现
-
生成Pipeline Script
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/stonebridgelin/myapp.git']])
stage('拉取Git仓库代码') { steps { checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/stonebridgelin/myapp.git']]) } }
6.3.Jenkinsfile实现配置
Jenkinsfile方式需要将脚本内容编写到项目中的Jenkinsfile文件中,每次构建会自动拉取项目并且获取项目中Jenkinsfile文件对项目进行构建。
6.3.1.准备Jenkinsfile
6.3.2.配置pipeline
Script Path和git项目的配置文件的路径和名称要匹配。
6.3.3.进行测试
6.4.Jenkins流水线任务实现
6.4.1.参数化构建
添加参数化构建,方便选择不的项目版本。
6.4.2.拉取Git代码
通过流水线语法生成Checkout代码的脚本
将*/main更改为标签${tag}
checkout scmGit(branches: [[name: 'main']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/stonebridgelin/jenkinstest.git']])
checkout scmGit(branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/stonebridgelin/jenkinstest.git']])
测试:
6.4.3.通过maven构建代码
通过脚本执行mvn的构建命令
stage('通过Maven构建项目') {
steps {
sh '/var/jenkins_home/apache-maven-3.6.3/bin/mvn clean package -DskipTests'
echo '构建项目----success'
}
}
测试:
6.4.4.通过SonarQube进行代码质量检测
通过脚本执行sonar-scanner命令即可
/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=sqa_b6ec85cdb651189861f23ac0bd2a2d20f192e34c'
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=sqa_b6ec85cdb651189861f23ac0bd2a2d20f192e34c\''
echo '构建项目----success'
}
}
6.4.5.制作自定义镜像并发布
生成自定义镜像脚本
stage('通过Docker制作自定义镜像') {
steps {
sh '''mv target/*.jar docker/
docker build -t ${JOB_NAME}:$tag docker/'''
echo '通过Docker制作自定义镜像----success'
}
}
测试:
Jenkins所在宿主机上的docker上新增镜像,但是尚未推送到Harbor
6.4.6.把Jenkins制作的镜像推送到harbor上
sh '''docker login -u harbor用户名 -p harbor密码 harbor地址
docker tag ${JOB_NAME}:${tag} harbor地址/harbor仓库/${JOB_NAME}:${tag}
docker push harbor地址/harbor仓库/${JOB_NAME}:${tag}'''
pipeline {
agent any
environment{
harborHost = '47.251.53.131:8090'
harborRepo = 'repo'
harborUser = 'admin'
harborPasswd = 'Harbor12345'
}
// 存放所有任务的合集
stages {
stage('通过Docker制作自定义镜像') {
steps {
echo '通过Docker制作自定义镜像----success'
}
}
stage('将自定义镜像发布到Harbor') {
steps {
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}'''
echo '${harborRepo}----success'
}
}
stage('通过Pushlish Over SSH通知测试服务器部署项目') {
steps {
echo '通过Pushlish Over SSH通知测试服务器部署项目----success'
}
}
}
}
6.4.7.通过Publish Over SSH通知测试服务器执行脚本执行
pipeline {
agent any
environment{
harborHost = '47.251.53.131:8090'
harborRepo = 'repo'
harborUser = 'admin'
harborPasswd = 'Harbor12345'
}
// 存放所有任务的合集
stages {
stage('通过Pushlish Over SSH通知测试服务器部署项目') {
steps {
sshPublisher(publishers: [sshPublisherDesc(configName: 'Jenkins_Test_On_Aliyun_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborHost $harborRepo $JOB_NAME $tag 8080 9000", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
echo '通过Pushlish Over SSH通知测试服务器部署项目----success'
}
}
}
}
由于采用变量,在execCommand使用双引号。
execCommand: "deploy.sh $harborHost $harborRepo $JOB_NAME $tag 8080 9000"
测试:
-
pipeline流程执行无报错
-
harbor中存在Jenkins推送的镜像
-
测试服务器的docker运行的项目容器
-
访问项目
6.4.8.完整的Jenkinsfile
pipeline {
agent any
environment {
harborHost = '47.251.53.131:8090'
harborRepo = 'repo'
harborUser = 'admin'
harborPasswd = 'Harbor12345'
}
// 存放所有任务的合集
stages {
stage('拉取Git仓库代码') {
steps {
checkout scmGit(branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/stonebridgelin/jenkinstest.git']])
echo '拉取代码----success'
}
}
stage('通过Maven构建项目') {
steps {
sh '/var/jenkins_home/apache-maven-3.6.3/bin/mvn clean package -DskipTests'
echo '构建项目----success'
}
}
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=sqa_b6ec85cdb651189861f23ac0bd2a2d20f192e34c\''
echo '构建项目----success'
}
}
stage('通过Docker制作自定义镜像') {
steps {
sh '''mv target/*.jar docker/
docker build -t ${JOB_NAME}:$tag docker/'''
echo '通过Docker制作自定义镜像----success'
}
}
stage('将自定义镜像发布到Harbor') {
steps {
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}'''
echo '${harborRepo}----success'
}
}
stage('通过Pushlish Over SSH通知测试服务器部署项目') {
steps {
sshPublisher(publishers: [sshPublisherDesc(configName: 'Jenkins_Test_On_Aliyun_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborHost $harborRepo $JOB_NAME $tag 8080 9000", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
echo '通过Pushlish Over SSH通知测试服务器部署项目----success'
}
}
}
}
6.5.Jenkins流水线整合邮件通知
-
开启邮箱的POP3/SMTP服务
过程略
-
下载插件
初始时,会默认下载。
-
设置
-
Jenkins Location
-
Extended E-mail Notification
自定义的邮箱设置
-
E-mail Notification
略
-
<font color='red'><strong> </strong></font>