月度归档:2016年11月

macOS 安装配置 Jenkins 持续集成 Unity 项目指南

安装 Java 和 JDK

由于 Jenkins 是一个基于 Java 实现的项目,所以我们需要先确保我们的 macOS 上安装有 Java,直接从 Oracle 的 官方网站 上下载安装即可。

安装完成之后,理论上咱们就可以安装 Jenkins 了,但是考虑到咱们实际上使用 Jenkins 来进行持续集成的目的是让其自动将 Unity 工程打包成 Android 平台和 iOS 平台的安装包,而 Android 工程的编译又依赖于 JDK,所以我们还需要安装一个 JDK,同理也可以直接从 Orcale 的 官方网站 上下载后安装。

安装完成之后在命令行终端中输入一下 java -version 命令,输出内容类似:

java version “1.8.0_91”
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)

安装 Jenkins

从 Jenkins 官网 下载适用 macOS(截止写这篇文章的时候,Jenkins 官网上依然写的是 Mac OS X)的 pkg 文件,我下载的是 LTS 版本 2.19.2。双击一步一步安装完成即可,安装完成之后执行一下 defaults read /Library/Preferences/org.jenkins-ci 命令,输出内容如下:

{
“JENKINS_HOME” = “/Users/Shared/Jenkins/Home”;
heapSize = 512m;
httpListenAddress = “192.168.200.99”;
httpPort = 8080;
minHeapSize = 256m;
minPermGen = 256m;
permGen = 512m;
tmpdir = “/Users/Shared/Jenkins/tmp”;
}

这个就是 Jenkins 的各项启动参数,从以上输出的参数就得到了 Jenkins 的后台管理页面的地址:http://192.168.200.99:8080 ,在浏览器中输入该地址之后应该能看到如下的页面:
jenkins_dashboard

当然默认肯定是没有任何构建项目的,截图中已有的 3 个项目是我添加的,到这一步就意味着我们已经将 Jenkins 安装好了,而且使用 pkg 文件安装的方式会帮我们把 macOS 开机自启动 Jenkins 服务的工作都做好,省去了自己去折腾 LaunchDaemons 相关的各种配置的麻烦,不过也有其他的问题,咱们一个个来解决。接下来,我们需要安装一些插件,或者更新一些插件。

安装 Git 插件

通过 Jenkins Dashboard 页面中系统管理菜单项进入 Jenkins 管理页面,点击管理插件选项即可进入插件管理页面,找到在右上方的过滤输入栏中输入 Git 筛选一下跟 Git 相关的插件,找到自己需要的插件勾选,然后点击安装即可,等插件下载安装完成之后,按照页面的提示可以重启一下 Jenkins 让这些新安装的插件生效。

设置 Credentials

由于我们团队使用 Git 对 Unity 项目进行版本管理,所以我们需要设置一个 Credentials 能让 Jenkins 中的 Git 插件可以用来与 Git 服务器进行验证和交互。还是通过 Jenkins Dashboard 页面的 Credentials 菜单项进入管理页面,然后新建一个 Credentials,我选择的是 SSH Username with private key 的方式,输入 Username(例如安装 Jenkins 的机器当前登录的用户名为 developer,那么就填入 developer),Private Key 选择 Enter directly(因为其他的两个方式不知道 Jenkins master 具体指的是啥,也没有帮助没有设置成功,最终只能选择直接输入 private key 的方式了),确保当前登录的用户目录下有 .ssh 目录并且已经有 id_rsa 和 id_rsa.pub 文件(如果没有的话,通过 ssh-keygen 生成一个 SSH 的密钥对吧),然后在终端中执行一下 cat ~/.ssh/id_rsa 命令,把输出的内容全部拷贝,粘贴到 Jenkins 的 Private Key 设置输入框中,保存即可。

注意:~/.ssh 目录下的 id_rsa.pub 应该已经被添加到 Git 服务器信任的公钥列表中,例如我们团队中使用的是自己搭建的 GitLab 服务,那么就需要将 id_rsa.pub 中的内容通过 Profile Settings -> SSH Keys 设置页面,将这个 SSH Key 添加到账户的 Profile 中,这样 Jenkins 在使用 Git 拉取代码的时候才能验证成功。

修改用于 Jenkins 服务启动的用户和组

由于 Unity Editor 的限制,如果要在 Jenkins 中调用 Unity Editor 提供的命令行执行 BuildPlayer 方法来完成构建任务的话,必须要通过用户名和密码登入 macOS 系统后再执行构建任务才能正常调用 Unity Editor 的命令行,否则整个构建任务会一直 Hang 住。

这个是在经历了各种各样的坑之后才总结出来的,例如我曾经经历过 Mac 电脑自动更新后重启,未主动输入用户密码登录系统,通过浏览器可以其他电脑上访问 Jenkins Dashboard 并且能查看到所有构建任务的状态,可是所有的构建任务永远都不会完成。这个就是因为 Jenkins 默认在系统启动之后就自动启动了,感谢 LaunchDaemons,所以可以访问 Jenkins Dashboard 页面。但是由于未成功登录账号,Unity Editor 无法正常执行其提供的命令行,最终所有的构建任务全 Hang 住了,通过 GUI 登入用户账号之后恢复正常(通过 Remote Desktop 输入用户的密码登入也行,但是必须登入用户账号)。

这个问题我的理解是这样的,由于 Unity Editor 是在当前登入的用户(developer:wheel)下安装的,所以通过 Jenkins 调用 Unity Editor 的命令行也需要使用当前登入的用户来调用,才有权限能执行 Untiy Editor 的命令行。然而通过 pkg 文件的方式安装的 Jenkins 会自动创建一个名为 jenkins 的用户,所在组也是 jenkins。在 jenkins 用户空间中执行的 Jenkins 服务再调用 Unity Editor 的命令行肯定也是在 jenkins:jenkins 用户空间下执行的,而 jenkins 用户组应该是没有权限调用 Unity Editor 的命令行,所以出现了上面提到的整个构建任务 Hang 住的情况。

如果在通过 pkg 文件安装了 Jenkins 之后不做任何调整,直接配置好构建任务,然后点击 Build Now 直接开始构建,我们会发现前面拉取代码的流程都是正常的,但是 Unity 的图标却一直不显示在 macOS 的桌面 Docker 栏上(我们知道虽然调用 Unity Editor 的命令行不会显示 Unity Editor 的窗口,但是在 Docker 栏上还是会显示 Unity 的图标的,这个我们可以直接执行一下 /Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -quit -projectPath [Unity 工程路径] -executeMethod [public 的 static 无参方法] 命令来验证一下,详细可以参考 Unity 的命令行使用方法官方文档),所以我们可以确认 Unity Editor 的命令行压根就没有执行,接下来我们就要做些调整来让 Jenkins 成功构建 Unity 工程。

1. 修改 LaunchDaemons 目录下 Jenkins 启动配置 plist 文件

执行 sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist 命令,先将安装完之后默认自动启动的 Jenkins 服务关掉,然后使用文本编辑器打开 /Library/LaunchDaemons/org.jenkins-ci.plist 文件,找到 <key>GroupName</key> 将其下方一行中的 <string>daemon</string> 修改为 <string>wheel</string>,找到 <key>UserName</key> 将其下方一行中的 <string>jenkins</string> 修改为 <string>developer</string>,然后保存该文件。

由于我们没有修改 /Library/LaunchDaemons/org.jenkins-ci.plist 文件中 JENKINS_HOME 的配置,也没有修改 /Library/Preferences/org.jenkins-ci.plist 文件中 JENKINS_HOME 的默认配置,所以目前 Jenkins 还是会使用 /Users/Shared/Jenkins/Home 作为其主目录,使用 /Users/Shared/Jenkins/tmp 作为其临时目录,Jenkins 的日志将会输出到 /var/log/jenkins/jenkins.log 文件。

这些目录和文件在 Jenkins 安装成功之后就都创建出来了,并且都是使用 jenkins:jenkins 用户创建的,但是由于上面我们提到的问题,我们现在需要使用 developer:wheel 这个用户来启动 Jenkins,也就意味着我们需要把 Jenkins 可能用到的所有目录和文件的所有者修改为 developer:wheel 用户,这样 Jenkins 启动的时候才不会出现问题。所以我们需要依次执行以下命令:
sudo chown -R developer:wheel /Users/Shared/Jenkins
sudo chown -R developer:wheel /var/log/jenkins
将相关的目录和文件的归属修改为 developer:wheel 用户,然后再执行一下 sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist 命令,启动 Jenkins 服务,然后在浏览器中输入一下 http://192.168.200.99:8080 测试一下。

2. 疑难杂症

如果按照以上的流程进行操作出现了问题,这当然是很有可能的,毕竟每个人的电脑的软硬件环境各不相同,这里就把我自己遇到的一些问题罗列一下,以供参考。

  • 用于启动 Jenkins 的用户跟安装 Unity 的用户不是同一个,导致在 Jenkins 中正确配置了所有的参数后,无法正常编译 Unity 工程,这个问题需要我们保证 Jenkins 跟 Unity 是在同一个用户空间下运行的,详细方法见上一步;
  • 按照上述的步骤安装和设置好了 Jenkins 之后依然无法启动,那么可以尝试查看一下 /var/log/jenkins/jenkins.log 文件中的日志信息,如果启动出错的话,通常错误日志以及相关的异常信息都会输出到这里的,但是如果你看到 jenkins.log 文件中有类似 logfile turned over 之类的字眼的时候,先把 Jenkins 服务关闭,然后把整个 /var/log/jenkins 目录删了再自己手动创建一个 jenkins 目录,在新建的 jenkins 目录下创建一个 jenkins.log 文件,再重新启动 Jenkins 服务就好了;
  • 如果想调整 Jenkins 启动的参数,例如日志文件的位置和 Jenkins 的 Home 目录等等,咱们可以通过文本编辑器编辑 /Library/LaunchDaemons/org.jenkins-ci.plist 文本文件,或者通过 defaults 命令修改 /Library/Preferences/org.jenkins-ci.plist 这个加密的配置文件,详细的教程可以参考 Jenkins 的官方 Wiki。记住这两个文件是有区别的哦,别使用 defaults 命令去修改 /Library/LaunchDaemons/org.jenkins-ci.plist 这个文件哦,否则这个文件被改成加密的 plist 文件后(使用 defaults 命令行貌似编辑后的 plist 文件貌似都是加密的),launchctl 不认识了就得重装 jenkins 了,如果怕操作出错可以在编辑前先备份一下这个文件。