CircleCIを導入した話

## はじめに
レバレジーズ新卒エンジニアの[uramotot](https://qiita.com/uramotot)です。
現在携わっているリニューアルプロジェクトにCIを導入した際の、背景とCircleCIを選んだ理由について書いていきたいと思います。

※ 「CI」という単語は、この記事上では「CI/CD」という意味で書いています。内容自体はほとんどCDなので念のためｗ

## 背景
僕が所属しているリニューアルチームは、エンジニアが大体10人くらいの中規模チームです。
独自ライブラリや各媒体のリポジトリが90個くらい乱立しており、privateなライブラリはsatisを使って社内限定で配信しています。
エンジニアの人数が増え、リポジトリ数も多くなってきたことから、デプロイやsatisの更新にかかるコストが耐えられないものになってきました。
そこで、学生時代にCIツールを触ったことがある僕に白羽の矢が立ったという感じです。

## CI導入前
CIを導入した理由を書く前に、CI導入前がどのような状態だったか書いていきます。

### satisの更新
リニューアルチームでは、privateなライブラリ郡をsatisを使って限定配信しています。
satisは配信しているライブラリに変更があると、そのライブラリをビルドをし直す必要があります。
CI導入前は、ライブラリの変更を取り込むために、定期的にcronでsatisで配信しているライブラリを全てビルドし直していました(大体5分に1回くらい)。

※ satisについて詳しくは[こちら](https://getcomposer.org/doc/articles/handling-private-packages-with-satis.md)

#### 問題点
##### 1. 一回のビルドに時間がかかる
変更がない場合にもsatis.jsonにかかれている全てのライブラリのビルドを行うため、1回のビルドに無駄な時間がかかっていました。

##### 2. 変更が反映されるまで待たないといけなかった
ライブラリの変更がマージされても、cronの実行とsatisのビルドが終わるのを待たないといけなかったため、開発効率が落ちていました。


### ステージングサーバへのデプロイ
ステージングにデプロイする際には、まずsshでデプロイサーバに入り、手動でデプロイコマンドを叩いていました。
ステージングデプロイは、緊急の修正が取り込まれた時と、毎日17時くらいに毎日行っていました。

図にするとこんな感じ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/120358/a4812dfe-7ae3-d3bb-033d-e85cfb75e4ff.png)

#### 問題点
##### 1. ステージングサーバのデプロイに時間が取られてしまう
CI導入前のデプロイフローでは責任者が毎回デプロイサーバに入り、デプロイコマンドを叩いていました。
媒体数が少なく変更頻度も少なければこれでも問題ないのですが、開発段階で媒体数もそこそこあったため、緊急の変更があった際などに責任者の時間がかなり奪われていました。

##### 2. デプロイ時に初歩的なエラーに遭遇することがあった
これはタイトル通りですね。lockファイルのバージョンが上がっていないことや、phpのextensionがステージングサーバに入っていなかったことが原因で、デプロイが失敗することが何度かありました。
そのたびに、責任者は修正依頼を出さなければ行けない状態でした。

---

媒体が増え、エンジニアが増えたことで変更が多くなり、責任者のデプロイタスクのコストが増大したため、自動化しよう！となったわけです。

## CIツールの選定
CI導入前がわかったところで、次はどのCIツールを使うのか選ばなければいけませんでした。
当時の現状から、CircleCIを選んだ理由を書いていきます。

### 比較したCIツール
Jenkins
TravisCI
CircleCI

#### Jenkins
まず、CIツールの中で多分一番有名だとおもられるJenkinsについて調査しました。
Jenkinsの特徴としては、拡張性が高く、カスタマイズすればなんでもできることと、オンプレ上に構築することです。
記事も豊富にある人気のCIツールだったのですが、CI用にサーバを用意しなければならないため、そのサーバの保守・運用が必要になる事と、Jenkinsサーバの設定についてすべて把握している、Jenkinsおじさんが必要になる可能性が高かったため不採用にしました。

当時のメモも残しておきます。
##### メリット
- 拡張性が高く、なんでもできる
- オンプレ上に構築するため、IPが固定
- 記事も豊富

##### デメリット
- サーバを用意する必要があるため保守・運用が必要
- 本番を含めワークフローに組み込むため、導入は計画的に行う必要がある
- 管理を怠るとJobの詳細が作った人しかわからなくなってしまう

#### TravisCI
次に調査したのは、TravisCIです。
このCIツールは、先程のJenkinsとは違いCloud上にコンテナを建ててその上で色々な処理を実行します。
Githubとの親和性も高く、人気のCIツールだったので、これでも良かったのですが、コンテナにssh接続ができないので、CI上でエラーが発生した時にデバッグがしにくい事と、使い始めるのに$129かかってしまうので、CIを使ったことのないうちのチームでは提案しにくかったので不採用にしました。

##### メリット
- Cloudであるため、サーバの管理・運用は不要
- Githubとの親和性高め
- 記事も豊富

##### デメリット
- コンテナにsshで入れないのでデバッグしにくい
- $129がかかるため、CIをはじめて導入する際には提案しにくい
- Cloudなのでビルドの度にIPが変わる

#### CircleCI

結局導入した、CircleCIですが、TravisCIと同じでCloud上で実行されます。
サポートも充実していて、英語でメールを送るとその日のうちか次の日くらいに返事をくれます。
あとは、先程のTravisCIとは違い、sshでコンテナに入れるので、デバッグがし易いことと、無料で使い始められることから、CircleCIを採用することにしました。

##### メリット
- Cloudであるため、サーバの管理・運用は不要
- サポートが手厚い
- 記事も豊富
- sshでコンテナに入れるので、デバッグしやすい
- 無料で使い始められる
- 最近versionが上がってdockerやworkflowにも対応(Werckerっぽい感じになった)

##### デメリット
- Clouldなのでビルドの度に毎回IPが変わる

## CI導入後

CircleCIを導入することで、責任者がmasterブランチにmergeした瞬間CircleCIがデプロイコマンドやSatis更新コマンドを実行するようになりました。

Deployerを使っていたので、それはそのまま利用しました。
コマンドの実行にはEC2 Run Commandを使っています。

図にするとこんな感じになりました
![image.png](https://qiita-image-store.s3.amazonaws.com/0/120358/ec45f499-9c53-6159-9901-8c5292a952f1.png)

## まとめ
結果として、責任者がデプロイに時間を取られなくて済むようになり、定期的にデプロイしていたのが、1回のマージで頻繁にデプロイできるようになりました。

今回は自動デプロイの導入だけ行いましたが、課題はまだまだあります。この辺も解決次第記事を書いていこうと思います。

##### 1. デプロイ前のテストがほとんど意味をなしていない
デプロイ前に、phpunitを実行するようにしているが、ちゃんとしたテストがほとんど書かれていないため、ほとんど意味をなしていない状態です。
これに関しては今からテストを書いても工数に対して得られるものが少ないため、一旦おいています(時間も限られていますので)。
しかし、継続的にテストを実行する環境は出来上がったので、リファクタの段階で必要な部分からユニットテストを入れる提案していこうと思っています。

##### 2. Deployサーバの保守をしなければならない
折角CircleCIを導入してCIサーバを持たないようにしたのに、結局デプロイサーバのコマンドを叩いてしまっているので、オンプレにCIサーバを構築してデプロイしているようなものです。
ここも、AWS CodeDeploy等をいれることでデプロイサーバ自体なくしたいと思っています。