Wercker を使ってみた

[Wercker - automation driven development](http://wercker.com/)

プライベートリポジトリが無料で使える上、独自の実行環境を作って使うこともできる CI サービス。
LXC と Docker の２種類のインフラストラクチャが使用可能で、ビルドの後にデプロイを実行したりもできる。
なお、今後は Docker の方が奨励されるらしく、後述の LXC を使う方法は役に立ちません。

## 独自の Box を作る

LXC の場合、ビルドを実行する環境は Wercker の [Registry](https://app.wercker.com/#explore) から Box というものを探して使用します。Registry に自分で作成した Box を登録することもできます。

試しに PHP 7 が使える Box を作ってみます。次のように wercker に Applications を登録します。

- `wercker-box.yml` というファイルが含まれたリポジトリを GitHub に作る
  - [https://github.com/ngyuki/example-wercker-box](https://github.com/ngyuki/example-wercker-box)
- リポジトリを Wercker の [Applications](https://app.wercker.com/#applications) に登録する
  - 作成途中で **Docker か？** みたいなことを聞かれますが、**No** です
  - **リポジトリに wercker.yml がないよー** みたいに言われるかもしれないけど無視する
  - Box を Registry に登録するためには Application が Public である必要がある
- Application の設定画面を開いて Targets に `wercker directory` を登録する
  - Targets というのはデプロイの設定のこと
  - どの Git のブランチがデプロイされるかを設定できる
  - ターゲット名はただの飾り


[wercker-box.yml](https://github.com/ngyuki/example-wercker-box/blob/b6f7aa32a310e8f9d6a7c5c96707e55237877f9f/wercker-box.yml) は次のような内容です。

```yaml
name: example
version: 0.0.4
type: main
platform: ubuntu@12.04
description: example
keywords:
  - php
  - php7
packages:
  - php@7
script: |
  sudo apt-get update
  sudo apt-get install -y wget curl tar make gcc autoconf re2c bison libxml2-dev python-pip
  sudo apt-get clean

  sudo pip install awscli

  cd /tmp/
  wget --content-disposition https://github.com/php/php-src/archive/master.tar.gz
  tar xzf php-src-master.tar.gz

  cd php-src-master/
  ./buildconf
  ./configure
  make
  sudo make install
  sudo cp php.ini-development /usr/local/lib/php.ini

  cd
  sudo rm -fr /tmp/*

  php -v
```

Application の登録が完了したらビルドを実行します。ビルドを実行すると空のビルドが走ります。`wercker.yml` がリポジトリに含まれていないためです。本来は `wercker.yml` にビルドの手続きを書いているのですが、このリポジトリは Box の作成のためのものなので `wercker.yml` がありません。

ビルドが成功すると（空なので必ず成功するはずですが）、デプロイが実行されます。

`wercker directory` のデプロイは `wercker-box.yml` に書かれた手続きを実行したあと、デプロイで使用した環境そのものを Registry に登録します。

- `platform` でベースとなるプラットフォームを指定しますが `ubuntu@12.04` しか選べないらしいです
  - LXC のホストのことだと思います
- `inherits` かなにかで Registry に登録されている Box をベースにできたと思います
- 同じ `version` を重複してデプロイできません
  - 上書きされたりもしないのでデプロイの都度 `version` はインクリメントが必要です

## 独自の Box を使ってみる

↑で作成した PHP 7 の Box を使ってみます。

- `wercker.yml` というファイルが含まれたリポジトリを GitHub につくる
  - [https://github.com/ngyuki/example-wercker/](https://github.com/ngyuki/example-wercker/)
- このリポジトリを Wercker の [Applications](https://app.wercker.com/#applications) に登録する
  - 作成途中で **Docker か？** みたいなことを聞かれますが、**No** です

[wercker.yml](https://github.com/ngyuki/example-wercker/blob/db67da1a50ed6e350819d270f7219c5c03e19303/wercker.yml) は次のような内容です。

```yaml
box: ngyuki/example
build:
  steps:
    - script:
        code: |-
          uname -a
          php -v
```

Wercker で手動でビルドするか、GitHub のリポジトリに Push すればビルドが実行されます。

## ビルドとデプロイの連携

ビルドやデプロイの実行時には次のように環境変数が設定されています。また、カレントディレクトリは `/pipeline/build` です。

```sh
export WERCKER_ROOT="/pipeline/build"
export WERCKER_SOURCE_DIR="/pipeline/build"
export WERCKER_OUTPUT_DIR="/pipeline/output"
```

ビルドで `$WERCKER_OUTPUT_DIR` になにかが出力されていれば、デプロイではそのディレクトリの内容が `$WERCKER_SOURCE_DIR` にコピーされます。もし、ビルドで `$WERCKER_OUTPUT_DIR` が空っぽなら、ビルドの `$WERCKER_SOURCE_DIR` がデプロイの `$WERCKER_SOURCE_DIR` にコピーされます。

試しになにか適当なファイルをビルドで作って、デプロイで S3 にアップロードしてみます。

- Application の設定画面の Targets で `custom deploy` を追加します
  - ターゲット名はただの飾りです
- `AWS_ACCESS_KEY_ID` `AWS_SECRET_ACCESS_KEY` `AWS_S3_BUCKET` のような環境変数をそれっぽく設定します
  - `Protected` を ON にすれば画面やビルドのログに表示されなくなります
- SSH 鍵なんかも登録できるようです
  - rsync でデプロイとかも簡単そうです

デプロイの設定ができたら、リポジトリの [wercker.yml](https://github.com/ngyuki/example-wercker/blob/42dbd3bcdd3cdeb862fa40cbb38469964c04b863/wercker.yml) を次のように修正してプッシュします。

```yaml
box: ngyuki/example
build:
  steps:
    - script:
        name: php information
        code: |-
          uname -a
          php -v
          php -i > $WERCKER_OUTPUT_DIR/wercker-output.txt
deploy:
  steps:
    - script:
        name: upload s3
        code: |-
          aws s3 cp wercker-output.txt s3://$AWS_S3_BUCKET/
```

自動的にビルドが実行され、さらにデプロイで S3 へのアップロードも行われます。

## Docker を使ってみる

インフラストラクチャに Docker を使う場合は Wercker の [Registry](https://app.wercker.com/#explore) のようなものではなく普通に [Docker Hub](https://hub.docker.com/) が使えるので、独自のビルド環境が欲しければ Docker Hub にイメージを登録すれば OK です。

ビルドの [wercker.yml](https://github.com/ngyuki/example-wercker-docker/blob/b5c576654f2df67446faaa657058d52783988b86/wercker.yml) も、下記のように `box` のところを Docker のイメージの名前にするだけです。

```yaml
box: docker.io/centos:7
build:
  steps:
    - script:
        name: uname
        code: |-
          uname -a
```

## wercker CLI

[wercker CLI](http://devcenter.wercker.com/learn/basics/the-wercker-cli.html) というものが提供されていて、wercker のサイトと同じ環境でビルドのテストとかができます（インフラが Docker の場合だけです）。

インストールします。

```sh
curl https://s3.amazonaws.com/downloads.wercker.com/cli/stable/linux_amd64/wercker \
  -o $HOME/bin/wercker
chmod +x $HOME/bin/wercker
wercker --version
```

例えば `wercker.yml` をこんな感じにして `wercker dev` すると、カレントディレクトリを監視して変更があると自動的にコマンドが実行される（cifs だとダメ）。

```yaml
box: docker.io/centos:7
dev:
  steps:
    - internal/watch:
        code: bash app.sh
        reload: true
```

`wercker.yml` をこんな感じにすると、`wercker dev` でコンテナの中に入ることができる。

```yaml
box: docker.io/centos:7
dev:
  steps:
    - internal/shell:
      cmd: /bin/bash
      code: |
        cd /var/log
```

`wercker.yml` をこんな感じにして `wercker dev --attach-on-error` とすれば、コマンドがコケた時だけコンテナの中に入ります。

```yaml
box: docker.io/centos:7
dev:
  steps:
    - script:
      code: |-
        bash app.sh
```

他にも `wercker build` であたかも wercker のサイトでビルドしたかのようにローカルでビルドできたり、`wercker pull` で wercker サイトからコンテナを持ってきたり、ビルド結果のコンテナを持ってきたりすることができるっぽい。

## Steps

ここでは全く使いませんでしたが、`wercker.yml` の `steps` は複数指定することができ、また、`script` 以外にも作成済のものがいろいろ使えます。

例えば、[wercker/step-npm-install](https://github.com/wercker/step-npm-install) は `npm install` を実行する Step で、下記のように使えます。

```yaml
build:
  steps:
    - npm-install
    - script:
      code: npm test
```

他にも、[S3 にアプロードする Step](https://github.com/wercker/step-s3sync) などいろいろ便利なものがあります。

```yaml
deploy:
  steps:
    - s3sync:
        key-id: $KEY
        key-secret: $SECRET
        bucket-url: $BUCKET
        source-dir: $SOURCE
        opts: --acl-private
```

Step も Box と同じように、自分で独自のものをつくることができます。