AWS EC2上にApache + Jenkinsの環境を構築。
AndroidStudioで作成したプロジェクトをGithubへpush。
GithubのWebhookでJenkinsにpush通知し、Gradleを使ってビルドさせます。
確認環境:
クライアント:
PC Mac OS X 10.9.2
Gradle ver. 1.12
Android Studio ver. 0.5.8
Android Build tools gradle ver. 0.10.1
サーバ:
Amazon Linux AMI release 2014.03
Apache/2.2.27(Unix) built:Apr 25 2014 22:26:04
Jenkins ver.1.563-1.1
JDK ver.1.7.0_55
git ver. 1.8.3.1
Gradle ver. 1.12
Android SDK Build tools ver.19.1.0
Android Build tools gradle ver. 0.10.1
AWS EC2インスタンス準備までは下記のサイトを参考に進めました。
参考:EC2にJenkinsによるCI環境を作成する | Developers.IO
http://dev.classmethod.jp/cloud/aws/jenkins_on_ec2/
EC2インスタンスタイプ:m1.small(試作程度なら micro でもOK)
EBSのボリュームサイズですが、初期の8GiBだとAndroidSDKのフルインストールが
ディスクフルとなって入りきらなかったので80GiBに増量して使用しています。
参考:ボリュームのストレージ領域を拡張する | AWS Documentation.
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ebs-expand-volume.html
EC2インスタンスにユーザ"ec2-user”でSSH接続
$ ssh -i ./jenkins-key.pem ec2-user@54.xxx.xxx.xxx
●前準備
EC2 AmazonLinuxのタイムゾーンは、米国時間が初期設定なので日本時間に設定します。$ sudo cp -P /usr/share/zoneinfo/Japan /etc/localtime $ date
●JDKのインストール
ビルド環境構築のため、まずはJDKを導入。AmazonLinuxは初期状態でJRE1.7.0_55が入っているようです(2014.5.19現在)
$java -version java version "1.7.0_55" OpenJDK Runtime Environment (amzn-2.4.7.1.40.amzn1-x86_64 u55-b13) OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)
JDKはrpmでインストールします。直接rpmファイルを取得するのが難しいので、
まず、Mac(ローカル)にサーバへインストールしたいJDKの.rpmをダウンロード。
DL先:Java SE Development Kit 7 Downloads | Oracle
http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
=> jdk-7u55-linux-x64.rpm
rpmファイルをscpでサーバに転送(最後のコロンを忘れずに)
$ scp -i ~/Documents/dev/jenkins-key.pem jdk-7u55-linux-x64.rpm ec2-user@54.xxx.xxx.xxx:
サーバのec2-userホームに.rpmファイルが転送されるのでこれをインストール。
$ sudo rpm -ivh jdk-7u55-linux-x64.rpm
インストールが完了したらJDK1.7.0_55に切り替え。
$ sudo alternatives --install /usr/bin/java java /usr/java/jdk1.7.0_55/bin/java 2000
切り替わったことを確認します。
$java -version java version "1.7.0_55" Java(TM) SE Runtime Environment (build 1.7.0_55-b13) Java HotSpot(TM) 64-Bit Server VM (build 24.55-b03, mixed mode)
あとは環境変数を設定して、JDKの準備は完了。
$ export JAVA_HOME=/usr/java/jdk1.7.0_55/
●Apache+Jenkinsをインストール
とりあえずApacheをインストール。$ sudo yum install httpd
次にJenkinsをインストール。
↓のコマンドを打ちたいところだけれど、これだとエラーがでました。
$ sudo yum install jenkins > パッケージ jenkins は利用できません。
そのため、yumリポジトリにJenkinsを追加してからインストール。
$ wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo $ rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key $ sudo yum install jenkins
参考:RedHat Linux RPM packages for Jenkins | Jenkins CI
http://pkg.jenkins-ci.org/redhat/
インストールが終わったらJenkinsの設定を確認します。
$ sudo vim /etc/sysconfig/jenkinsJenkinsのポート番号が8080であることを確認。
JENKINS_PORT=“8080"
念のため、8080ポートが使用済みでないか確認。
8080が未使用であれば問題ないので次へ(使用中なら別のポート番号を割り当ててください)
$ netstat -an | grep LISTEN $ lsof -i -n -P
この時点で一度httpd, jenkinsサービスを起動して、アクセス確認してみます。
$ sudo service https start $ sudo service jenkins start
うまくサービス開始できたら下記のURIにアクセス。
(Jenkinsのサービス起動には1分程かかる場合があります)
http://54.xxx.xxx.xxx:8080
今のURIでは不便なので、Jenkinsのドキュメントルートを変更します。
Jenkins設定ファイルのJENKINS_ARGSにドキュメントルートパスを指定します。
$ sudo vim /etc/sysconfig/jenkinsJENKINS_ARGS="--prefix=/jenkins”
これでJenkinsに下記のURIでアクセスできるようになります。
http://hogehoge:8080/jenkins
双方のサービスは自動起動するように設定しておきましょう。
$ sudo chkconfig httpd on $ sudo chkconfig jenkins on
設定が反映されているか確認します。
$ /sbin/chkconfig --list | grep -e 'jenkins' -e 'httpd'
●Jenkinsユーザの設定
再度下記サイトを参考に、Jenkinsの初期設定(セキュリティ設定)を行います。参考:EC2にJenkinsによるCI環境を作成する | Developers.IO
http://dev.classmethod.jp/cloud/aws/jenkins_on_ec2/
Jenkinsのホームディレクトリはパッケージ管理ソフトでインストールした場合、
/var/lib/jenkins になります。
●AndroidSDKのダウンロード
AndroidSDKをダウンロードします。ダウンロードサイト:http://developer.android.com/sdk/index.html
次の手順でダウンロードリンクをコピー(2014.05.19現在ではr22.6.2が最新)
DOWNLOAD FOR OTHER PLATFORMS > SDK Tools Only > Linux32 > 64-bit
/usr/localにAndroidSDKを展開。
$ cd /usr/local/ $ sudo wget http://dl.google.com/android/android-sdk_r22.6.2-linux.tgz $ sudo tar -xvzof android-sdk_r22.6.2-linux.tgz
ビルドに必要なツールを落とします。
$ sudo ./android update sdk --no-ui
↑のコマンドだと、エミュレータイメージ等もまとめてダウンロードするのでサイズが大きくなります。
$ sudo android update sdk -t platform -uなどとすれば、ダウンロードしたいモジュールを絞ることができます。
(今回は面倒だったのですべてダウンロードしました)
ダウンロードが完了したら環境変数を設定。
$ export ANDROID_HOME=/usr/local/android-sdk-linux/
JenkinsにもANDROID_HOMEのパスを追加します。
Jenkins > Jenkinsの管理 > システムの管理 > グローバル・プロパティ
キー:ANDROID_HOME
値:/usr/local/android-sdk-linux/
念のためAndroidSDKのビルドツールバージョンを確認しておきましょう。
$ ls $ANDROID_HOME/build-tools/
今回は19.1.0を使用しています。
Gradleでビルドする際のBuildToolsバージョンとあわせる必要があるので覚えておきます。
●Github連携(GitHub設定)
Githubへのpushをトリガに、JenkinsのワークスペースへgitリポジトリをCloneします。GitHubにはpushをトリガに特定URIを叩く機構(Webhook)が用意されています。
Webhookを使って、「GitHubにpushされたらJenkinsでビルド」を実現します。
GitHubとの連携には鍵認証が必要です。
Jenkinsからのアクセスとなるので、Jenkins用のsshキーを作成。
$ cd /var/lib/jenkins $ sudo mkdir .ssh $ sudo chown jenkins .ssh $ sudo -u jenkins -H ssh-keygen -t rsa -C jenkins@54.xxx.xxx.xxx $ sudo chmod 755 ../.ssh
次に、公開鍵(id_rsa.pub)の内容をGitHubのSSH Keyとして登録。
GitHub > AccountSetting > SSH Keys > Add SSH Key
Titleは適当に。Keyは公開鍵の内容をペースト。
GitHubに鍵の登録ができたら接続テストをします。
$ sudo -u jenkins ssh -T git@github.com
問答の結果、次のメッセージが表示されれば成功。
Hi YukiMatsumura! You've successfully authenticated, but GitHub does not provide shell access.
これでGitHub連携の準備は完了です。
●GitHub連携(Jenkins設定)
JenkinsがWebhookできるように設定します。まず、AmazonLinuxにgitをインストール。
$ sudo yum install git-core
次はJenkinsの設定。
Jenkins > Jenkinsの管理 > プラグインの管理 > [利用可能]タブ から
"GitHub Plugin”をインストールし、Jenkinsを再起動。
再起動が終わったら、Webhookを受信するJenkinsジョブを準備します。
"新規ジョブ作成”からジョブを作成します。
ジョブの種類は"フリースタイル・プロジェクトのビルド”とし、適当なジョブ名をつけて作成。
ジョブの設定項目は下記を参照。
GitHub project:GitHubリポジトリのURI(ブラウザで確認する際のURIでOK)
ソースコード管理:Gitを選択
Repository URI:先ほどGitHub projectで入力したURIのhttps:スキームを"git:"に変更。
ビルド・トリガ:"Build when a change is pushed to GitHub"を選択
●GitHub連携(GitHub Webhook設定)
ブラウザからWebhook対象のGitHubリポジトリに移動し、Settings > Webhooks & Services > Servicesの[Add service] > [Jenkins GitHub plugin]
Jenkins hook urlにはJenkinsサーバのルートに/github-webhook/を追加した文字列を指定します。
http://54.xxx.xxx.xxx:8080/jenkins/github-webhook/
設定後、GitHub側でWebhookURI編集画面にある[Test service]を押下すれば接続テストができます。
対象のJenkinsジョブにある"GitHub Hook Log”にアクセスログが残っていれば疎通確認OKです。
●AndroidStudioのプロジェクトをGitHubにpush
AndroidStudioとGitHubの連携については割愛します。今回は無用な問題を避けるためにAndroidプロジェクトの
build.gradleに指定する各ビルドツールのバージョンを明示的に指定します。
・プロジェクトルートのbuild.gradle
buildscript { dependencies { classpath 'com.android.tools.build:gradle:0.10.1'
・モジュール毎のbuild.gradle
android { buildToolsVersion "19.1.0"com.android.tools.build:gradleのバージョンが変わるとビルドが通らないことがよくあります。
buildToolsVersionについてはAmazonLinuxに展開したAndroidSDK側にも同じver.のものが必要です。
プロジェクトをGitHubにPushしたらJenkinsのジョブを確認。
新しいビルドがスケジューリングされているのがわかります。
ワークスペースにはGitHubにあるファイルがCloneされます。
●ビルド
Cloneしたソースをビルドします。先ほど作成したジョブの”設定”からジョブを再編集します。
Gradle Wrapperを使ってビルドするために下記を設定します。
ビルド > [ビルド手順の追加 > “シェルの実行”
シェルスクリプト:./gradlew build
これで、GitHubからリポジトリCloneした後にGradleによるビルドが実行されます。
今の状態でビルドしてみましょう。
# GitHubからClone済みであればジョブの"ビルド実行”からビルド開始できます
ビルド成功ならばOK。ビルド失敗ならば原因解析します。
ジョブ画面のビルド履歴からビルド結果の詳細が確認できます。
ビルド失敗した場合はビルド結果画面にある”コンソール出力”で失敗理由を確認します。
・失敗例1
What went wrong:
A problem occurred configuring project ':app'.
> SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.
環境変数”ANDROID_HOME”がjenkinsに設定されていません。
先述のグローバル・プロパティにANDROID_HOMEを設定することで解決します。
・失敗例2
* What went wrong:
Execution failed for task ':app:mergeDebugResources'.
> /var/lib/jenkins/jobs/hogehoge/workspace/build/exploded-aar/com.android.support/appcompat-v7/19.1.0/res/drawable-xxhdpi/abc_ic_voice_search.png: Error: Cannot run program "/usr/local/android-sdk-linux/build-tools/19.1.0/aapt": error=2, No such file or directory
aaptは32bitアプリケーションなので、32bit用ライブラリをインストールする必要があります。
まずは標準Cライブラリ(glibc)をインストール。
$ yum install glibc.i686
次に共有ライブラリの依存関係を調べます。
$ ldd /usr/local/android-sdk-linux/build-tools/19.1.0/aapt
手元の環境では下記の結果が得られたので、"not found”のライブラリをインストールしていきます。
linux-gate.so.1 => (0xf772a000)
librt.so.1 => /lib/librt.so.1 (0xf771b000)
libdl.so.2 => /lib/libdl.so.2 (0xf7716000)
libpthread.so.0 => /lib/libpthread.so.0 (0xf76fc000)
libz.so.1 => not found
libstdc++.so.6 => not found
libm.so.6 => /lib/libm.so.6 (0xf75de000)
libgcc_s.so.1 => not found
libc.so.6 => /lib/libc.so.6 (0xf7421000)
/lib/ld-linux.so.2 (0xf772b000)
libz.so.1のパッケージを検索、インストール。
$ yum whatprovies libz.so.1 zlib-1.2.7-10.17.amzn1.i686 : The compression and decompression library リポジトリー : amzn-main 一致 : Provides : libz.so.1 $ yum install zlib-1.2.7-10.17.amzn1.i686
libstdc++.soも同じく。
$ yum whatprovides libstdc++.so.6 libstdc++44-4.4.6-4.81.amzn1.i686 : GNU Standard C++ Library リポジトリー : amzn-main 一致 : Provides : libstdc++.so.6 $ yum install libstdc++44-4.4.6-4.81.amzn1.i686
libgcc_s.so.1も同じく。
$ yum whatprovides libgcc_s.so.1 libgcc44-4.4.6-4.81.amzn1.i686 : GCC version 4.4 shared support library リポジトリー : amzn-main 一致 : Provides : libgcc_s.so.1 $ yum install libgcc44-4.4.6-4.81.amzn1.i686
・その他失敗例
ビルドに失敗する要因は様々ですが、開発環境とJenkinsとで異なるGradleバージョンを使用している
ことが原因である可能性もあります。
・おわりに
今回の内容にはセキュリティの観点が含まれていません。
実運用する際にはAWS, GitHub, Jenkinsのセキュリティ設定にご注意ください。
以上。