CircleCI as a Resource

Retty Advent Calendar 2018 5日目の記事です。
昨日は @shindo-taichi  さんの記事で、 [Rettyマネタイズを支える広告商品開発](https://qiita.com/shindo-taichi/items/4f87a1ae7478c2b10eb2) でした。


みなさんの会社では、CIをどれぐらい活用されていますでしょうか？

"Fail Fast, Fail Often, Fail Forward" な開発体制を整えるためには
CI/CDは欠かせない構成要素のひとつで、紆余曲折あって
今ではCircleCIを利用しています。

CircleCIはCI/CDのための優れたサービスとして、様々な素晴らしい側面を持っています。
本記事では、単なるビルド環境に閉じない利用事例を紹介したいと思います。


CricleCI とは
----------------------------------------

[CircleCI](https://circleci.com/)はCIのためのSaaSのひとつで
ymlで簡単にワークフローを記述し、dockerを利用したジョブ実行により
CI/CD環境を手軽に構築することができます。

並列実行の可否も全てCircleCIがワークフローから判断を自動的に行ってくれます。

以下はCircleCIの[Sample Configuration with Parallel Jobs - CircleCI](https://circleci.com/docs/2.0/sample-config/#sample-configuration-with-parallel-jobs)からの引用になりますが 
buildジョブとtestジョブが並列実行されます。
CircleCIのお手軽さがうかがえるのではないでしょうか？

```yaml

version: 2
jobs:
  build:
    docker:
      - image: circleci/<language>:<version TAG>
    steps:
      - checkout
      - run: <command>
  test:
    docker:
      - image: circleci/<language>:<version TAG>
    steps:
      - checkout
      - run: <command>
workflows:
  version: 2
  build_and_test:
    jobs:
      - build
      - test
```


CircleCIを利用した継続的開発プロセス
----------------------------------------

このようにお手軽なCircleCIですが
実行環境リソースとして注目した場合の優れた点を挙げることができます。

* インスタンス管理が不要なサーバレスアーキテクチャ
* CI/CDのために最適化された高速なインフラ環境 (ネットワーク, コンテンツストレージ) 
* 並列性に優れたジョブキューシステム

どれをとっても素晴らしいのですが、特に３つめのジョブキューシステムとしての側面は
手前で用意するにはかなり大変で、複雑なシステム構成を必要とします。

これだけ優れた機能をビルドやユニットテストだけのために利用するのはもったいない！
CircleCIを十二分に使いたおしてしまいましょう。

### Githubとの連携して、アーティファクトの画像を貼り付ける

CircleCIにはビルド生成物をアップロードし、利用可能なようにする
アーティファクト機能があります。

https://circleci.com/docs/ja/2.0/artifacts/

このアーティファクト自体は S3でできていて、CircleCIのUIから簡単に確認できるようになっているのですが
なんと、これをGithubに貼り付けることができます。


下みたいな感じです
![スクリーンショット 2018-12-05 20.03.19.png](https://qiita-image-store.s3.amazonaws.com/0/62929/07e9b120-812e-f17c-407c-d55e20f47e08.png)


要は circleciのトークンを GETパラメータで渡してやればいいの感じになります。
以下のような関数でうまいこと生成できます。

```javascript
function artifactsUrl(artifactsPath) {
  const absPath = path.resolve(artifactsPath);
  const {
    CIRCLE_TOKEN: token,
    CIRCLE_BUILD_NUM: buildNum,
    CIRCLE_REPO_ID: repoId,
  } = process.env;
  return `https://${buildNum}-${repoId}-gh.circle-artifacts.com/0${absPath}?circle-token=${token}`;
}
```

**「tokenをURLに貼り付けのはちょっと....」** と思いのあなた。

<h4>ご安心を</h4>

githubだと貼り付けられた画像コンテンツをキャッシュし、URLを自動的に置換するサービスが動いているので
tokenがついたURLをハッシュ化してくれます！
なのでcircleciのトークンもうまいこと隠してくれます！(e.g. https://camo.githubusercontent.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)

なので CIで大量の画像生成 -> githubに貼り付け  なんてことができます！
いやー便利ですね！！

githubがコンテンツキャッシュ/ CircleCI自体のコンテンツの寿命の兼ね合いもあって画像はかなり長寿命です。

### Performance Metrics for Sites

ブラウザ環境をエミュレートする必要のあるE2Eテストではメモリを多く必要とします。
バッチサーバで動かしているとメモリを使い潰してしまい、他のジョブに影響がでてしまった！
なんてことが起きえます。

CircleCIを使えば、リソースはジョブごとに確保されるためFaaSのような使い方が可能です。
エラーが起きたとしても 一定時間が経てばジョブはkillされるため、安心して使うことができます。

弊社ではProduct環境のパフォーマンス監視のためのE2Eテストして
[Lighthouse](https://developers.google.com/web/tools/lighthouse/)や[Pagespeed insight](https://developers.google.com/speed/pagespeed/insights/)を使って
パフォーマンスの測定を定期実行しています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/62929/12ac3bfc-a782-3407-5434-b50d8571976a.png)


特にLighthouseの測定ではメモリを多く必要とし
ブラウザをエミュレートすることから非常に不安定になりやすいですが
ジョブの度に新しい環境が作られるため悩みの種が小さくすることができます。

### Instant Chatbot on CircleCI

デプロイをもっと手軽にするためにチャットボット導入したいけど
一日数回のデプロイのために、サーバを設置するのは... と思ったことありませんか？

もしくは、チャットボットは複数の小さな機能の集合物になりやすいですが
小さな機能を足していく内に気がつけばメンテナンスできないぐらいに機能が
膨大になってしまっていたということもあるのではないでしょうか？

そんな時の解決方法の一つとして「CIでチャットボットを起動する」ってのをやっています。

以下は CIによるdeployment周りのやりとりをSlackでしている様子です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/62929/c29ec220-3905-6280-3df0-ee29834ad97c.png)


レシピとしては

- CircleCI 
- [ngrok](https://ngrok.com/) 
- 応答用のシナリオスクリプト (Python) 
- 社内用のSlack App (Slack Token発行 + エンドポイント)

の組み合わせで実現しています。

CirlceCIのインスタンスはサービスの性質上IPの固定化が難しいですが
それをngrokで補っています。

**ngrok** は ローカルで立ち上げたサービスを コマンドで簡単にWeb上に公開できる便利サービスです。
https://ngrok.com/

開発のデモの用途とかでよく使います。
無料版では、生成されるURLはランダムですが
有料版を使うと ドメインの固定化もしくはビジネス板であればサブドメインの利用もできます。

これを使うことで CI上に立てたサーバをSlackのチャットボット用のサーバにすることができます。
ローカルで jsonを受け取って jsonを出力するだけのスクリプトです。
多少の条件分岐を書けば、ちょっとリッチなインタラクティブなChatOpsが実現できます。

CIが死ぬと同時にサーバも死んでしまうようなサーバですが Yes/Noの確認を行う程度の
用途としては十分です。

やっていることはAWS Lambda や Cloud FunctionsをはじめとするFaaS でも実現できると思いますが
応答用のスクリプトは簡単にローカルでも実行できるため開発がしやすいですし、
ngrokというサービス自体がモジュールとして単機能で 手軽かつ頻繁に利用できるシーンが多いため

この組み合わせが個人的にとても気に入っています。

開発の注意として

- ジョブのタイムアウトを導入して、ユーザからの反応が無い場合にもすぐ終わるようにしておきましょう。
  CIが落ちたあと中途半端に応答のボタンが残っているとUXは悪いです。またタイムアウト時間が数分程度であれば、他のジョブへの影響も少なくなります。

- 同時に エンドポイントが複数できていなかを起動時に確認する

必要がありますが、簡単につくれるので
みなさんオススメです。


おわりに
----

いかがでしたでしょうか？
CircleCIは色々な面で優れた機能をもっており、アイディア次第で様々な用途で利用することができます。
気がつけば、CircleCIのステマとなってしまっていましたが

お楽しみいただけましたでしょうか？

こんな使い方もあるよ！というご意見募集しております。