Alibaba CloudとWerckerでCI/CDパイプラインを作ってみた

(元の記事は: [SBクラウドのテックブログ](http://techblog.sbcloud.co.jp/2017/06/23/cicd-with-alibabacloud-and-wercker/)を参照してください) 

# はじめに

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/ae95b336-4686-a9af-f56d-9b993ed83ad6.png)

継続的インテグレーション (CI - Continuous Integration) は、開発者が書いたコードを定期的に共通レポジトリへマージし、マージした後のビルド・テストが自動的に実行する開発の手法です。

継続的デリバリー (CD - Continuous Delivery)は 、CIの拡張したもので、デリバリープロセスが追加されます。継続的デリバリーでは、開発したコードが自動的にビルド・テストされ、本番環境へリリース可能な状態へ準備されます。

CI/CDは主に以下のメリット

* 開発生産性を向上
* バグを早期に発見し対処できる
* 更新を迅速に配信

CI/CD実施するメリットが多いため、開発プロセスに導入するのが当たり前となっていると思います。
オンプレミス時代なら、ビルドサーバーやCIサーバーの見積もりや構築・運用しなければならず、CI/CDの導入することが大変だと思いますが、今のクラウドやSaaS時代ならば、CI/CDを容易にできるようになりました。Alibaba Cloud 日本リージョンはCI/CDのサービスはまだサポートしていませんが、他のSaaS系CIツールと組み合わせればCI/CDを実施可能です。

# CI/CD構成

CI/CDの試すために[Wercker](http://www.wercker.com/)というツールを使いました。Werckerは、DockerによりCI/CDを実施する自動化プラットフォームです。Werckerの詳細については、qiitaには[記事がたくさんあった](http://qiita.com/search?q=wercker)ので興味を持っている方はそちらに参照してください。

設定したい構成は以下の図の通りです

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/ad220f5e-e095-0215-c1dd-22b09c4295c9.png)

1. Githubへコミットします
2. Github HookによりCIパイプラインが実行されます
3. テストがパスしたら、Alibaba CloudのECSにデプロイされた検証環境へ更新
4. デプロイ済みの検証環境ECSからイメージを作成

ステップ4のイメージはAutoScalingへ使用してもよいし、イメージを基づいて本番環境のECSを作成してもよいです。

1のデモ用のレポジトリは https://github.com/telescreen/aliyun-wercker-cicd-demo です。

# 設定手順

#### 1. プロジェクト設定

```
git clone git@github.com:telescreen/aliyun-wercker-cicd-demo.git
cat wercker.yml
initial-build:
  ...
deploy-staging:
  ...
prepare-production-image:
  ...
```

`wercker.yml`の中身からパイプラインを３つ存在していることがわかります。それは `initial-build` ビルド・テストパイプライン、`deploy-staging`パイプライン、と `prepare-production-image` パイプラインです。それぞれのパイプラインの実施する作業は`steps`で確認できます。

これらのパイプラインを `wercker`管理画面で `Add new pipeline`ボタンでパイプラインを追加し、`Editor` でパイプラインを繋ぎます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/45825dad-a09a-3521-398f-8dc192d914a6.png)

#### 2. 必要な環境変数を設定する

`Wercker`管理画面で、`steps`が使用する環境変数を定義します。デモアプリの場合は

* SLACK_URL: 通知用のSlack webhook URL
* SLACK_CHANNEL: 通知チャンネル
* PKEY_PRIVATE: 検証環境へアクセス用の秘密鍵
* STAGING_SERVER_IP: 検証環境のIP
* STAGING_SERVER_FINGERPRINT: `known_hosts`に追加する必要のfingerprint

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/f59b5b89-921e-5cc5-e680-2d7947af9bc0.png)

ECSイメージの作成は`aliyuncli`を使ってAPI経由で行うため、`prepare-production-image`の個別に環境変数の設定が必要です

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/6b0552ec-de5a-69a3-44e8-d38f26543c95.png)

[aliyuncli](http://qiita.com/talzeus/items/28c773f77b40770a8c42) に必要となる情報は

* ACCESS_KEY_ID / ACCESS_KEY_SECRET: APIを呼び出す用の鍵
* REGION_ID: ECSにあるリージョン
* INSTANCE_ID: 検証環境のECSインスタンスID

#### 3. パイプラインを実行し、検証環境デプロイ

パイプラインを実行し、結果をわくわく待ちます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/da173c21-deaf-adb5-87c4-55cd31dd3f19.png)

パイプラインをすべて実行し、問題がなければ緑パイプラインが表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/698fa0e4-cae2-84fc-0700-dba9c42fd7b5.png)

# CI/CDパイプラインを実際に動かしてみる

#### 1. 変更してみる

```bash
$ git checkout -b develop/feature
```

editor で cicd.pyを開き、以下のコードを追加

```python
@app.route("/newlist")
def newlist():
    entries = model_data()
    entries.append({"text": "hi, again"})
    return render_template("index.html", entries=entries)
```
`cicd_test.py`を開き、テストコードを追加

```python
def test_newlist(self):
    rv = self.app.get('/newlist')
    assert b'hi, again' in rv.data
```

追加したコードを単体テスト実施

```bash
(cicddemo) workspace/cicddemo - [develop/new-feature●] » pytest cicd_test.py -k newlist
========================================= test session starts =========================================
platform darwin -- Python 3.6.1, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /Users/tal/workspace/cicddemo, inifile:
collected 3 items

cicd_test.py .

========================================= 2 tests deselected ==========================================
=============================== 1 passed, 2 deselected in 0.40 seconds ================================
```

#### 2. 変更をレポジトリへプッシュする

```
$ git add .
$ git commit -m "Add code (for cicd testing)"
$ git push origin develop/new-feature
```

ソースコードがプッシュされると、`wercker`が自動にテストが走らせます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/fd0b6e1f-5f55-d2e3-de94-9bb9f9a6f80e.png)

パイプラインが実行終わったら、ECS側でイメージ作成されていることを確認できます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/29aa5a6d-c9bc-2dc0-a012-e5efc713db51.png)


![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/8233c01a-394b-efed-d307-8c34be6daaba.png)

#### 3. テストでバグ発見したら

よくある、モデルを修正して、単体テストは通りますが、結合テストで問題を発見。

```
@app.route("/newlist")
def newlist():
    entries = model_data()
    return render_template("index.html", entries=entries)

def model_data():
    return [
        { "text": "Hello" },
        { "text": "world" },
        { "text": "one more" },
        { "text": "hi, again" }
    ]
```

これで`model_data`というモデルレイヤが修正され、単体テストがパスしているように見えますが、結合テストは失敗。

Werckerはそれを見つけてくれます。そして、ステップを開くと詳細エラーの原因がわかります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/638a59c7-446d-431b-bbec-587d48071f7a.png)

そして、Slackへ通知されます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/501302fa-c635-5f46-7843-7ff744b93a1b.png)

テストを通るように問題を修正してもう一回コミットすると

```python
def test_model_data(self):
    rv = cicd.model_data()
    assert len(rv) == 4
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/74420/27a71568-6230-e686-ae7d-5c5552402092.png)

# まとめ
CI/CDは

* 開発生産性を向上
* バグを早期に発見し対処できる
* 更新を迅速に配信

というメリットがあります。
今のクラウド時代なら、WerckerのようなSaaS CIサービスとAlibaba Cloudのようなクラウドサービスを組合せることによって容易にCI/CDパイプラインを実施できます。

CI/CDを見て興奮する気持ちを理解したい方は、是非テストプロジェクトをクローンしてwerckerのパイプラインを見てみてください。

# 参考
1. [Continuous Integration](https://www.martinfowler.com/articles/continuousIntegration.html)
2. [werckerドキュメンテーション](http://devcenter.wercker.com/docs/home)
3. [Werckerについて]((http://qiita.com/search?q=wercker))
4. [Alibaba Cloud](https://jp.aliyun.com)