介绍

本文介绍如何配置 Jenkins 打包。

系列

安装

虚拟机

首先需要在本地测试,因此使用 Vagrant + Virtual Box 组合创建一个现成的虚拟机,如果直接在生产环境上安装可以跳过下面的安装过程,直接参考 Jenkins 官方教程进行安装。包管理器安装方式也可以参考 Jenkins 安装配置 - 狂飙

使用 Vagrant 安装 Ubuntu 22.04 作为服务器(后续需要使用 Packer 生成镜像),使用 Docker 安装 Jenkins。

Vagrant 2.2.19

Virtual Box 6.1.32

使用 Ubuntu 20.04 镜像

虚拟化

启动 Vagrant 虚拟机时有报错:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ vagrant init ubuntu/focal64

...

==> default: Booting VM...
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: ["startvm", "1bdaf9e2-9ca4-4512-8851-632af81a91a4", "--type", "headless"]

Stderr: VBoxManage.exe: error: Not in a hypervisor partition (HVP=0) (VERR_NEM_NOT_AVAILABLE).
VBoxManage.exe: error: VT-x is disabled in the BIOS for all CPU modes (VERR_VMX_MSR_ALL_VMX_DISABLED)
VBoxManage.exe: error: Details: code E_FAIL (0x80004005), component ConsoleWrap, interface IConsole

需要禁用 HyperVisor,以管理员运行命令行提符:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
C:\Windows\system32>dism.exe /Online /Disable-Feature:Microsoft-Hyper-V

部署映像服务和管理工具
版本: 10.0.19041.844

映像版本: 10.0.19044.1620

禁用一个或多个功能
[==========================100.0%==========================]
操作成功完成。

然后重启,按 F2 进入 BIOS,在 BIOS 中开启 Intel 虚拟化 VMM,再次运行 Vagrant 就可以了。

Docker 安装

1
2
3
4
5
6
7
8
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
$ sudo docker run hello-world
$ docker pull jenkins/jenkins:lts-jdk11

桥接网络

使用文档

改为桥接网络 config.vm.network "public_network",但是启动后依然找不到网卡。显式指定了网卡 config.vm.network "public_network", :bridge => "Realtek PCIe 2.5GbE Family Controller" 也无效。

打开 Virtual Box,选择 Vagrant 启动的虚拟机,点击 设置 | 网络 | 网卡1,连接方式改为桥接,然后可以看到下面的 界面名称 下拉框中没有可选的网卡,这说明是缺失 Virtual Box 网卡驱动,安装即可。

安装方法:

  1. 打开当前网络连接属性,点击 安装 按钮
  2. 选择网络功能类型 对话框中选择 服务,点击 添加 按钮
  3. 选择网络服务 对话框中点击 从磁盘安装
  4. 从磁盘安装 对话框的 制造商文件复制来源 输入框中输入 C:\Program Files\Oracle\VirtualBox\drivers\network\netlwf
  5. 选择网络服务 对话框中点击 确认 按钮

相关解决方案:

之前如果运行过 vagrant up 出错,使用 Ctrl+C 中断操作,那么需要打开任务管理器,结束 ruby.exe 进程。

最后确认一下是否获得了内网 IP:

1
2
3
4
5
6
vagrant up
vagrant ssh
# 显示当前 IP
ip addr show
# Ping 百度 确认是可以访问外网的
ping baidu.com

Docker 配置

以 Docker 后台模式运行 Jenkins

1
2
3
4
5
6
7
8
$ sudo docker run -d -v jenkins_home:/var/jenkins_home -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts-jdk11
34faa7e724116e6e8ddf905935a209e49a3505bea623200296be02b1d7055971
vagrant@ubuntu-focal:~$ docker logs 34faa7e724116e6e8ddf905935a209e49a3505bea623200296be02b1d7055971

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

拿到内网 IP 后在浏览器中访问 http://内网IP:8080/

Docker 数据目录映射

由于后续需要对 Jenkins 版本进行升级,因此需要将数据放到外面。Docker Volume 用起来不太直观,因此考虑将文件直接放到宿主机上。

另外由于使用的是 Vagrant,似乎可以将文件存到主机的映射目录中,但是 Jenkins Docker 文档中提到了符号链接在某些操作系统下会变成拷贝,会导致最后一次稳定构建链接问题,因此决定不放到映射目录中:

Note that some symlinks on some OSes may be converted to copies (this can confuse jenkins with lastStableBuild links etc)

使用映射目录必须修正权限问题:

1
2
3
4
5
# 切换到 root 用户
$ sudo su
$ mkdir /var/jenkins_home
$ chown -R 1000:1000 /var/jenkins_home
$ docker run -d -v /var/jenkins_home:/var/jenkins_home -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts-jdk11

Docker 设置镜像开机启动

1
docker update --restart=always 镜像ID

Jenkins Agent

配置

创建节点,然后配置节点 通过Java Web启动代理,在状态中下载 agent.jar 放到 d:\Jenkins\,并拿到启动节点的命令,将其保存为 d:\Jenkins\JenkinsAgent.bat ,运行后提示:'java' 不是内部或外部命令,也不是可运行的程序或批处理文件。需要下载 Java runtime 才能运行,选择 Windows Offline (64-bit) 下载。

复制出来的命令必须删除 -workDir 参数的双引号,否则运行报错:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
d:\Jenkins>java -jar agent.jar -jnlpUrl http://192.168.1.100:8080/computer/XXX/jenkins-agent.jnlp -secret xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -workDir "d:\Jenkins\"
Exception in thread "main" java.io.IOException: java.nio.file.InvalidPathException: Illegal char <"> at index 10: d:\Jenkins"\remoting
        at org.jenkinsci.remoting.util.PathUtils.fileToPath(PathUtils.java:59)
        at org.jenkinsci.remoting.engine.WorkDirManager.initializeWorkDir(WorkDirManager.java:210)
        at hudson.remoting.Launcher.run(Launcher.java:321)
        at hudson.remoting.Launcher.main(Launcher.java:297)
Caused by: java.nio.file.InvalidPathException: Illegal char <"> at index 10: d:\Jenkins"\remoting
        at sun.nio.fs.WindowsPathParser.normalize(Unknown Source)
        at sun.nio.fs.WindowsPathParser.parse(Unknown Source)
        at sun.nio.fs.WindowsPathParser.parse(Unknown Source)
        at sun.nio.fs.WindowsPath.parse(Unknown Source)
        at sun.nio.fs.WindowsFileSystem.getPath(Unknown Source)
        at java.io.File.toPath(Unknown Source)
        at org.jenkinsci.remoting.util.PathUtils.fileToPath(PathUtils.java:57)
        ... 3 more

开机自启

资源管理器打开 shell:startup,然后右键拖放 JenkinsAgent.bat 到此目录中,在弹出的菜单中选择创建快捷方式,这样就可以将其添加到开机自启动中了。

构建

Job 类型选择

由于 Unity 项目通常比较大,内部有大量的美术资源需要大量时间导入。如果每次都重新克隆新仓库或者将上次导入的缓存完全清除掉,那么重新导入的时间过长,会导致打包耗时过长。

Jenkins 默认的集成仓库方式看起来很好,但是配置中的更新项要求必须完整地清理已忽略文件,可是缓存都在已忽略文件列表中,如果清理掉就会重新导入。

看起来非常有前景的将 Pipeline 脚本放在仓库里,然后每次克隆仓库获取打包指令这种方式也有上述的问题。可以说 Jenkins 主要是为了互联网行业设计的,并没有考虑游戏行业的特点。

最终决定使用自由风格的构建,然后将版本控制的更新放在 Python 脚本里面手动控制,而不是依赖于 Jenkins。而且使用自由风格的构建也可以使用内嵌的 Pipeline 来控制打包。

Pipeline

使用流水线对构建流程进行拆分细化。

按照上一篇文章 Python 整合打包 - 狂飙 定义的阶段来编写 Pipeline 脚本,基本上只是单纯地调用写好的 Python 脚本。

  1. 准备阶段
    1. 准备好打包需要的环境,例如终止上次未结束的 Unity 进程
    2. 更新仓库,清理无用文件,恢复到初始状态
  2. 导出阶段
    1. Unity 导出工程
  3. 打包阶段
    1. Gradle 打包 apk / Xcode 打包 ipa
  4. 部署阶段
    1. 部署 apk/ipa 到 FTP/CDN
    2. 部署 AssetBundle 等更新用的资源到 CDN
  5. 通知阶段
    1. 编写自定义的构建成功通知信息

插件

通知

使用通知扩展主要是为了实现任务失败时的通知,因为这时候只有 Jenkins 可以执行操作。

构建用户

使用 Jenkins 的 Build User Vars 插件通过环境变量获取触发构建的用户名字,环境变量 BUILD_USER

安装完成后需要在 配置管理 | 系统配置 | Build User Variables 中勾选 Enabled for all builds 选项,这样才能在 Pipeline 中获取此

GitLab WebHooks

通过钩子可以配置自动构建,用于排查推送的提交是否有问题。

如果添加 WebHook 时提示 Url is blocked: Requests to the lcoal anetwork are not allowed,需要在管理员面板 Admin Area | Settings | Network | Outbound requests 中启用 Allow requests to the local network from web hooks and services 选项。

添加完成后可以手动触发 Push Events,然后上方会提示 Hook executed successfully: HTTP 200