文章目录
环境
- 日期: 2023-11-01
- CentOS Stream 9
- 镜像: Jenkins 2.414.3 LTS (jenkins/jenkins:2.414.3-lts-jdk17)
文档
下载
Jenkins 官网下载页面的 Docker 会跳转到 DockerHub 的 Jenkins 页面, 使用 docker 下载对应 Tag 的 Jenkins, 这里选的是 jenkins/jenkins:2.414.3-lts-jdk17
额外说明: Jenkins 内嵌了 Winstone, 是一个 Jetty Servlet 容器的包装, War 包可以直接用 java -jar jenkins.war --httpPort=8888
来运行. War 包也可以在清华大学开源软件镜像站下载, https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/
安装
下载镜像
docker pull jenkins/jenkins:2.414.3-lts-jdk17
docker pull docker:dind
创建网络
docker network create jenkins
运行 docker:dind 镜像
# 为了在 Jenkins 节点内执行 Docker 命令, 先运行 docker:dind 镜像
docker run \
--name jenkins-docker \ # -n, 创建的容器的名称
--rm \ # 容器运行结束后自动删除该容器, 可选
--detach \ # -d, 后台运行容器
--privileged \ # 授予容器扩展权限. 在 Docker 容器中运行 Docker 当前需要特权访问才能正常工作, 这一要求可能会随着更新的 Linux 内核版本而放宽
--network jenkins \ # 将容器连接到上面创建的网络 jenkins
--network-alias docker \ # 指定该容器在网络 jenkins 中的别名(hostname)为 docker. 其他容器连接到网络 jenkins 中, 即可通过 docker 这个 hostname 访问该容器
--env DOCKER_TLS_CERTDIR=/certs \ # 允许在Docker服务器中使用 TLS。由于使用了特权容器,建议这样做,尽管它需要使用下面描述的共享卷。此环境变量控制管理 Docker TLS 证书的根目录。
--volume jenkins-docker-certs:/certs/client \ # 在主机创建一个卷 jenkins-docker-certs, 其位置由 Docker 决定, 印射到容器内的 /certs/client 目录
--volume jenkins-data:/var/jenkins_home \ # 在主机创建一个卷 jenkins-data, 印射到容器内的 /var/jenkins_home 目录. 这里可以使用 挂载 而不是 卷, 便于自定义容器目录印射到主机目录的位置, 如 -v /data/jenkins:/var/jenkins_home
--publish 2376:2376 \ # -p, 暴露容器端口到主机端口
docker:dind \ # Docker DIND(Docker-in-Docker)是一种使用 Docker 容器创建 Docker 容器的技术。它允许在 Docker 容器内模拟 Docker 环境
--storage-driver overlay2 # Docker 卷 的存储驱动程序
# 无注释版本
docker run --name jenkins-docker --rm --detach \
--privileged --network jenkins --network-alias docker \
--env DOCKER_TLS_CERTDIR=/certs \
--volume jenkins-docker-certs:/certs/client \
--volume jenkins-data:/var/jenkins_home \
--publish 2376:2376 \
docker:dind --storage-driver overlay2
自定义官方 Jenkins 镜像. 在一个空目录中, 创建 Dockerfile 文件, 其内容如下
FROM jenkins/jenkins:2.414.3-lts-jdk17
USER root
RUN apt-get update && apt-get install -y lsb-release
RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \
https://download.docker.com/linux/debian/gpg
RUN echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \
https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
RUN apt-get update && apt-get install -y docker-ce-cli
USER jenkins
RUN jenkins-plugin-cli --plugins "blueocean docker-workflow"
然后在该目录下执行构建命令, 等待构建完成, 完成后 docker 镜像中就会有 myjenkins-blueocean:2.414.3-1 镜像
docker build -t myjenkins-blueocean:2.414.3-1 .
运行自定义的 Jenkins 镜像
注意: 下面的 卷 jenkins-data 的印射, 可以换成挂载 如 -v /_:/_
, 即主机的 /_
目录印射到了容器的 /_
目录, 这个配置的特点是两边的路径在印射后将会完全一致, 主机的配置无需更改即可在容器中生效, 举个例子, 主机的 maven 在 /_/maven/3.9.5
, 主机的本地仓库在 /_/maven/repository
, 印射后, 容器内无需对 settings.xml 文件做任何修改, 即可直接使用, 因为两边的路径完全一致
docker run \
--name jenkins-blueocean \
--restart=on-failure \ # 开启容器停止时自动启动, 如果手动停止,则只有在Docker守护进程重新启动或容器本身手动重新启动时才会重新启动。
--detach \
--network jenkins \
--env DOCKER_HOST=tcp://docker:2376 \ # 将此容器连接到先前定义的jenkins网络。Docker守护进程现在可以通过主机名Docker用于这个Jenkins容器。
--env DOCKER_CERT_PATH=/certs/client \
--env DOCKER_TLS_VERIFY=1 \
--publish 8080:8080 \ # 访问 Jenkins 的 Http 端口, 可以自定义
--publish 50000:50000 \
--volume jenkins-data:/var/jenkins_home \ # 需要和上面 docker:dind 的配置保持一致, 是卷都是同一个卷, 是挂载都是同一个挂载
--volume jenkins-docker-certs:/certs/client:ro \
myjenkins-blueocean:2.414.3-1
# 无注释版本
docker run --name jenkins-blueocean --restart=on-failure --detach \
--network jenkins --env DOCKER_HOST=tcp://docker:2376 \
--env DOCKER_CERT_PATH=/certs/client --env DOCKER_TLS_VERIFY=1 \
--publish 8080:8080 --publish 50000:50000 \
--volume jenkins-data:/var/jenkins_home \
--volume jenkins-docker-certs:/certs/client:ro \
myjenkins-blueocean:2.414.3-1
访问容器
docker exec -it jenkins-blueocean bash
访问日志
docker logs jenkins-blueocean
访问 Jenkins home 目录
# 如果使用的是 挂载, 直接在主机文件系统访问主机印射目录即可
cd ....
# 如果使用的是 卷, 我记得 卷 也可以在主机上找到印射目录
docker container exec -it jenkins-blueocean bash
# 使用该命令可查看卷 jenkins-data 在主机上的路径, 用 cd 访问该路径应该也是一样的效果
docker volume inspect jenkins-data
配置
解锁
首次访问一个新的 Jenkins 实例时, 使用自动生成的密码解锁它, 访问 http://localhost:8080 (端口看自定义设置) 即可看到解锁页面. 我这边用的是虚拟机, 所以访问地址为 192.168.88.129:8080
通过以下方式可看到这个密码, 密码在容器内部的 /var/jenkins_home/secrets/initialAdminPassword 文件内
docker exec jenkins-blueocean cat /var/jenkins_home/secrets/initialAdminPassword
# 通过 卷/挂载 印射在主机查看该密码
# 如果是挂载, 直接 cd 到目录
cat secrets/initialAdminPassword
# 如果是卷, 先找到卷的路径, 然后再 cd/cat 查看
docker volume inspect jenkins-data
cd /var/lib/docker/volumes/jenkins-data/_data # 我这边找到的路径
cat secrets/initialAdminPassword
安装插件
直接先选推荐的插件, 后续可以在管理页面配置
创建第一个管理员用户
这里用 root 为 id 创建一个名为 administrator 的管理员账户
实例配置
就用能正常访问 Jenkins 的默认 Jenkins URL 即可
初次访问页面大致如此
配置
完全汉化
默认插件里有中文语言包插件, 且页面默认已经是显示中文了, 但是汉化并不完整, Locale 插件允许汉化剩余部分中的一些, 安装了 Locale 后, 在系统设置里就有了 Locale 这一个配置项, 填写 zh_CN, 勾选选项, 点击保存, 访问 http://192.168.88.129:8080/restart 重启 Jenkins
如果重启后, 发现汉化还是不完整, 修改 Locale 为 en_US, 重启, 然后改回 zh_CN 即可
安装插件
Maven Integration
默认插件里没有该插件, 需要单独安装 Maven Integration 插件
Publish Over SSH
默认插件里没有该插件, 该插件是通过 SSH 连接其他 Linux 机器, 远程传输文件及执行 Shell 命令
因为现在是用 Docker 运行的 Jenkins, 所以 Jenkins 流程里执行的 shell 命令, 都是在 Docker 容器内部执行, 所以这里一定需要某种方式能在容器外执行 shell 命令, 该插件就可以实现
设置
在 系统管理 - 系统配置 中找到 Publish over SSH, 先在这里设置好链接的服务器信息, 需要填写如下字段
SSH Servers
- Name: 192.168.88.129
- Hostname: 192.168.88.129
- Username: root
- Remote Directory: /
- 连接主机后的初始工作路径, 推荐配置为根目录, 这样依赖该路径的配置就都可以直接用绝对路径了
- 在高级选项里勾选 Use Password authentication, or use a different key
- Passphrase / Password: 目标主机 root 账户的密码
- 点击该部分配置右下角的 Test Configuration 按钮即可验证配置是否有效
- 其他字段保持默认即可
- 这里使用的是账号密码的连接方式, 也可以使用公私钥的方式
然后在任务配置中, 添加一个 Post Steps, 类型为 Send files or execute commands over SSH
- SSH Server
- Name: 选刚刚配置的主机 192.168.88.129
- Transfers
- Source files: target/*.jar
- 要传输的文件, 以 workspace 路径作为基准的相对路径, 本任务的 workspace 路径是 /var/jenkins_data/workspace/test
- Remove prefix: target
- 不加 target 就会把 target 文件夹一起传输过去, 加了就会取消这个前缀
- Remote directory: /data
- 保存的位置, 在主机的 /data 目录下, 具体值需要依赖上面配置的 Remote Directory
- Exec command:
- 要在主机执行的 shell 命令, 所有路径全部使用绝对路径
- Source files: target/*.jar
执行的命令大致如下, 第三行的 cd 非常重要, 能避免一堆奇怪的执行错误问题
echo ""
echo "----------"
cd /data/carbon-resourcelib
pid=$(ps -ef | grep carbon | grep -v grep | awk '{print $2}')
if [ -z "$pid" ]; then
echo "PID: None"
else
echo "PID: $pid"
kill -9 $pid
fi
echo "----------"
nohup /_/jdk/11.0.20/bin/java -XX:MetaspaceSize=256M -jar carbon-resourcelib.jar --spring.profiles.active=dev > /dev/null 2>&1 &
pid=$(ps -ef | grep carbon | grep -v grep | awk '{print $2}')
echo "PID: $pid"
echo "----------"
echo ""
全局工具配置
Jenkins 通常需要在 系统管理 - 全局工具配置 中配置 JDK 和 Maven 和 Git, 容器中默认已经有 JDK 和 Git 了, 如果其版本等不满足条件, 可以自行配置, 方式就是将主机中的相关工具目录印射到容器中, 确保在容器中能访问目录, 然后在 Jenkins 中配置上容器路径就好了
可以将工具目录拷贝到印射的 卷 jenkins-data 指向的目录 /var/lib/docker/volumes/jenkins-data/_data 下. 在该目录下创建独一无二且绝不可能和 Jenkins 可能使用到的目录相同的目录, 用于存放这些工具
也可以在运行容器的时候, 额外添加各种工具和容器的目录印射挂载, 如 -v /_:/_
, 将主机的 /_
目录印射到容器的 /_
目录, 在主机目录下创建 jdk 目录, 存放多版本的 JDK, 还有 maven 目录, 里面有各版本的 Maven, 里面还有一个 repository 目录(chmod 777), 作为本地仓库, 其他的按需创建和拷贝即可
选择第二种挂载的话, 需要修改运行镜像的命令如下
docker run --name jenkins-blueocean --restart=on-failure --detach \
--network jenkins --env DOCKER_HOST=tcp://docker:2376 \
--env DOCKER_CERT_PATH=/certs/client --env DOCKER_TLS_VERIFY=1 \
--publish 8080:8080 --publish 50000:50000 \
--volume jenkins-data:/var/jenkins_home \
--volume jenkins-docker-certs:/certs/client:ro \
-v /_:/_ \
myjenkins-blueocean:2.414.3-1
JDK
我配了 4 个, 以应对各种 JDK 需求
- 8.0.381: /var/jenkins_home/_/jdk/8.0.381
- 11.0.20: /var/jenkins_home/_/jdk/11.0.20
- 17.0.9: /var/jenkins_home/_/jdk/17.0.9
- 21.0.1: /var/jenkins_home/_/jdk/21.0.1
不知道为什么, 容器内以 java -jar jenkins.war 的方式启动了 Jenkins, 在宿主机同样有一个类似的 java 进程, 只是两者的 PID 不同, 在宿主机结束该 java 进程会导致容器重启
Maven
- 3.9.5: /var/jenkins_home/_/maven/3.9.5
页面顶部的 Maven 配置 无需配置, 修改 Maven 目录里 conf 目录下的 settings.xml 文件内容正确即可
注意 settings.xml 里面 localRepository 标签指定的本地仓库位置, 需是容器能够识别的位置, 我这里在主机的印射目录下新建了一个 repository 目录, 用来作为本地仓库, 该印射目录在主机与容器下的路径分别如下
- 主机: /var/lib/docker/volumes/jenkins-data/data//maven/repository
- 容器: /var/jenkins_home/_/maven/repository
注意 repository 目录在主机侧创建, 权限给 777, 因为 Jenkins 是以 jenkins 用户运行的, 在权限上可能会出问题, 在主机侧设置权限对容器侧有效
如果有现成的本地仓库, 可以在运行 Jenkins 镜像容器时, 额外指定一个挂载印射目录, 然后给 settings.xml 里面配置该印射目录在容器内的路径即可
settings.xml 内容如下, 配置了 aliyun.public 和 tencent.public 和个人私库等多个远程仓库
<?xml version="1.0" encoding="UTF-8"?>
<settings
xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<localRepository>/var/jenkins_home/_/maven/repository</localRepository>
<mirrors>
<mirror>
<id>aliyun.public</id>
<name>aliyun.public</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central,jcenter</mirrorOf>
</mirror>
<mirror>
<id>maven-default-http-blocker</id>
<mirrorOf>external:http:*</mirrorOf>
<name>Pseudo repository to mirror external repositories initially using HTTP.</name>
<url>http://0.0.0.0/</url>
<blocked>true</blocked>
</mirror>
</mirrors>
<servers>
<server>
<id>mrathena</id>
<username>username</username>
<password>password</password>
</server>
</servers>
<profiles>
<profile>
<id>mrathena</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>aliyun.public</id>
<name>aliyun.public</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>tencent.public</id>
<name>tencent.public</name>
<url>https://mirrors.cloud.tencent.com/nexus/repository/maven-public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>mrathena</id>
<name>mrathena</name>
<url>https://mrathena-maven.pkg.coding.net/repository/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>aliyun.apache.snapshots</id>
<name>aliyun.apache snapshots</name>
<url>https://maven.aliyun.com/repository/apache-snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
</settings>
Git
- 用内置的 Git 即可, 默认不需要动
任务
点击 新建 Item
, 选择 构建一个 Maven 项目
, 名称填写 test, 点击确定即可进入流程配置环节, 大致如下
General
选择项目使用的 JDK
也可以添加构建参数选择, 比如手动选择构建的 Git 分支, 这里定义的参数名称 branch, 可以在其他地方通过 ${branch}
的方式引用该值
源码管理
选择 Git, 先用 HTTP 的 git 克隆地址, 找一个有权限的代码托管平台的账号, 添加为 Username/Password 类型的凭据, 当 Repository URL 下面的红字提示消失, 说明凭据认证通过, 配置正确
源码库浏览器按照实际情况填写即可
构建触发器
如何出发构建流程, 默认是通过手动在 Jenkins 点击构建, 可以通过配置选项, 设置成提交代码就自动构建, 或者每天定时构建, 等
构建环境
在控制台输入日志里添加时间戳
Pre Steps
构建流程, 分为3个阶段, Pre - Build - Post, 后面流程里还有一个 构建后操作, 是这三个阶段都完成后, 才会执行的操作
构建前的操作, 支持很多种操作, 如 Execute shell 就可以执行各种 shell 命令, 里面可以引用很多提前定义的环境变量
Build
Jenkins 会给每一个项目分配一个工作空间, 用于克隆代码, 构建应用等操作, 之前已经设置过全局默认的 settings.xml 文件, 但在 高级 选项里可以用自定义配置覆盖
Post Steps
构建后操作, 可以选择执行该操作的条件, 同样可以选多种操作, 比如, 可以在这个阶段 kill 之前的应用进程, 拷贝新构建的 jar 到指定目录, 执行 java -jar xxx.jar 启动应用, 判断进程存在, 输出应用启动成功等
这里需要用到 Publish Over SSH 插件, 具体设置参考上面的相关内容
构建设置
构建结果可以通过邮件通知
构建后操作
同样也有很多操作