写在最前
终于来到jenkins篇章了它是即强大又难以掌握啊,那么跟随我拿下它让它来做非常有意思的工作。
1. 前置要求
2. 部署流程
2.1 docker 部署
按流程部署,再 docker logs jenkins 查看密码即可,然后选择推荐插件安装
# 删除容器和数据目录
docker rm -f jenkins && rm -rf /data/jenkins
# 创建数据目录和更改访问权限
mkdir -p /data/jenkins && chown -R 1000 /data/jenkins
# 部署容器
docker run --name jenkins -d \
-p 8080:8080 \
-p 50000:50000 \
--restart=always \
-v /data/jenkins:/var/jenkins_home \
jenkins/jenkins:2.478-jdk17
2.2 域名配置
2.2.1 1panel 域名配置
主域名:jenkins.dev.tanqidi.com
代理地址:172.31.0.100:8080
2.2.2 dnsmasq 域名解析
address=/jenkins.dev.tanqidi.com/172.31.0.100
2.3 安装插件
Locale,部署上jenkins会发现只有部分汉化这个插件可以让你控制Jenkins的语言,安装此插件能最大限度完成汉化。
CloudBees Docker Build and Publish,这个插件可以构建基于Dockerfile的项目,以及将构建的镜像推送到指定镜像仓库中。
CloudBees Docker Custom Build Environment,流水线调用docker必备插件,用于构建环境参数。Parameterized Trigger,该插件允许你在构建完成时触发新的构建任务,并通过各种方式为新构建指定参数。
2.4 配置汉化
安装完 Local 插件后即可配置汉化,因为jenkins更新的太快了汉化组只能兼容大部分并非完全汉化。
记住!!!选择第一个英语,不要选择中文!!!
在jenkins入口访问/restart即可出现重启按钮,重启后jenkins即可实现汉化
2.5 密码修改
3. 操作流程
3.1 创建秘钥
在流水线自动化执行过程中,访问Git仓库和Harbor容器仓库等资源时,需要使用凭证进行身份验证。为了确保流程顺畅,我们需要提前准备并配置好这些访问密钥。
3.2 基础操作
3.2.1 创建流水线
在主页点击 + 创建一个名称为 devops-java-sample 项目
https://gitee.com/tanqidi/devops-java-sample,你可以到这里Forked一份代码到你的gitee仓库中。
3.2.2 限制项目的运行节点
这里你要先看 前置要求2 构建Maven3.6的slave节点才会出现此选项,如果你没有任何slave节点这里是不会出现的,我就选择build-maven3.6作为构建环境
3.2.3 git源码配置
3.2.4 添加构建步骤 shell
Build Steps 添加一个步骤为 shell,粘贴以下命令最终你可以看到我成功通过mvn构建源码得到 devops-sample-0.0.1-SNAPSHOT.jar
# 查看当前路径
pwd
# 列表文件
ls -l
# 使用build-maven3.6当前环境的mvn构建java源码
mvn clean package -Dmaven.test.failure.ignore=true -DskipTests=true -U
# 构建完成后当前目录会多一个target目录,里面就是最终具体的可运行jar包了
ls -l target
# 这个项目看起来有点特殊他不叫Dockerfile而是叫Dockerfile-on-prem,所以我们这里需要使用cp命令将它复制一份名为Dockerfile,即可为 Docker Build and Publish 步骤识别
cp Dockerfile-on-prem Dockerfile
# 列表文件
ls -l
3.2.5 添加构建步骤 Docker Build and Publish
这里用到了 CloudBees Docker Build and Publish 这个插件
Build Steps 添加一个步骤为 Docker Build and Publish
因为这个插件的 " Registry credentials " 是不支持私有仓库的,所以我们需要在构建环境中选择凭证让他注入环境变量中来用让shell来使用,按此操作进行完再构建,可以看到我顺利构建出镜像并且推送到aliyun了。
#!/bin/bash
echo "登录私有镜像仓库"
echo ${HARBOR_ACCESS_PWD} | docker login registry.cn-hangzhou.aliyuncs.com --username ${HARBOR_ACCESS_USER} --password-stdin
3.2.6 调用部署任务
请先看高级操作 ,添加构建后操作 Trigger parameterized build on other projects,具体这些变量名什么含义你去 Pipeline Script 看看
deploy_node_name=build-maven3.6
application_name=devops-java-sample
container_name=devops-java-sample
image_name=tanqidi-temp/devops-java-sample
tag_name=dev_latest
在构建完成后,
devops-java-sample
成功调用了deploy-app
,并传递了相关参数,脚本顺利执行,应用成功部署至容器。然而,你可能会疑惑,应用部署到了哪里?让我来澄清一下:我的build-maven3.6
节点运行在IP地址为172.31.0.123
的宿主机上。这意味着该宿主机的Docker服务被挂载进了容器,脚本中调用的Docker正是位于172.31.0.123
的Docker实例。只需访问172.31.0.123:8080
,你就能看到应用成功运行的界面。
3.3 高级操作
我们需要为流水线解耦,简单来说就是A流水线操作完了传递期望的参数给到B流水线让他来运行后续的东西,这样的好处就是剥离开一些公共的部分,这样流水线一多就会非常容易操作,如果不拆分那么所有操作都在一个流水线里面,流水线一多就不好修改了。
3.3.1 其他工程构建后触发
这里用到了 Parameterized Trigger 这个插件
现在 devops-java-sample 已经完成了编译jar与构建镜像了,就差最后一步的部署容器运行起来了,这个部分我们就可以拆分开命名为 deploy-app,接受一些必须的参数然后让它来拉取镜像部署到主机上,这样后续所有的流水线都可以在最后的步骤调用这个任务来完成。
创建流水线
参数化构建过程,全部都是字符参数:application_name,deploy_node_name,container_name,image_name,tag_name
Pipeline Script,注意!我的阿里云harbor凭证是aliyun-harbor-secret,要将你的粘贴替换上去,如果不存在会报错。
node("${deploy_node_name}") {
try {
timestamps {
stage("Deploy ${application_name} to ${deploy_node_name}") {
withCredentials([usernamePassword(credentialsId: 'aliyun-harbor-secret', passwordVariable: 'HARBOR_ACCESS_PWD', usernameVariable: 'HARBOR_ACCESS_USER')]) {
sh """
echo ${HARBOR_ACCESS_PWD} | docker login registry.cn-hangzhou.aliyuncs.com --username '${HARBOR_ACCESS_USER}' --password-stdin
docker pull registry.cn-hangzhou.aliyuncs.com/${image_name}:${tag_name}
docker rm -f -v ${container_name} || echo "${container_name} container not exist"
sleep 5s
docker run -d --name ${container_name} --dns=172.31.0.53 --net host -v /data/${container_name}:/data -v /log/${container_name}:/log registry.cn-hangzhou.aliyuncs.com/${image_name}:${tag_name}
"""
}
}
}
} catch (err) {
// Handle exception
echo "Error during deployment: ${err}"
}
}
4. 异常解决
4.1 permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
4.1.1 临时
这是因为挂载进去的 /var/run/docker.sock 的权限,和容器内的执行者权限不一样所以出现了无法调用docker.sock的问题,最快速的就是在宿主机上对docker.sock做权限变更,但这只是临时的,下次重启docker这个sock文件会被重建权限就又丢失了。
chmod 666 /var/run/docker.sock
4.1.2 永久
本质上,就是要确保确保Docker运行的组和Jenkins slave运行的组一致。具体步骤如下:
我在
docker-install.sh
中优化了一下,先创建一个GID为999
的docker
组,这样在生成docker.service
文件时,docker.sock
会自动拥有该组的权限。在Jenkins slave的Dockerfile中,同样创建一个名为
docker
、GID为999
的组。将Jenkins用户(即容器中的运行用户)添加到这个
docker
组中。
通过这种方式,Jenkins slave在调用docker.sock
时,其GID为999
,与宿主机一致,从而获得必要的权限。这样可以确保容器与主机之间的Docker访问权限协调一致。
# 创建docker组并指定GID为999
RUN groupadd -g 999 docker && \
usermod -aG docker jenkins
4.2 Docker Build and Publish "Registry credentials注册表凭据" 不适用于私有 docker 注册表
https://issues.jenkins.io/browse/JENKINS-39952
5. 操作总结
你如此这般耐心地逐字逐句地阅读本篇章,实属不易,而我也期待你能完整的跟着本篇章来操作一遍,仔细梳理devops-java-sample
和deploy-app
之间的调用关系,以及如何使用build-maven3.6
这个slave节点进行操作,最后我要恭喜你,你成功的掌握到了jenkins的部署与构建流程!