Androidアプリ開発向けの横断CI環境
段 文楓
こんにちは、スマートデバイス基盤チームの段です。
スマートデバイス基盤チームでは、リクルートライフスタイルのスマホアプリ開発における開発標準・品質指標の策定、新技術の検証及び横断推進、また、可視化及びCIシステムの運用改善など横断ミッションを担っています。
継続的インテグレーション(CI)はアプリ開発プロセスにおける重要な一環で、そのシステム運用改善を横断チームで実施するか各サービス側で実施するかの選択肢があると思いますが、弊社ではスマートデバイス基盤チームが担当しています。日頃の安定運用も勿論ですが、サービス側要件の柔軟対応、CIノウハウの属人化回避、運用工数削減などを意識した改善活動を積極的に行っています。
本記事では、現在運用しているAndroid向けのCI環境をご紹介します。
全体構成
- ビルド処理〜配布はジョブ毎にDockerコンテナで実施
- Jenkins Pipelineを導入し、コードベースでジョブ管理する
- Github、Slack、Deploygate、SonarQubeなどとの外部連携
機能拡張する為に多くのPluginを導入
機能拡張する為のPluginが多数存在することはJenkinsの大きな特徴で、現在導入されている一部のPluginも紹介させていただきます。各Pluginの機能をより詳細に知りたい方はJenkins Pluginsをご参照ください。
1. 静的解析
Plugin | 機能概要 |
---|---|
Static Analysis Collector | 静的解析の結果を表示 |
Dashboard View | ダッシュボードビュー、Static Analysis Collectorの結果もジョブを跨いだ表示が可能 |
JaCoCo | コードカバレッジレポート |
Checkstyle | コーディング規約チェック |
FindBugs | 不具合が発生しそうなコードの検出 |
2. 外部連携
Plugin | 機能概要 |
---|---|
Slack Notification | ビルド関連の通知をSlackに送信する |
Google Play Android Publisher | Google PlayにビルドできたAPKをアップロードする |
Google OAuth Credentials | Google APIsを利用する為のOAuth認証機能を提供 |
Nexus Artifact Uploader | Nexus連携 |
3. Jenkins画面のカスタマイズ
Plugin | 機能概要 |
---|---|
Build Trigger Badge | ビルド履歴にトリガーをアイコンで分別できるようにする |
categorized-view | 大量ジョブがある場合、ジョブのグルーピングすることが可能 |
View Job Filters | ジョブのフィルタ機能を提供、条件指定して特定ステータスのジョブビューを作成可能 |
Simple Theme | トップバーの色設定など見た目の変更 |
Job Configuration History | ジョブごとのJenkinsの設定変更履歴を確認可能にする |
Sidebar Link | Jenkinsのサイドバーにリンク追加可能にする |
ビルド処理に利用するDockerイメージを用意
アプリビルドするための基本的な環境をDockerイメージとして用意し、サービス側で利用及び拡張できるようにしています。また、イメージの作成/最新化もJenkinsジョブとして登録していて、ジョブ実行するだけでできるようになっています。
Dockerfileの内部処理(一部抜粋)
1. Java実行環境のインストール
1
2
3
4
5
6
7
8
9
10
11
RUN \
# Oracle JDK8
wget -O jdk.tar.gz --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" \
http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.tar.gz && \
tar zxf jdk.tar.gz && rm jdk.tar.gz && \
ln -s /opt/jdk1.8.0_161 /opt/oraclejdk8 && \
# Maven 3.3
wget -O maven.tar.gz http://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz && \
tar zxf maven.tar.gz && rm maven.tar.gz && \
ln -s /opt/apache-maven-3.3.9 /opt/maven-3.3 && \
chmod -R 755 /opt/*
2. emulator起動に必要なライブラリ群のインストール
1
2
3
4
5
6
7
8
9
10
11
RUN \
dpkg --add-architecture i386 && \
apt-get update && \
apt-get install -y --force-yes libc6-i386 lib32stdc++6 lib32gcc1 lib32ncurses5 lib32z1 libqt5widgets5 && \
libpulse0 && \
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* /var/cache/debconf/*-old
RUN \
apt-get update && \
apt-get -y --no-install-recommends install imagemagick && \
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* /var/cache/debconf/*-old
3. Android SDKのインストール
(※android-sdk-download.bash、android-sdk-download.bash、android-sdk-licenses.bashは内製スクリプト)
1
2
3
4
5
6
7
8
ENV ANDROID_HOME /opt/android-sdk-linux
ENV ANDROID_SDK_ROOT ${ANDROID_HOME}
ENV ANDROID_NDK_HOME ${ANDROID_HOME}/ndk-bundle
RUN \
/bin/bash android-sdk-download.bash && \
/bin/bash android-sdk-update.bash /opt/oraclejdk8 && \
/bin/bash android-sdk-licenses.bash ${ANDROID_HOME}/licenses && \
chmod -R 777 /opt/android-sdk-linux
Jenkins Pipelineの導入
Pipeline導入前のビルドスクリプトがスマートデバイス基盤チーム内に閉じていて、サービス側に対してはブラックボックス化されていました。その為、下記課題がありました。
・エラー発生した場合、サービス側で原因究明できず、且つ問題発生箇所が可視化できていない為、問題解決に時間が掛かる
・CI関連ノウハウの属人化
・サービス側で提供された機能しか利用できず、独自設定・処理を追加できる柔軟性に欠ける
Pipeline適用とともに、スマートデバイス基盤チーム側はビルド環境(インフラ、Jenkins、導入Pluginなど)の構築・進化及び技術サポートを担い、サービス側は開発フローに沿ってスクリプトを自由に組み込めるような形にしました。また、Pipeline化により、ビルドスクリプトの履歴管理ができ、ビルド処理がステージごとに分割されることにより可視化ができ、問題が短時間で解決できるようになりました。
Jenkinsfileのサンプルコード:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
node("docker") {
try {
stage("Init") {
//初期化処理、Shared Library読み込み
}
stage("Checkout") {
//CheckOut
}
//ビルド処理〜配布
stage("Container") {
withDockerContainer(args: CONTAINER_NAME + environments.getENV(JAVA), image: IMAGE) {
environments.setENV(JAVA)
stage("Build") {
//ビルド処理
}
stage("Tests") {
//テスト処理
}
stage("StaticAnalysis") {
//静的解析
}
stage("Deploy") {
//配布
}
}
}
stage("Archive") {
//成果物保存
}
} catch (Exception e) {
logger.printStackTrace(e)
currentBuild.result = "FAILURE"
} finally {
if (!currentBuild.resultIsBetterOrEqualTo("SUCCESS")) {
slack.color = "danger"
}
notification.sendSlack(slack)
}
}
共通処理をShared Libraryとして提供
ビルドスクリプトの作成・管理はサービス側で持つことになりますが、共通的な処理の実装は横断で提供すべきところで、基盤チームからShared Libraryを実装・ソース公開しました。下記は提供しているものの一覧となります。
スクリプト | 機能 |
---|---|
jobProperties | ジョブの成果物の保持数及び保持日数を設定 |
environments | ビルドコンテナの環境変数設定 |
gradlew | gradlewタスク実行 |
buildVariant | ビルドモード、配布モード取得 |
emulator | エミュレーターの作成・起動 |
analysis | 静的解析、解析結果収集、SonarQube解析などを実施 |
sonarQube | SonarQube解析、SonarQubeの解析モード設定取得 |
deploy | DeployGateにアップロードする |
notification | Slack通知 |
logger | Exception発生時のログをコンソールに出力 |
gitComments | 実行中のブランチの最新のコミットコメントを取得 |
終わりに
今回は基盤チームの日頃の運用改善事例としてAndroidアプリ開発のCI環境を紹介させていただきました。Pipelineの詳細、Dockerの一般的な知識は割愛させていただきましたが、少しでもご参考になればと思います。
次回はiOSアプリ開発のCI環境も紹介させていただきたいと思います。