前言
在之前写过的两篇文章中(如何组好队伍刷怪
与 Android 与 Docker
)粗略提到一些可以针对团队的提高开发效率、控制开发质量的工具,例如 Nexus 仓库和持续集成(CI)服务。
之前公司的代码托管在自己搭建的 Gitlab 上,所以当时 CI 服务用的是 Gitlab CI,无需自己搭建。而新公司代码托管在 Github 上,虽然有 Travis CI 等服务,但是仅对开源仓库免费,所以还是自己搭建好些。So 我选择了 Jenkins。
二进制仓库
都搞定后,我们工程中所有二进制都使用自己搭的私有仓库进行代理了,像这样:
buildscript {
repositories {
maven {
url "${ZBD_NEXUS_REPO}/jcenter/"
}
}
dependencies {
// ...
}
}
allprojects {
repositories {
maven {
url "${ZBD_NEXUS_REPO}/jcenter/"
}
maven {
url "${ZBD_NEXUS_REPO}/jitpack.io/"
}
}
}
它带来的好处是巨大的,一来是起到缓存的作用(要知道 Jcenter 或 Maven Central 在国内的访问速度有多慢)。不管是开发者还甚至是 CI 服务,只要缓存一次,再次请求时都是用的缓存,基本上几秒钟就能同步完整个工程用的所有二进制。
二来是一些私有的二进制也能上传到仓库上。例如我们公司的项目用到并修改了 ijkplayer 库,在我来之前,他们把 ijkplayer 的代码和编译好的二进制都扔进 Git 仓库中,导致我入职时 Git 仓库已经高达 4G 大小了。。。要知道,二进制这种东西是不应该出现在代码仓库中的。
好了,现在搭了 Nexus 后,先把 ijkplayer 那 Part 的代码从主项目中移出来,然后将编译生成的二进制自动上传到 Nexus 仓库上,主项目直接从上面 Pull 编译好的二进制。

持续集成
使用 Jenkins 提供的 CI 服务也给我们的开发带来了巨大收益:自动构建新的代码变动、自动设置 Github 的 Commit Status(构建失败的 Commit 无法混合进 Dev / Master 分支)。
在 Branchs 上可以查看所有分支的构建状况:

提交的 Pull Request 需要通过构建才能进行混合:

构建失败的 Commit 是无法混合进保护分支的:

利用持续集成服务还能实现更多的功能,例如构建成功后自动上传二进制、自动发邮件通知等,它实现了真正意义的 自动化。
着手搭建
为什么用 Docker?只给你一台服务器,你能在一天内搭好所有东西么(笑?
下面的脚本记录我搭建的一些过程,其中 docker-android
是我自己写的镜像,包含以下工具和环境: Oracle Java 8 / Android Platform SDK 23 & 24 / Android Build Tools 23.0.3 & 24.0.3 / Pre-installed Gradle version 3.1
#!/bin/sh
# 此份脚本仅用于服务部署,如需进行服务迁移请使用 Docker 的容器备份功能
curl -sSL https://get.daocloud.io/docker | sh
service docker start
docker pull sonatype/nexus3
docker pull jenkins
docker pull daocloud.io/nekocode/docker-android:1.6
mkdir -p /hi/ci/android/jenkins-data
docker run -d \
-p 8081:8081 \
--name nexus \
sonatype/nexus3
docker run -d \
-u root \
-v $(which docker):/usr/bin/docker \
-v /hi/ci/android/jenkins-data/:/var/jenkins_home/workspace/ \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/lib64/libsystemd-journal.so.0:/usr/lib/x86_64-linux-gnu/libsystemd-journal.so.0 \
-v /usr/lib64/libsystemd-id128.so.0:/usr/lib/x86_64-linux-gnu/libsystemd-id128.so.0 \
-v /usr/lib64/libdevmapper.so.1.02:/usr/lib/x86_64-linux-gnu/libdevmapper.so.1.02 \
-v /usr/lib64/libgcrypt.so.11:/usr/lib/x86_64-linux-gnu/libgcrypt.so.11 \
-v /usr/lib64/libdw.so.1:/usr/lib/x86_64-linux-gnu/libdw.so.1 \
-p 8082:8080 \
--name jenkins \
jenkins
在 Jenkins 下 Android 工程我也打算使用 Docker 来构建,所以要实现 Docker in docker 的功能,于是上面的脚本在开启 Jenkins 容器时必须做些挂载设置。而 Jenkins 中构建 Android 工程的命令可以写成这样:
docker run --rm -v /hi/ci/android/jenkins-data/:/workspace -w /workspace/${JOB_NAME} daocloud.io/nekocode/docker-android:1.6 gradle clean app:assembleRelease
如果签名使用的 Keystore 密码配置放在 Properties 文件中,而且加入了 .gitignore 列表的话(这是个好习惯),可以使用类似下面的命令在构建前自动在工作目录生成需要的 Properties 文件:
echo "KEY_ALIAS=xxx\nKEYSTORE_PASSWORD=xxx\nKEY_PASSWORD=xxx" > /var/jenkins_home/workspace/${JOB_NAME}/keystore.properties
对了,要想 Jenkins 从 Github 的私有仓库成功拉下代码的话,还得为 Jenkins 生成用于访问 Github 私有仓库的 SSH 密钥对(可以自由替换下面的 projectname 字符串):
docker exec -it -u root jenkins /bin/bash
# 生成 Github Deploy Key
ssh-keygen -t rsa -f id_rsa.projectname_android
chmod 755 *
su jenkins
eval "$(ssh-agent -s)"
ssh-add id_rsa.projectname_android
# 把 Public Key 设置到 Github repository 的 Deploy Key 中就行了
cat id_rsa.projectname_android.pub
另外,要让 Jenkins 将构建状态显示到 Github Commit Status 上的话还得在个人账户上生成个 Access Token,并在 Jenkins 配置好。
