收益
- 不用再通过命令行发布
- 发布环境稳定,可以重复执行
- 多节点同步构建,提高效率
准备
- linux服务器已安装jenkins、git、openjdk8和maven3.5+已就绪
- git服务
- 一个已经能够构建支持多CPU架构docker镜像的Dockerfile
- 一台已经安装docker环境的同jenkins宿主机不同架构的linux服务器
jenkins和git服务可参考树莓派4B基于docker搭建devops平台进行准备。
本实践环境中使用的jenkins就是参考树莓派4B基于docker搭建devops平台进行搭建的,参考文档中使用的jenkins镜像使用root用户启动jenkins,方便挂载宿主机的docker运行环境,无权限问题执行docker命令,该镜像同时支持树莓派和普通x86服务器; apiworld-codeg是一个快嘉脚手架项目,本实践我们选择的Dockerfile就是该项目提供的,基于该Dockerfile我们可以同时构建支持arm64和x86架构CPU的docker镜像。如您也准备好了一个已经能够构建支持多CPU架构docker镜像的Dockerfile,可以将它 push到搭建好的git服务器,如gogs;或者任何可选的代码托管平台,如github、gitee、codeup、coding等等。
本实践环境中的jenkins部署在一台树莓派4B上,另外的一台linux服务器是x86服务器,已经安装docker环境。具体信息如下
服务器名称 | 操作系统 | CPU架构 | IP | docker-version | docker-Experimental |
---|---|---|---|---|---|
jenkins宿主机 | centos7.9 | arm64 | 10.168.1.220 | 19.03.8 | true |
x86服务器 | centos7.7 | amd64 | 192.168.99.240 | 17.05.0-ce | false |
pipeline设计与实现
步骤
- 下载源码
- jenkins宿主机和x86服务器分别构建镜像、推送hub镜像
- jenkins宿主机创建manifest
- jenkins宿主机图送hub manifest
docker配置
开启实验属性 本实践中我们开启宿主机的docker实验属性,以便支持manifest。 docker实验属性需要同时开启server端和client端 我们先开启server端,宿主机新建文件/etc/docker/daemon.json,内容如下
{
"experimental": true,
"insecure-registries": ["10.168.1.220:8082","10.168.1.220:8083"],
"log-driver":"json-file",
"log-opts": { "max-size": "100m", "max-file": "5" },
"exec-opts": ["native.cgroupdriver=systemd"],
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
重启docker,jenkins也会自动重启
systemctl restart docker
再开启client端,这个本来需要在jenkins容器里执行,不过我们已经通过mount将/root目录直接挂载在宿主机的/opt/server/jenkins/data,所以我们可以直接在宿主机操作 宿主机新建文件/opt/server/jenkins/data/.docker/config.json,内容如下
{
"experimental": "enabled"
}
这时候再进入jenkins容器,发现docker的实验属性已经开启
[root@pi155 ~]# docker exec -it jenkins bash
bash-4.2# docker version
Client: Docker Engine - Community
Version: 19.03.8
API version: 1.40
Go version: go1.12.17
Git commit: afacb8b
Built: Wed Mar 11 01:27:06 2020
OS/Arch: linux/arm64
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 19.03.8
API version: 1.40 (minimum version 1.12)
Go version: go1.12.17
Git commit: afacb8b
Built: Wed Mar 11 01:25:44 2020
OS/Arch: linux/arm64
Experimental: true
containerd:
Version: 1.4.12
GitCommit: 7b11cfaabd73bb80907dd23182b9347b4245eb5d
runc:
Version: 1.0.2
GitCommit: v1.0.2-0-g52b36a2
docker-init:
Version: 0.18.0
GitCommit: fec3683
容器中保存docker登录凭证
[root@pi155 ~]# docker exec -it jenkins bash
bash-4.2# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: fastjrun
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
这样登录凭证就保存在容器中的/root/.docker/config.json,后续我们就可以直接使用jenkins推送docker镜像至hub了。
jenkins设置
jenkins容器内生成ssh-key,并ssh登录x86服务器
[root@pi155 .m2]# docker exec -it jenkins bash
bash-4.2# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:LMv7Hr/uqumnPDAOkgIeBlGekEPEyrMi7Ct+dG/F2NQ root@0cab68699043
The key's randomart image is:
+---[RSA 2048]----+
|**. |
|++ . |
|+.o . |
|o= . . E |
|=.+ . S |
|*+..oo + + |
|=..o.o+ o |
|.. ....=.o |
|ooo .OB++=. |
+----[SHA256]-----+
bash-4.2# ssh 192.168.99.240
The authenticity of host '192.168.99.240 (192.168.99.240)' can't be established.
ECDSA key fingerprint is SHA256:moZlvJwOjMx9Yybd1/0uebewfcHlA0b1zPYXp78H6rc.
ECDSA key fingerprint is MD5:3b:90:d4:c0:16:07:69:4f:e3:2b:95:6f:bc:c6:e6:d6.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.99.240' (ECDSA) to the list of known hosts.
root@192.168.99.240's password:
配置x86服务器为jenkins的一个agent,标签设置为amd64
jenkins控制台点"Manage Jenkins"
点“Manage nodes and clouds”
新建节点
输入节点名称,选中Permanent Agent后,点“Create”按钮,继续编辑该节点信息
这一页需要调整的有节点名字、Number of executors、远程工作目录、标签、用法和启动方式,其他采用默认值即可。节点名字随意;Number of executors默认值为1,可调整为2;远程工作目录要保证确实存在;标签至少设置一个iamd64,如果有多个,可以用空格分隔;用法有2个选项,这里我们选择“Only build jobs with label expressions matching this node”
启动方式有3个选项,这里我们选择"Launch agents via SSH"
启动方式选择"Launch agents via SSH"后,会显示主机输入框和用户凭证下拉选择框,我们输入IP和登录凭证后,点“保存”按钮。 返回“Manage nodes and clouds”页面,当jenkins检测到从节点后,显示如下
脚本
node {
stage('git chekout') {
git branch: "master", url: 'https://gitee.com/fastjrun/apiworld-codeg.git'
}
stage('package') {
sh 'sh build.sh package_mock_server'
}
stage('prepare docker') {
sh 'rm -rf output && mkdir output'
sh 'cp apiworld-mock-server/target/apiworld-mock-server.jar output'
dir( 'output' ) {
stash 'output'
}
}
stage('parallel docker build && push') {
parallel (
'docker build && push': {
sh 'cd output && docker build . -t pi4k8s/apiworld-mock-server-arm64:1.4'
sh 'docker push pi4k8s/apiworld-mock-server-arm64:1.4'
},
'docker build && push amd64': {
node('amd64') {
dir( 'output' ) {
unstash 'output'
}
sh 'cd output && docker build . -t pi4k8s/apiworld-mock-server-amd64:1.4'
sh 'docker push pi4k8s/apiworld-mock-server-amd64:1.4'
}
}
)
}
stage('manifest'){
try {
sh 'docker manifest rm pi4k8s/apiworld-mock-server:1.4'
}catch(exc){
echo "some thing wrong"
}
sh 'docker manifest create pi4k8s/apiworld-mock-server:1.4 pi4k8s/apiworld-mock-server-amd64:1.4 pi4k8s/apiworld-mock-server-arm64:1.4'
sh 'docker manifest annotate pi4k8s/apiworld-mock-server:1.4 pi4k8s/apiworld-mock-server-amd64:1.4 --os linux --arch amd64'
sh 'docker manifest annotate pi4k8s/apiworld-mock-server:1.4 pi4k8s/apiworld-mock-server-arm64:1.4 --os linux --arch arm64'
sh 'docker manifest push pi4k8s/apiworld-mock-server:1.4'
}
stage('cleanWs'){
parallel (
'arm64': {
cleanWs()
},
'amd64': {
node('amd64') {
cleanWs()
}
}
)
}
}
#!/bin/bash
echo "build ..."
if [ "install_all" = $1 ]; then
mvn compile -pl apiworld-api -am -Dapigc.skip=false
mvn compile -pl apiworld-bundle -am -Dbdgc.skip=false
mvn compile -pl apiworld-client -am -Dclientgc.skip=false
mvn clean install -U
elif [ "deploy_all" = $1 ]; then
mvn compile -pl apiworld-api -am -Dapigc.skip=false
mvn compile -pl apiworld-bundle -am -Dbdgc.skip=false
mvn compile -pl apiworld-client -am -Dclientgc.skip=false
mvn clean deploy -U
elif [ "package_mock_server" = $1 ]; then
mvn clean package -U -pl apiworld-mock-server -am -Dbdmgc.skip=false
elif [ "clean_all" = $1 ]; then
mvn clean
rm -rf *-api/src
rm -rf *-client/src
rm -rf *-bundle/src
rm -rf *-bundle-mock/src
fi
echo "build done."
pipeline执行
配置任务
jenkins控制台新建item
输入任务名称apiworld-mock-server-image,选择Pipeline后,点“确定”按钮,进入配置任务页面
选择Pipeline script from SCM后,显示SCM下拉选择框如下
选择Git后,显示Repository标签和Repository URL输入框如下
Repository URL输入https://gitee.com/fastjrun/apiworld-codeg.git
脚本路径输入docker.groovy
点“保存”按钮后,这个构建支持多CPU架构docker镜像并推送到hub的任务就配置好了
任务执行
以参考树莓派4B基于docker搭建devops平台首次部署的jenkins在不增添任何plugin的情况下执行本任务,是可以成功执行的。
Blue Ocean
安装Blue Ocean插件后,可以更直观看到本流水线执行的效果。
总结
参考树莓派4B基于docker搭建devops平台进行搭建的jenkins已经解决了很多潜在问题,如果参考其他方案搭建的jenkins在执行构建过程中可能会遇到一些其他问题,您参考网上的解决方案自行处理即可,本实践将不再赘述。