さようならJenkinsおじさん、こんにちはCodeBuildさん

# はじめに

先日のre:InventでフルマネージドのCIサービス、[CodeBuild](https://aws.amazon.com/jp/blogs/news/aws-codebuild-fully-managed-build-service/)が発表されましたね。

業務ではずっとJenkinsおじさんに頑張ってもらっていたのですが、これを機にCodeBuildに乗り換えてJenkinsおじさんとお別れしたので、その際の手順や注意事項をざっくりと書き残します。

# 構成

とりあえず、前提としてアプリやCodePipelineのプラットフォームや構成を説明しておきます。

## アプリの構成

* 使用言語
    * サーバサイド: Node.js(ES6)
    * クライアントサイド: Typescript
    * スタイル: SCSS
    * ビュー: Pug
* 使用フレームワーク: Express
* プラットフォーム: Docker
* リバースプロキシ: nginx

こんな感じのをElastic Beanstalkに乗っけて運用してます。

## CodePipelineの構成

もともと業務で開発していたアプリはこんな感じでCIしてました。

1. CodeCommitにソースをプッシュしたらCodePipelineをキック
2. Jenkinsサーバで
    * `npm install`
    * Typescriptとscssをそれぞれjsとcssにトランスパイル
    * テスト実行
3. Elastic Beanstalk上で`docker build`して稼働

今回は2の部分をCodeBuildに置き換えました。
なのですでにCodePipelineが一通り出来上がっていることが前提になります。
悪しからずご了承ください。

# CodeBuildの設定

コンソールからCodeBuildの画面に行ってもいいのですが、
どうせCodePipelineからしか使わないので、CodePipelineの画面から設定します。

![スクリーンショット 2016-12-05 20.40.01.png](https://qiita-image-store.s3.amazonaws.com/0/116434/5ed76419-9482-b0e5-70a8-d9377f514299.png)

Pipeline編集画面に行ったらBuildステージの鉛筆マーク(上図の矢印部)をクリックします。
すると右に設定フォームが出るので、まずBuild Providerは「AWS CodeBuild」を選択します。

ちなみに、2016-12-05時点で対応しているBuild ProviderはAWS CodeBuild、Jenkins、Solano CIの三つです。
Jenkinsは自前でサーバを用意しなければならず、Solano CIはクラウドサービスだけど情報が全然ないのが困りものでした。

さて、Build Providerを選択したら既存のプロジェクトを使うか新しくプロジェクトを作るか選択します。
今回は初めてのCode Buildだったので新しく作りました。

## ビルド環境の設定

![スクリーンショット 2016-12-05 20.40.26.png](https://qiita-image-store.s3.amazonaws.com/0/116434/2e5005bf-6826-df05-c2ea-34a4381f75a8.png)

次にビルドの環境を設定します。
CodeBuild側で用意されたイメージを使うか、あらかじめ用意したDockerイメージを選択できますが、今回はマネージドのイメージを使います。

OSの選択は2016-12-05時点ではUbuntuしか選べません。CentOS派は涙目です。
世界的には一番人気だから仕方ないね。
しかしバージョンぐらいは教えて欲しい...

Runtimeで選べるのは

* Android
* Java
* Python
* Ruby
* Go
* Node.js
* Docker

です。
Versionもそれぞれ複数選べるのでお使いの環境に合わせて選びましょう。

前述の通りExpressアプリなのでRuntimeはNode.js、バージョンはせっかくなので7.0にします。
新しい物好きなので。
ていうかちょっと前に6.9にあげたばかりなのに、もう7系が出てるのかよ。Node.jsのバージョンアップ速すぎィ!

画像一番下にBuild Specificationというのがありますが、これはビルドの内容(`npm install`とか)です。
これをbuildspec.ymlというファイルに書くか、ここに直接コマンドを書き込むかという選択ですが、
よっぽど短くない限りはbuildspec.yml推奨です。
めっちゃ小さいテキストフィールドにビルドで用いるコマンドを全て&&でつないで書くとか苦行です。

buildspec.ymlについては後述します。

## ロールの設定

![スクリーンショット 2016-12-05 20.40.40.png](https://qiita-image-store.s3.amazonaws.com/0/116434/b094ebbd-2892-70b6-6324-204b74a37fb2.png)

次にプロジェクトに付与するロールの設定です。
とりあえず新しくロール作っときゃ問題ないかと思います。

まあ、同じ内容のロールがたくさんできたりしたらうざいので、プロジェクトを複数走らせるようになったら適度に使い回しましょう。

## 拡張設定

![スクリーンショット 2016-12-05 20.40.53.png](https://qiita-image-store.s3.amazonaws.com/0/116434/e1ed42d2-53b2-4fd3-1110-2dac3ccbcfcf.png)

最後にタイムアウト時間、ビルド環境のスペック、環境変数の設定をします。
私は特にいじる必要がなかったのでデフォルトのままです。

## 注意事項

今回私は以前から使っていたPipelineをいじったため、**PipelineにアタッチしているロールにCodeBuildへのアクセス権限が一切無い状態でした**。
まあ、当然失敗するわけですよね。
なので、すでにアタッチされているロールに新しく権限を追加してやりましょう。
IAMのコンソールからアタッチポリシーで**AWSCodeBuildDeveloperAccess**っていうポリシーを追加してやればOKです。

新しくPipelineを作ったらどうなるかはすいませんが未確認です。

# buildspec.yml

さて、一通りCodePipelineの設定が済んだら前述のbuildspec.ymlを作ってプロジェクトルートに入れてやります。

buildspec.ymlで設定するのは以下の項目です

* version : buildspecのバージョン 0.1にしとけば問題ないです
* environment_variables : ビルド時の環境変数
* phases : ビルドの各フェーズでの動作を定義します。フェーズ名は以下の四つで固定されています。
    * install : インストール時の動作 ex.) `npm install`
    * pre_build : ビルド前の動作　必要なディレクトリ作ったりとかですかね
    * build : ビルド
    * post_ubild : ビルド後 テストで発生したログの掃除とかですかね
* artifacts : 出力ファイルの設定
    * type : 出力ファイルの形式 zipしか受け付けてくれません
    * files : zipに含めるファイル ワイルドカードも使える
    * discard-paths : zipに含めるファイルのパスを省略するかどうか デフォルトではnoになっている
 
discard-pathsは任意ですが、他は全て必須です。

公式に載ってる例はこんな感じ(Javaだけど)

```yaml:buildspec.yml
version: 0.1

environment_variables:
  plaintext:
    JAVA_HOME: "/usr/lib/jvm/java-8-openjdk-amd64"

phases:
  install:
    commands:
      - apt-get update -y
      - apt-get install -y maven
  pre_build:
    commands:
      - echo Nothing to do in the pre_build phase...
  build:
    commands:
      - echo Build started on `date`
      - mvn install
  post_build:
    commands:
      - echo Build completed on `date`
artifacts:
  type: zip
  files:
    - target/messageUtil-1.0.jar
  discard-paths: yes
```

各フェーズ毎にコマンドをそのまま書いていく感じですね。
カレントディレクトリは勝手にプロジェクトルートにしてくれるのでそんなに気にしなくていいです。

この例だと出力するファイルが一つですが、複数選択する場合は

```yaml
artifacts:
  type: zip
  files:
    - target/messageUtil-1.0.jar
    - hoge/hoge.jar
    - fuga/fuga.json
    - fugafuga/**/* # ワイルドカードも使える!
```

こんな感じですかね。
これをひっくるめてCodeCommitにプッシュしてやれば無事に動きました。

# おわりに

こんな感じにして、私の業務環境ではJenkinsおじさんはお役御免となりました。
名残惜しいですね。
~~まあ、ぶっちゃけJenkinsおじさんの面倒見るの超めんどくさかったんだけど~~

とはいえ、いくつかまだまだJenkinsおじさんの方が有能な部分があったので挙げておきますと

* Jenkinsおじさんはビルドの結果をSlackで通知できる
* Jenkinsおじさんはテスト結果の推移をグラフで出せる
* JenkinsおじさんはHTML形式のドキュメントを簡単に表示できる

まあCodeBuildからでも他のサービスを駆使したらできるんでしょうけど、やっぱりJenkinsおじさんのプラグインに比べるとハードルが高いかなと。

という感じで、まだまだ物足りないところはあるのですが、マネージドのCIサービスまで提供されて、フルマネージドでリポジトリからCI、デプロイまで一気通貫で構築できるのは大きな魅力かと思います。

# 参考

* [チュートリアルを通してCodeBuildを理解する #reinvent](http://dev.classmethod.jp/cloud/aws/understanding-codebuild/)
* [公式ドキュメント](http://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-versions)