从0搭建Jenkins打包
前言
游戏开发过程中打包是一个很频繁和复杂的事。打包除了涉及资源打包流程,还涉及到APK,IPA,小游戏打包等平台分类。不同平台接入第三方SDK等库又不一样,不同渠道又有不同的SDK要接入。每次打包如果都是打开Unity的打包窗口去设置这些详细打包参数,那对于打包维护成本来说就很高。本章节就是详细深入**CI/CD(持续集成和持续交付/部署)**的实战,目标是打造易用性,易扩展维护性,支持快速持续打包部署交付的自动化打包流程。
Jenkins
从介绍可以看出Jenkins是一个免费开源的支持数百个插件用于打包,部署,自动化的自动化服务器。
以前学习了解过Jenkins的打包流程,这一次准备从0到1搭建Unity游戏开发的全自动化打包流程(包含不同打包需求,不同平台,不同渠道,不同SDK等)。
Jenkins安装
因为Jenkins是基于Java编写的,所以我们要先安装Java环境:
关于Java环境变量设置参考网上说明,最终配置好后:
后续会将Path里的全路径修改成访问JAVA_HOME的相对路径方便统一修改Java版本。
验证是否设置Java环境变量成功可以在PowerShell里输入”java -version”查看java版本信息:
搭建Jenkins自动化打包第一步安装Jenkins:
考虑到C盘硬盘容量有限,我安装到了其他盘:
为了确保后续Jenkins权限服务正常,优先选择Logon Type为Run service as local or domain user:,选择这个后需要输入本机的用户名和密码(这里的用户名和密码我尝试了各种用户名和密码好像都不对),考虑到为了避免使用现有用户名可能因为现有用户名的一些权限修改影响Jenkins运行,最终我决定新建一个用户名作为Jenkins独立使用的用户名,Win10家庭版添加用户名流程:
设置->账户->家庭和其他用户->将其他人添加到这台电脑->输入新用户名和密码
然后我们使用这个用户名和密码作为Jenkins安装的用户名,如果确认用户名密码都数对了,但还是提示Test Credential失败如下:
按照官网的说法是指定的用户名没有Logon as a service的权限解决办法
如果是家庭版Win10好像没有secpol.msc这个时候我们要使用以下方案:
How To Enable Group Policy Editor (gpedit.msc) In Windows 10 Home
经过测试上述方案命令行有报错,无法正确安装gpedit.msc,也就无法给用户名添加Logon as a service权限,最后AI的建议是先通过LocalSystem模式安装,安装完成后就能有services.msc工具,同时也能从LocalSystem指定切换用户,相当于最终又回到Run service as local or domain user的方式!
以LocalSystem安装Jenkins
设置默认Jenkins端口号到8080
设置Java SDK位置
这一步Jenkins对Java版本有要求,需要下对应版本的Java JDK
这里本人安装一个Java 21,安装完成后要将JAVA_HOME重新指向最新的Java 21目录,这样本机默认使用的才是Java 21,为了保持Java Path配置一致性顺带将Path里的路修改成%JAVA_HOME%\bin的方式:
打开PowerShell输入”java -version”测试是否配置成功:
Jenkins安装成功后我们就能在**本地服务(Ctrl+R然后输入services.msc运行)**看到Jenkins服务了,属于自动启动也就意味着开机Jenkins服务就会自动运行起来
本地服务里选中Jenkins右键->属性->登录,输入要切换的用户名和密码进行用户名切换,从而切换到前面我们无法使用的Run service as local or domain的方式:
这一步貌似直接使用现成的用户名和密码好像无法正确启动Jenkins,AI说因为我使用的账户是MicrosoftAccount账户,需要单独创建一个用户作为Jenkins的用户
创建新用户,设置->账号->家庭和其他用户->将其他人添加到这台电脑
然后我们再次去设置Jenkins服务的用户到jenkins-build这个用户并启动Jenkins服务
可以看到经历千辛万苦我们终于给Jenkins指定新用户且启动起来了。
本地测试下Jenkins是否运作正常,在浏览器输入localhost:8080进行测试
默认密码存在于C:\ProgramData\Jenkins.jenkins\secrets\initialAdminPassword我们复制输入后进入Jenkins初始化设置界面
由于第一次安装也不确定安装哪些Jenkins插件,所以这里我默认安装推荐的插件模式(安装好后进入Jenkins后续我们还能根据自己需求去自行删除和安装插件)
安装过程中会发现有大量插件安装失败:
这个我们可以后续再自行安装。
Jenkins插件安装完成后,我们需要创建我们第一个Jenkins管理员账号
接下来配置Jenkins的访问URL
完成Jenkins设置可以开始使用Jenkins了
考虑到刚才有很多插件安装失败了,所以开始Jenkins使用的第一件事就是打开Manage Jenkins进行插件安装
关于到底哪些插件安装失败了,可以打开Download progress查看到:
部分插件貌似需要重启Jenkins,但重启Jenkins的我发现又报错了:
核心原因是我们前面设置的用户jenkins-build没有对C盘jenkins目录和安装Jenkins目录(含jenkins.exe)的读写权限:
所以我们需要对这两个目录右键->属性->安全->编辑->添加jenkins-build用户(并设置对应权限)
上面为了确保jenkins-build用户权限足够,我把对应两个目录的所有权限都勾上了。
然后再次重启Jenkins会发现成功启动:
然后再次打开Jenkins Manage Plugins惊奇的发现起始之前大部分插件已经安装成功了!
在真正开始使用Jenkins之前我们先了解下Managing Jenkins和Jenkins Pipeline。
Note:
- Jenkins作为Service启动在Windows上,必须确保Jenkins服务账户拥有
Log on as a service权限 - Jenkins的安装对Windows的.NET Framwork版本也有要求,Jenkins 2.238起要求.Net Framework 4.0,之前要求.Net Framework 2.0
修改Jenkins主目录
在了解Manageing Jenkins和Jenkins Pipeline之前,我先修改Jenkins的默认工作目录(因为我的C盘硬盘不够了),默认是在**%ProgramData%\Jenkins.jenkins**路径。
迁移流程如下:
打开PowerShell(必须以管理员身份运行)输入”net stop Jenkins”将Jenkins服务停止
复制所有%ProgramData%\Jenkins.jenkins目录下的文件到新的Jenkins目录
修改Jenkins目录下的jenkins.xml里的
的value到新路径 1
<env name="JENKINS_HOME" value="G:\Software\JenkinsHome"/>
打开PowerShell(必须以管理员身份运行)输入”net start Jenkins”将Jenkins服务开启
然后再次在页面上打开jenkins的Manage Jenkins配置可以看到Jenkins的工作目录已经切换到我们的新目录了
注意给新的Jenkins目录添加jenkins-build等使用用户的操作权限(这一步请先停止jenkins服务先,如果有部分文件权限修改报错如果能正常启起来Jenkins可以先不管,AI说是有写保护文件无法添加完全控制权限)
至此我们成功切换了Jenkins的工作目录,再也不用担心Jenkins的使用让我的C盘不够用了。
Managing Jenkins
打开Jenkins,点击Manage Jenkins我们会看到Jenkins的管理界面:
接下来分别理解下这个页面上的各个入口是做什么的。
System Configuration
系统配置
给Jenkins Controller配置全局设置和路径
比如配置Jenkins主目录,Jenkins URL,系统管理员邮箱等
目前我只添加了一个系统管理员邮件地址
全局工具配置
工具配置,包括它们的位置和自动化安装器
插件管理
添加,删除,禁用或启用Jenkins功能扩展插件
推荐把Jenkins推荐安装的插件都先安了,方便后续直接开工搭建自动化打包流程
节点和云管理
添加,删除,控制和监视系统运行任务的节点
这里我们需要深入理解下Jenkins的几个概念Controller,Nodes,Agents,Executors
Controller
从介绍来看,Jenkins Controller是Jenkins本身,是作为一个总管理者和调度中心的角色存在,比如管理任务调度,任务配置,任务权限等。
Nodes
从介绍来看,Jenkins Nodes是构建机器,Jenkins负责管理这些构建机器的磁盘空间,系统时间,磁盘释放等。
Jenkins Nodes分为一下两种:
agents
build-in node
build-in node好像是Controller里默认的一个节点,从安全,性能,可扩展性等方面来说官方不建议直接使用build-in node
我想这就是为什么我在Manage Jenkins页面看到以下警告的原因:
Agents
Agents manage the task execution on behalf of the Jenkins controller by using executors.
从介绍看,Agents是通过使用Executors帮Controllers管理任务执行的。
Executors
从介绍看,Excecutor是真正执行任务的执行者,agent有多少个executor就表示能同时执行多少个任务。
官方建议如下:
- One executor per node is the safest configuration.(一个node最安全的配置是一个executor)
- One executor per CPU core can work well, if the tasks running are small.(一个executor对应一个CPU core工作最好)
- Monitor I/O performance, CPU load, memory usage, and I/O throughput carefully when running multiple executors on a node.(如果一个node运行多个executor需要注意I/O,CPU负载,内存使用等情况)
通过上面的介绍,可以看出当我们搭建CI/CD工作流的时候,为了安全,性能和可扩展性最好不要直接使用Build-in node,我们应该去创建我们自己的Agent去针对性配置。
Clouds
添加,移除,配置远端提供Agent能力的实例
Appearance
配置Jenkins外观样子
Security
Security
保护Jenkins,配置谁被允许访问和使用Jenkins系统
这里有一项关于Git验证方式的配置Host Key Verification Strategy有以下几个选项:
Know hosts file(default)
使用.ssh\known_hosts文件进行验证(我们单独给Jenkins配置了jenkins-build用户,所以这个文件可能压根没有,也就是后续我们添加了SSH Credential后依然无法正常访问Git SSH地址的原因)
Accept first connection
第一次连接时接受并记录GitHub提供的Host Key,后续Host Key变化时拒绝连接。
Manually provided keys
利用手动添加到这里的Host key进行验证(后续为了避免不同WIndows用户名的SSH配置问题,这里会采用这个方案)
No verification(not recommended)
不验证Host Key
Credentials
配置证书相关
这里用于全局存放打包相关证书的地方,Agent Pipeline里通过全局变量访问,不要把证书信息直接写进Agent打包流程里!
Credential Providers
配置证书提供者和类型
Users
创建,删除,修改可以登录到Jenkins的用户信息
Status Information
系统信息
显示系统环境信息
系统日志
所有Jenkins通过java.util.loggins捕获到的日志信息
负载统计
显示Jenkins的资源使用情况
About Jenkins
查看Jenkins的版本和许可证信息
Jenkins Pipeline
在真正开始使用Jenkins之前我们先了解下Jenkins Pipeline,。
这里直接搬运下以前Jenkins Pipeline的学习记录。
什么是Pipeline
Jenkins Pipeline is a suite of plugins which supports implementing and integrating continuous delivery pipelines into Jenkins. Pipeline provides an extensible set of tools for modeling simple-to-complex delivery pipelines “as code”.(这里的Pipeline是一套插件,用于支持持续自动化集成编写。好比脚本文件定义一系列的自动化流程,但并不等价于脚本。)
那么Pipeline是用什么语言编写了?
Jenkins是基于Java的,Pipeline的编写是基于Groovy。
Groovy是Java平台上设计的面向对象编程语言。这门动态语言拥有类似Python、Ruby和Smalltalk中的一些特性,可以作为Java平台的脚本语言使用。
这里了解几个Pipeline的概念Node,Stage,Step:
Node
这个就是前面讲到的Node概念,用于运行Pipeline的Node
Stage
Stage是将Pipeline细分成几个任务流程(比如Build,Test,Deploy)
Step
Step是运行任务的最小单位,是告诉Jenkins在什么时间点执行什么的任务步骤,比如执行指定shell命令或者python脚本
为什么要Pipeline
为什么需要Pipeline?
- Code – 可管理可编辑可视化的自动化流程脚本
- Durable – 可持续化开发
- Pausable – 可以自动也可以停止等待输入
- Versatile – 支持复杂的持续交付需求
- Extensible – “The Pipeline plugin supports custom extensions to its DSL [5: Domain-Specific
Language] and multiple options for integration with other plugins.”(支持DSL语言的自定义扩展)
如何使用Pipeline
接下来让我们看看如何创建一个Pipeline。
首先我们必须安装Pipeline插件(这一步在安装推荐插件的时候完成了,没安装的可以去Manage Plugins的插件管理界面自行安装)
关于创建Pipeline有两种方式:
- Through the classic UI(Jenkins提供的UI操作)
- In SCM(可以直接手动编写Jenkinsfile文件)
前者生成的Jenkinsfile文件在Jenkins的目录,后者的好处是可以打包流水线流程可以直接进入Git版本管理,就算电脑出问题了Jenkins的流水线也不会丢。
这里我们先了解几个Pipeline里编写的几个大的概念:
- Node(这个就是我们创建Agent对应的Node概念,在Jenkinsfile里表示指定流程可动态申请一个Executor执行,并在node流程块执行完后释放)
- environment(表示当前Pipeline流程里可全局访问的环境变量)
- parameters(表示Pipeline流程里可以通过页面配置显示的参数数据)
- Stage(定义一个流程块,包含一系列相关任务,比如Build,Test,Deploy等流程块
- Step(单个任务步骤,包含具体的任务执行)
- post (支持在特定step后指定运行状态下执行特定操作,比如将我们打包产物归档)
Pipeline工具
Snippet Generator
这是一个很有用帮助快速编写Pipeline的工具,他可以帮助我们把我们熟悉的自动化脚本转换成Pipeline格式的语句,也可以快速生成一些特定功能的脚本(比如邮件功能等)。(Jenkins提供)
脚本命令行(Jenkins->Manage Jenkins->脚本命令行)
可以进行Jenkins代码编写和快速测试!
比如访问所有node并打印node名字:
1 | Jenkins.get().nodes.each { node -> |
Unity打包CI/CD+Pipeline实战
系统配置
有些配置(比如磁盘监控警告限制配置,管理员通知邮箱)不归属单个Agent而是全局生效的
全局工具配置
有些东西是属于所有Agent都要统一使用的工具(比如Git,JDK,Gradle等),这些东西应该配置在全局而非但Agent里。
为了明确给Jenkins指定Git使用还是配置上路径避免用默认的。
比如配置Git:
Manage Plugins->全局工具配置->Git installations
如果不确定本地安装Git位置,可以打开cmd输入where git查看
如果不配置Git将会使用系统默认能找到的Git
如果发现配置了全局Git,但打包日志里依然有”Selected Git installation does not exist. Using Default. The recommended git tool is:None”日志,但Git.exe工具拉去地址后续又显示正确可以先不管,具体原因不明但功能看起来正常。
配置全局Git后发现打包Git拉取报错如下:
这是因为我们给Jenkins创建的jenkins-build用于没有配置过Git相关的.ssh配置,所以默认访问了SSH 22端口。
那为什么用默认的Git没报错?
AI给出的回答是我们创建的Agent是在TonyTang用户名下通过bat运行的,所以能读取到TonyTang\.ssh\config的配置,所以读取了443端口。(不确定是否是这个原因)
TonyTang\.ssh\config内容如下:
1 | Host github.com |
总之我们给Pipeline配置Git地址时,准确写明是使用443端口即可:
原本Git地址:
1 | git@github.com:TonyTang1990/UnityNativeFramework.git |
修改到SSH 443端口后Git地址:
1 | ssh://git@ssh.github.com:443/TonyTang1990/UnityNativeFramework.git |
主动配置SSH 443的Git地址时,全局Security的git的Host Keys也要配置成对应的包含ssh和443端口的地址:
Note:
- Unity打包自带下载了JDK,NDK,Gradle,所以一般Agent要使用对应的JDK,NDK而非全局配置的。
Security
这里重点讲一下前面提到的关于Git Host Key Verification Stratefy(Git Host Key验证策略)配置,这里为了避免不同Windows用户带来的SSH访问验证问题,这里选择Manually provided keys策略:
这里我们将我们访问Git的**Host Key(注意不是SSH的公钥)**配置上即可。
具体Git的Host Key值是哪一个在这里查看:
选择符合加密方式的那个key fingerprints即可,这里我用的是ED25519算法,所以Host key为:
1 | github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl |
Credentials
像重要的一些比如打包Keystore,Apple证书,Git SSH用户名秘钥等都不要直接配置在Agent里,避免泄露,这些东西都统一配置在全局Credentials里,然后Agent里指向使用。
这里简单了解下Jenkins添加Credentials的方式类型:
- Secret Text(比如API token或者GitHub个人访问token)
- Username and password(比如配置用户名和密码,格式”用户名:密码”)
- Secret file(包含Secret内容的文件)
- SSH Username with private key(SSH链接包含用户名和私有Key,适用于Github SSH链接时的授权)
- Certificate(某些证书文件,暂时不清楚具体用处)
- Docker Host Certificate Authentication(Docker的证书授权)
每一个在Jenkins Credential里配置的Credential都有一个Credential ID,我们通过Credential ID可以在Jenkinsfile里访问
添加SSH Credential
这里我首先添加我的Git证书,考虑到用SSH访问,这里添加SSH username with private key的方式:
Jenkins->Manage Jenkins->Credentials->Add Credentials
给SSH username with private key配置生效范围和访问ID:
这里考虑到为了方便范围就配成Global,ID根据自己需求取一个唯一值后续会在Jenkinsfile里使用访问Credential,关于Github如何生成SSH Key这个自行搜索了解下。
SSH Key默认是在C:\\User\\用户名\.ssh\目录下的,要求填的密码是创建私钥时的一个密码,如果忘记密码可以在改目录下输入以下命令”ssh-keygen -y -f 私钥文件”进行尝试。
添加Github SSH的时候注意Username要填写git(AI说的具体不确定是不是必须)
添加完成后就能看到Jenkins->Manage Jenkins->Credentials下方出现我们配置的Credential了:
在Jenkinsfile里访问Credential:
1 | credentials('***') |
上面的配置是配置了SSH Credential的相关信息,但并不保证我们新建Windows的jenkins-build用户就能正确使用,因为我之前是在TonyTang这个用户下工作,所以所有的git SSH key相关都是操作保存在C:\\User\\TonyTang\\.ssh目录下的,现在Jenkins以jenkins-build用户在工作,默认全局的Security的Host Key Verification Stratety(Git的验证策略配置)是Known hosts file,也就是使用C:\\User\\USER_NAME\.ssh目录下的known_hosts文件进行验证。所以我们前面Credentials需要将Security的Host Key Verification Stratety修改成SSH Username with private key。
配置Git Host Key Verification Configuration的Manually provideed keys时注意要把http和ssh访问git的Host Keys都添加上。
创建Agent
结合前面提到的官方不建议使用默认的build-in Node,所以我们首先要先创建我们自己的Agent,打开Jenkins主页->Set up an agent:
接下来分别讲讲创建Agent里的各个参数的含义。
名字(Agent的唯一Id)
比如我的项目名称是UnityNativeFramework,所以我创建的Agent名称叫UnityNativeFrameworkBuild
描述(Agent的一个文本描述)
Number of executors(Agent拥有多少的Executors,官方建议1个Agent对应1个Executor最佳)
远程工作目录(Agent所在工作目录,不要放到JENKINS_HOME下)
标签(用于Pipeline指定Agent Lable时的识别标签,符合相同标签的可以被公用,比如多个工程同一个项目建了多个Agent,指定相同的标签能自动利用空闲Agent触发打包)
用法(限定节点的使用方式)
启动方式(限定Agent的启动方式)
可用性(限定Agent的可用状态)
关于节点属性选项:
Disable deferred wipeout on this node
来至Workspace Cleanup插件,用于删除整个Workspace时采用延迟擦除的方式优化速度(不推荐勾选,避免一些奇怪的问题)
Disk Space Monitoring Thresholds
用于设置该Agent的磁盘空间阈值,避免特定硬盘空间情况可以发出警告或直接终止打包(推荐勾选,设置合理阈值)
Enviroment variables
配置只运行在当前Agent的一些环境变量数据,比如Unity.exe路径,后续Pipeline里编写时可以通过%*%访问环境变量值,这里不要放证书相关数据,证书相关放到配置Security的Credentials里(推荐勾选,按需设置必要的环境变量)
Tool Locations
用于覆盖 Jenkins全局工具在这个Node上的实际安装位置。(不推荐勾选,,当前Agent和全局Controller配置工具没有特殊情况都使用统一的,比如Git使用统一配置)
最终设置结果:
Note:
- Agent的远程工作目录不要放到JENKINS_HOME
- 一个Agent推荐1个Executor,这是官方建议最稳妥的方式,避免一些I/O,CPU或内存的负载问题
- 新建一个统一放Jenkins Agent的目录,记着把该目录的修改权限添加给jenkins-build用户
- 标签里的名字默认不能与Agent名同名,因为默认Jenkinsfile里就能用Agent名字指定特定Agent
启动Agent
创建完成后会发现我们新建的Unity NativeFrameworkBuild还处于离线状态:
这是因为我们只是保存了Agent配置,Agent进程还没启动。
点击UnityNativeFrameworkBuild的Agent名字,点击状态,我们会看到启动Agent的办法:
多行命令复制粘贴到PowerShell会有问题,需要自己一行一行的复制执行:
可以看到我们成功启动了我们新建的UnityNativeFrameworkBuild的Agent:
我们新建的Agent的启动方式之前设置的是Launch agent by connecting it to the controller,为了避免每次重启电脑我们自己创建的Agent都要重新执行命令启动,我们需要利用WinSW将长期Unity构建的Jenkins Agent注册为Windows服务,考虑到注册服务也挺麻烦的,这里暂时将启动命令做成start-UnityNavitveFrameworkBuild-agent.bat运行:
1 | @echo off |
Note:
- 如果不想每个Agent都独立注册Windows服务,可以选择Luanch agent via SSH的方式,配置好SSH Server和SSH Key让所有Agent一次性自动全启动
- bat启动这个方式目前的bat代码是窗口关闭Agent就断开连接离线
搭建打包流程
搭建打包流程前,我们需要深入理解一个概念Pipeline,详情参考前面的介绍。
Jenkins搭建打包流程只要通过定义Pipeline,Pipeline有两种方式定义:
通过网页可视化界面
这种方式生成的Jenkinsfile默认在JENKINS_HOME文件夹下,不方便可视化+版本管理
手写Jenkinsfile文件
这种方式好处是可以提交版本管理,同一个项目多个Agent可以快速重用同一个Agent,不同考虑Jenkinsfile流程同步问题
创建Pipeline
创建Jenkinsfile流程如何:
确保Pipeline插件安装好
New Item – 新建Pipeline(选择Pipeline类型)
Configure Pipeline
这里简单讲几个重要的基础配置含义:
Discard old builds(丢弃旧的构建,用于自动丢弃时长过久的构建,确保硬盘空间够)
为了避免构建的包被意外清除,不推荐勾选
Do not allow concurrent builds(多个构建发起时的响应策略,用于确保不会同时并发执行多个构建或者后一个覆盖前一个构建等设置)
一般来说单个Unity工程只允许启动一个Batch mode打包,推荐勾选
Do not allow the pipeline to resume if the controller restarts(是否不允许Pipeline在controller重启后继续)
一般来说打包流水线必须要完整执行才不容易出问题,推荐勾选
GitHub project(用于关联一个Github项目URL,为部分插件提供上下文)
一般来说项目打包都是走自己的Git操作流程,不推荐勾选
This project is parameterized(这个项目是否允许参数配置化打包)
参数配置化打包也就是Jenkins里常见的页面可视化参数配置,然后打包时传入Unity进行对应打包参数控制,推荐勾上
这里简单讲几个重要触发时机配置介绍:
Build after other projects are build(是否在其他工程打包完成后自动触发打包)
适用于多个打包流程顺序合作构建的情况,目前Untiy打包暂时不需要,不推荐勾选
Build periodically(固定间隔时间或者固定时间自动构建)
主要用于每隔一段时间自动触发构建进行连续打包测试跟进
Unity开发过程中提交情况比较复杂,每隔一段时间打包很可能出现提交不完全导致打包失败等情况,建议还是自己主动找合适时机触发打包,不推荐勾选
关于Pipeline的详细配置介绍:
- 定义选择Pipeline script form SCM而非Pipeline script(因为我们打算走本地jenkinsfile的方式而非网页可视化配置界面)
- SCM类型选择Git,目前我使用的是Git,Jenkins显示支持的选项也只有Git,其他方式估计要安装对应插件
- Repository URL(jenkinsfile文件所在git地址,一般来说jenkinsfile文件都是放到Git项目根目录)
- Credentials(Git地址访问权限证书,这个也就是我们需要配置Git证书之后才能选择的了,证书添加参考前面的Credentials)
最终Pipeline创建配置如下:
Pipeline打包
No Jenkinsfile打包报错
我们直接点击Build Now会发现没有打包参数界面直接就开始打包并报错:
这是因为我们选择了SCM Jenkinsfile的方式,但我们还没有自己在仓库根目录创建Jenkinsfile文件上传导致的,所以我们需要在Git仓库下方自己创建Jenkinsfile并编写内容上传。
Jenkinsfile编写
Jenkinsfile初版内容如下:
1 | pipeline { |
Jenkinsfile负责编写打包流程,将所有打包流程串联起来。
Jenkins将可视化配置的打包参数一个一个传递给BatchBuildAndroid.py打包脚本打包。
Note:
打包脚本编写
BatchBuildAndroid.py
1 | #!/usr/bin/env python3 |
BatchBuildAndroid.py脚本负责接收Jenkins打包传过来的参数并解析,然后利用Unity Batch Build模式将Unity启动起来触发打包并将打包参数传递进打包代码。
Git SSH访问报错
上传Jenkinsfile后再次打包会发现依然打包报错:
这是因为我们配置Git Host Key的Host Keys只添加了支持http访问的Host Key而没有添加SSH访问的Host Key,按照前面添加SSH Credential的方式添加上后,我们再次打开新建的Agent会看到Jenkins的参数配置界面显示出来了:
打包CS脚本传漏报错
修改SSH访问的Host Key后我们再次触发打包:
发现依然打包失败,但我们打包流程里无论是Jenkins的打印输出还是BatchBuildAndroid.py里的打印输出都成功打印了,从日志可以看到我们触发了Unity Batch Mode打包,但过了一会就打包失败了,这里是因为我忘记上传打包相关脚本了,Git仓库上根本没有BuildTool.DoBuiuldFromCommands的代码文件。
Jenkins没输出Unity日志问题
原因如下:
Unity Batch Mode运行模式需要添加**-logFile -**参数,表示将将日志输出到控制台。
通过Jenkins->cmd.exe->Python->Untiy这个打包流程后,Unity没能正确得到能写入的stdout
方案:
- 我们需要再Python里显示去获取Unity日志并转发打印到Jenkins控制台
通过在打包脚本BatchBuildAndroid.py里添加以下代码,将
1 | process = subprocess.Popen( |
Unity中文日志乱码问题
原因如下:
- Windows控制台,Python,Jenkins使用的字符编码不一致造成的。
方案:
- 在打包流程脚本里统一字符编码格式
Jenkinsfile(统一Jenkins bat的字符编码到UTF-8,并将Python输入输出指定为UTF-8)
1 | bat ''' |
BatchBuildAndroid.py(确保Python保持UTF-8解码)
1 | process = subprocess.Popen( |
打包成功
上传打包文件后再次触发Jenkins打包:
可以看到我们终于正确触发Unity Batch Mode打包并打包成功:
最后在JenkinsAgent对应Agent和Pipeline目录下找到了打包输出的APK文件:
安装运行成功:
上述打包流程相关配置和代码暂时只处理了三个打包参数配置(IsDevelopment,VersionCode,ResourceVersionCode)后续更多参数配置扩展Jenkinsfile和打包相关脚本即可。
Pipeline打包归档
Pipeline打包归档是指我们打包生成的APK等产物,默认生成在JenkinsAgent对应Agent对应Pipeline项目工程下的特定位置,这种位置会受项目Git拉取,Jenkins清理工作区等操作影响。所以最好的方式就是Jenkins打包的最终产物统一放到一个独立长期保存的位置,这个就是Pipeline打包归档。
设置好打包归档后我们能在Jenkins对应Pipeline页面点击Build Artifacts里找到所有打包产物。
归档后的存储位置在%JENKINS_HOME%\jobs\任务名\builds\构件编号\archive路径下。
可以看到打包成功后Jenkins成功将打包产物符合的文件全部归档到了%JENKINS_HOME%目录对应目录下。
Note:
- 归档成功后没在Jenkins页面看到相关入口,原因不明
多Agent多Pipeline打包
之前我们只创建了一个UnityNativeFrameworkBuild Agent(只有1个Executor),但我们却创建了2个指定Agent Lable是UnityNativeFrameworkBuild的Pipeline,如果我们同时触发这2个Pipeline打包会发生什么?
答案是排队等待。
还记着我们之前给Pipeline设置的禁止并发打包吗?
创建的Agent只有1个Executor且禁止并发打包,这就是为什么2个Pipeline触发打包会排队等待的原因。
解决方案:
创建多个可用的Agent并启起来,2个Pipeline指向的Agent Lable多个Agent都符合,那么就会选空闲的Agent的executor进行打包。
为了快速创建相似的Agent,我们可以通过Jenkins->Manage Jenkins->Nodes->New Node->复制现有节点:
取名UnityNativeFrameworkBuild2
编写启动UnityNativeFrameworkBuild2的Agent的start-UnityNavitveFrameworkBuild2-agent.bat:
1 | @echo off |
启动后新Agent就可用了。
这是我们再次同时触发2个Pipeline打包会发现,2个Agent都同时运作起来,2个Pipeline也同时开始了打包流程:
Note:
- 复制Agent时远程目录记着要配套修改,不然就指向同一个远程目录了。

