Author:rab
Gitlab 版本:15.1.2
Jenkins 版本:2.332.3
目录
背景
企业在高并发构建场景下,Jenkins 是存在性能瓶颈的,我记得之前写过一篇文章关于 Jenkins 内存溢出的问题,感兴趣的大佬们可以去看看《记一次 Jenkins 构建内存溢出的解决方案》。由此可见,Jenkins 确实存在一定性能瓶颈的。因此,我们可以部署一套高性能的 CD Master Slave 架构,在构建时,对项目指定 Jenkins node 节点进行构建,从而缓解单台 Jenkins 服务的压力,从而提升构建效率。
一、规划
1.1 主机规划
Host | Server | Version | 备注 |
---|---|---|---|
192.168.56.131(2C/4G/30G) | Jenkins | 2.332.3 | Jenkins-master |
192.168.56.132(2C/4G/30G) | Jenkins | 2.332.3 | Jenkins-slave |
192.168.56.133(2C/4G/30G) | Gitlab | 15.1.2 | code server |
注:至少需要两台 Jenkins 服务器,slave 可有多台。由于我本地服务器资源限制,这里暂且使用“一主一从”的架构模式。
1.2 部署方式
本次采用 Docker 容器化部署,实现基于 Docker 的完整 CICD 流程。
二、部署
2.1 Jenkins
两台 Jenkins 服务器均操作
2.1.1 基础部署及配置
1、创建 Jenkins 工作目录
mkdir -p /home/data/jenkins
useradd jenkins
chown jenkins.jenkins /home/data/jenkins
# 注意
# 如果不赋予jenkins用户权限,则容器无法启动。
# 如果不赋予jenkins用户权限,需执行 777 权限
2、运行 Jenkins 容器
docker run -itd \
--privileged=true \
--name jenkins \
--restart=always \
-p 8080:8080 \
-p 50000:50000 \
-v /home/data/jenkins:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /etc/localtime:/etc/localtime \
-e JAVA_OPTS=-Duser.timezone=Asia/Shanghai jenkins/jenkins:2.332.3
浏览器 URL 访问测试:http://192.168.56.131:8080/
3、查询初始密码,并输入初始密码
-
容器内部查看初始密码
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword xxxxxxxxxx
-
docker logs -f jenkins
动态查看(高亮部分即为初始密码)
4、选择推荐插件安装/稍后安装都可以
新手选择 选择推荐插件安装 即可
5、根据提示设置新的用户名密码即可登录
6、插件安装
官方插件下载地址:https://plugins.jenkins.io/
在系统管理——>插件管理
如何安装插件?
2.1.2 Master Slave 配置
当两台 Jenkins 服务器都配置完成后,接下来就是部署 master-slave 架构了。
1、定义远程 Jenkins Slave 的工作目录
mkdir /var/jenkins_home
# 注意:这个目录有什么用?
# 如果你的 master 与 slave 是以 ssh 密钥方式通信,则相关的密钥文件(~/.ssh/*)必须存放于该目录下,否则无法在 Slave 运行agent 进程。用户名/密码方式则无该要求
# 你的java二进制命令也必须存放于该目录下的./jak/bin/,否则找不到 java 指令(你写在profile里也不行啊,因为master找的是绝对路径),则无法在 Slave 运行agent 进程。
2、132 服务器部署 JDK 环境
tar xzf jdk-8u202-linux-x64.tar.gz -C /var/jenkins_home
mv /var/jenkins_home/jdk-8u202-linux-x64 /var/jenkins_home/jdk
3、在 131 服务器上添加 Jenkins slave 节点
4、点击 Create 后继续以下配置
如何添加主机密钥凭证?
扩展(可选)
当然你也可以启动 java web 的方式来实现
在管理节点选择对应的 slave
具体如下:
点击【Launch】获取 JNLP 文件(jenkins-agent.jnlp),会下载到你本地。
点击图片中 agent.jar ,jar 包会下载到你本地。
分别上传 jenkins-agent.jnlp、agent.jar 到你的 jenkins-node1 节点的。
复制上图启动命令:连接 Master
echo "7dd1168f19c1d6d37917209e74de67501b816e40d3cd507def381f81243893da" > secret-file
nohup java -jar agent.jar -jnlpUrl http://192.168.56.131:8080/computer/jenkins%2Dnode1/jenkins-agent.jnlp -secret @secret-file -workDir "/home/data/jenkins" &> ./agent.out &
输出以下日志表示成功连接 master
5、配置完成后,手动点击启动 agent 进程
观察输出日志,看到 succeefull 字眼说明启动成功。
当然,你也可以去 slave 节点查看 Java 进程。
6、最终可在 master 节点管理处看到已在线的 slave 节点
至此,Jenkins 的 master slave 架构部署完成!
2.2 Gitlab
1、创建持久化目录
mkdir -p /home/data/gitlab
2、运行 Gitlab 容器
docker run -itd \
--privileged=true \
--name=gitlab \
--restart=always \
-p 443:443 \
-p 80:80 \
-p 2022:22 \
-v /home/data/gitlab/conf:/etc/gitlab \
-v /home/data/gitlab/log:/var/log/gitlab \
-v /home/data/gitlab/data:/var/opt/gitlab \
-v /etc/localtime:/etc/localtime \
gitlab/gitlab-ce:15.1.2-ce.0
# 注意,如果你的宿主机的 ssh 端口为默认的 22,则此处的映射就不能再是 22 了,否则会造成端口冲突。
3、初始化需等待一定时间,可查看日志来跟踪此过程
docker logs -f gitlab
4、获取初始密码
密码文件将在 24 小时后的第一次重新配置运行中自动删除。
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
5、登录验证
http://192.168.56.131/
可成功登录,登录后可修改初始密码(zhurs@123)。
至此,Gitlab 部署完成!接下来的工作就是创建项目库。
三、验证
3.1 Master Slave 架构可用性测试
1、创建一个流水线工程项目
下图的 label 标签就是我们添加 Jenkins slave 节点时指定的标签名
2、看看输出控制台
3.2 CICD 整体测试
此处以 Java 后端为例进行演示。
3.2.1 Gitlab 新建源码项目
3.2.2 Jenkins 编写 Jenkinsfile
1、Jenkins 如何 clone Gitlab 远程代码?
在Jenkins 流水线语法,进行片段生成。
填写 git 仓库地址(项目源码地址)
添加 git 仓库凭证(目的是为了 Jenkins 能与 Gitlab 通信)— 点击 ADD 添加凭证
添加凭证方式
-
用户名/密码形式
这种方式对应 gitlab 的 http
-
ssh 密钥形式
这种方式对应 gitlab 的 ssh
Jenkins 上传私钥:
Gitlab 上传公钥:
点击生成 jenkinsfile 语句
# SSH密钥
checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: 'git-pull', url: 'ssh://git@192.168.56.133:2022/root/tq.git']]])
# Http用户名/密码
checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-root-user', url: 'http://192.168.56.133/root/tq.git']]])
# 两者选其一即可
2、项目构建
mvn clean package -Dmaven.test.skip=true -P test
3、选项参数
同样用 Jenkins 自带流水线代码片段生成器来生成
实现的选项参数功能:
- 自动获取 Gitlab 远程仓库分支(gitParameter);
- 项目构建列表(extendedChoice);
- 项目构建环境(choice);
- 项目构建后选择是否启动(booleanParam).
-
gitParameter
该参数类型可自动获取远程 Gitlab 仓库的源码项目的所有分支或标签。 gitParameter (name: 'BRANCH_TAG', type: 'PT_BRANCH_TAG', branchFilter: 'origin/(.*)', defaultValue: 'main', selectedValue: 'DEFAULT', sortMode: 'DESCENDING_SMART', description: '选择分支或标签') # name:自定义 # defaultValue:自定义 # description:自定义
-
extendedChoice
该参数类型为选项参数,支持多选。 extendedChoice(name: 'JOB', description: '选择需要发布的项目', multiSelectDelimiter: ',', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_CHECKBOX', value: 'all,project-1,project-2,project-3', visibleItemCount: 10) # name:自定义 # description:自定义 # multiSelectDelimiter:分隔符 -- 自定义 # value:自定义,并以英文状态下逗号分割 # visibleItemCount:选项展示的数量
-
choice
该参数类型也是为选项参数,但仅支持单选。 choice(name: 'ENV', choices: ['test', 'pro'], description: 'test:测试构建,pro:正式构建') # name:自定义 # choices:自定义(可写多个) # description:自定义
-
booleanParam
该参数类型为布尔类型,只有两种情况 true 或 false。 booleanParam(name: 'START', defaultValue: 'false', description: '是否构建完成后启动项目?是则勾选,否则需手动启动项目。') # name:自定义 # defaultValue:默认为 false (或true) # description:自定义
-
text
该参数类型文本类型。 text defaultValue: 'project-1,project-2,project-3',name: 'ALL_PROJECT_LIST' # name:自定义 # defaultValue:自定义
4、配置远程主机信息
同样用 Jenkins 自带流水线代码片段生成器来生成
构建成功后,jar 包如何发布远程测试/生产服务器?
-
withCredentials: Bind credentials to variables 方法生成加密信息
该方法支持多种方式加密,根据实际情况选择。我本次采用的是
Username and password (separated)
-
远程测试/生产服务器配置信息
上面生成的用户名/密码的加密信息就是用于下图中来做变量替换的,如下图中远端服务器用户名/密码都是明文形式,不安全。
-
最终配置如下
withCredentials([usernamePassword(credentialsId: 'remote-host', passwordVariable: 'PassWord', usernameVariable: 'UserName')]){ def remote = [:] remote.name = "$Jarnname" remote.host = "$Host" remote.user = "$UserName" remote.password = "$PassWord" remote.port = 22 remote.allowAnyHosts = true //在远程测试/生产服务器执行命令(可选) sshCommand remote: remote, command: "sudo mv ${ProJect}/$Jarnname ${ProJect}/${Jarnname}.\$(date +%Y%m%d_%H:%M)" //部署jar包(必选) //如果into不添加具体路径,默认发布到远程服务器的家目录下 sshPut remote: remote, from: "${WORKSPACE}/${ProJect}/target/$Jarnname", into: "./${ProJect}/", override: true //在远程测试/生产服务器执行命令(可选) sshCommand remote: remote, command: "sudo chown root.root ${ProJect}/$Jarnname" sshCommand remote: remote, command: "sudo cp -f ${ProJect}/$Jarnname /opt/$ENV/${ProJect}/$Jarnname" }
上面是用户名/密码的方式与远程主机的通信,当然你也可以以 SSH 用户密钥的方式,可参考我前面的博文《Jenkins Pipeline 密钥实现远程部署》
5、流水线后操作
流水线是否执行成功,我们可以通过钉钉或邮件等其他形式通知,具体配置看我前面的博文《Jenkins Pipeline 配置钉钉消息通知》。
6、编写完 Jenkinsfile 之后执行构建
当然,Jenkins 需要安装一些额外的插件,这里不再赘述。
如上图构建成功,当然流水线代码较多,我没有写在上面,遇到问题的朋友可以私我,我们一起交流解决。
至此,一套 Jenkins Master Slave 架构部署完成。
四、FAQ
4.1 SSH 问题
启动 jenkins slave 时输出日志信息:
No entry currently exists in the Known Hosts file for this host. Connections will be denied until th
再次编辑 Jenkins slave 选择下图红色框选项即可。
4.2 无法启动 agent
当我们 jenkins-node1 配置完成后,Jenkins-master 会通过 ssh 连接远程 slave,并自动为我们在 slave 节点启用一个 agent 进程(remoting.jar
),所以要保证远程 slave 具备 JDK 环境。在 1.1.2 小结
已进行了说明。
4.3 Gitlab 用户头像无法显示
1、现象
2、解决方案
原因是因为GitLab默认使用了Gravatar的头像,而Gravatar目前是被墙的。所以访问不了,解决问题的办法就是更换其URL为国内的某个镜像URL。
vim /home/data/gitlab/data/gitlab-rails/etc/gitlab.yml
...
plain_url: http://sdn.geekzu.org/avatar/%{hash}?s=%{size}&d=identicon
ssl_url: https://sdn.geekzu.org/avatar/%{hash}?s=%{size}&d=identicon
...
# 其实也就是修改容器里的/var/opt/gitlab/*/gitlab.yml文件
重启以下 Gitlab 即可。
docker exec -it gitlab bash
gitlab-ctl restart
# 或 docker restart gitlab
在看看,头像已经正常显示了。
也可自定义自己的头像:
4.4 Gitlab 502 报错
1、现象
2、解决方案
这个一般是你服务器性能出现问题,稍等片刻或重启 Gitlab 即可解决。
4.5 Git 克隆报错
1、git clone 时提示如下错误
提示无法解析这个主机名。
上 Gitlab 看一下:不是主机IP,而是一串随机字符
2、解决方案
-
修改配置文件
vim /home/data/gitlab/conf/gitlab.rb
-
重启 Gitlab
docker restart gitlab
-
再次查看
-
新建一个 tq 项目并克隆
git clone ssh://git@192.168.56.133:2022/root/tq.git # 注意:ssh协议,其容器内部的22端口映射到了我的宿主机的2022端口了,所以clone时需改为2022端口。 # 如下图:成功clone
4.6 Jenkins 插件安装失败
1、Jenkins 插件管理
Jenkins 插件默认使用其官方源安装,因此在我们国内的话可能会安装失败,于是可以更换为国内源进行安装。
国内源:
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
http://mirror.xmission.com/jenkins/updates/update-center.json
2、修改 Jenkins 服务器 default.json
配置
将其中的 updates.jenkins-ci.org/download
替换为 mirrors.tuna.tsinghua.edu.cn/jenkins
某些 Jenkins 版本当中,是将 updates.jenkins.io/download
替换为 mirrors.tuna.tsinghua.edu.cn/jenkins
然后,把 www.google.com
修改为 www.baidu.com
vim /home/data/jenkins/updates/default.json
# 全局替换
:%s#updates.jenkins.io/download#mirrors.tuna.tsinghua.edu.cn/jenkins#g
:%s#www.google.com#www.baidu.com#g
# 或
sed -i 's#updates.jenkins.io/download#mirrors.tuna.tsinghua.edu.cn/jenkins#g' default.json
sed -i 's#www.google.com#www.baidu.com#g' default.json
3、重启 Jenkins 服务
docker restaer jenkins
ci.org/download替换为
mirrors.tuna.tsinghua.edu.cn/jenkins`
某些 Jenkins 版本当中,是将 updates.jenkins.io/download
替换为 mirrors.tuna.tsinghua.edu.cn/jenkins
然后,把 www.google.com
修改为 www.baidu.com
vim /home/data/jenkins/updates/default.json
# 全局替换
:%s#updates.jenkins.io/download#mirrors.tuna.tsinghua.edu.cn/jenkins#g
:%s#www.google.com#www.baidu.com#g
# 或
sed -i 's#updates.jenkins.io/download#mirrors.tuna.tsinghua.edu.cn/jenkins#g' default.json
sed -i 's#www.google.com#www.baidu.com#g' default.json
3、重启 Jenkins 服务
docker restart jenkins
如有错漏之处,敬请指正!