10年モノのインフラを3年がかりでカイゼンした

[(株)うるる](https://www.uluru.biz) に2015/06初に入社してから2018/08末で、インフラのカイゼンに一区切りついたのでまとめます。

10年モノというのは [うるるで運営しているサービスが最長で10年](https://www.uluru.biz/company/company_history) ほど経ってスゴイことになってました。

3年がかりなのは、インフラ大好きエンジニアが社内に少なくて、私の独り相撲で時間かかってしまいました。

カイゼンの内訳はざっくりこんな。

| 構成要素 | 2015/06初 | 2018/08末 | 
|----|-----|----| 
| CI | Jenkins | CircleCI |
| 監視と通知 | zabbix(ログインできない) | Datadog & CloudWatchの混成 | 
| MySQLサーバー | MySQL on EC2 | RDS (MultiAZ) | 
| メール送信 | EC2から直接送信とSESの混成 | Mailgunで固定IP | 
| crontab |EC2にSSHしてcrontab -e | wheneverでGitHub管理 | 
| crontabで動かしてるシェルスクリプト | EC2にSSHしてvi。SCPで配布 | GitHub管理 | 
| ログファイル | EC2のEBSにひたすら蓄積 | CloudWatch Logs |
| EC2の中身 | viして同ロールのEC2にSCPで配布 | AnsibleでGitHub管理 |
| Solrサーバー | Master/Slaveが1セット | Blue/Green構成 | 
| AWSアカウント | 1垢に複数サービスが雑居 | 1垢1サービス & VPCでprod/stg/devに分割 | 
| ネットワーク| EC2 Classic | VPC | 

## CI

いちおうJenkinsが立ってました。失敗して赤くなってるジョブが大半で、かといって誰が治すわけでもなく、よくわからないけど失敗したり成功したり、とにかく不安定でした。

CloudWatchのメトリクスで眺めて、EBSのIOPSクレジットの枯渇から激遅になって、Jenkinsジョブのタイムアウト設定で失敗になる、まで明らかにしました。その時の対処は、IOPSクレジット上限サイズの1TBのSSDのEBSを付けることと、同時並行で動けるJenkinsジョブ数に上限を設けることで、落ち着くようになりました。

とはいえ「Jenkinsおじさん」問題があるので、CIをどうにか民主化する必要があります。SaaSから検討して、TravisCIとCircleCIが最終候補になって、トラブルシュートをSSHでできるのを決め手に、CircleCIを導入しました。

8月末にCircleCI1.0が死んだときの2.0への移行作業はわりとキツかった。

## 監視と通知

計測、管理、改善の原則にしたがって、現状を可視化できるようにしたかったので。

zabbixが稼働して通知も来ていたものの、ログインできる人がいない。わけがわからないですね。社内に声かけて、EC2のSSH鍵とzabbixの認証に使ってたOpenLDAPのSSH鍵を入手して、OpenLDAPの管理者アカウントのパスワードを変更して、ようやくzabbixにログインできました。ついでにログインできる人が少ないので、共有アカウントを発行して、OneLoginに接続して、エンジニアなら誰でも見れるようにしました。

zabbixに入ってみると、監視項目がザル。EC2インスタンスは、エラーログの監視、ロードアベレージの監視、ストレージ空きの監視、程度。ダッシュボードも無い。

* 障害発生をユーザーからカスタマーサポートチームへの問い合わせで気づく、
* 営業メンバーがお客様のオフィスでデモしてる最中に白画面(HTTP 5xx)で気づく、
* 朝、出社するとオフィスがざわついてて気づく

こんな状況だったので、zabbixを超いい感じにしても駄目な未来がみえました。もっと簡単に管理できるもの、当時はSaaS型が流行りはじめたころで、NewRelicとかMackerelとかのSaaS型から、最終的にDatadogを選びました。

## MySQLサーバー

サービス本体のMySQLは入社時点でRDSになっていたのですが、社員がちゃんと関与していなかったサブシステムのMySQLがやばいことになっていました。AMIを取っているものの、mysqldumpでバックアップが失敗してる。このEC2が消滅したらどのくらい困るのかアプリのエンジニアに聞くと、いやそれは大いに困る、サービスのデータが数日抜けてお客様からクレームがくる程度に困ると。怪談です。

幸いにしてcron起動のバッチジョブのためだけのMySQLだったので、cronを止めて、mysqldumpして、予め立てておいたRDSに投入するだけでした。

## メール送信

AWS SESは、料金の安さやセットアップの簡単さなどから、まあ普通に使うサービスです。しかし、SESからユーザーまでのログを取れない、そのくせバウンスレートでいきなり止められたりする。トラブルに弱い。

SESから受け取ってくれないお客様もいて、その方々のために、EC2にpostfix立てて送信もしてました。バッチサーバーもWebサーバもメール送信するので、SPFレコードに全台のIPアドレスが記載してあるという。SPFレコードに記載できる文字数に上限があって、サービスのスケールの上限でした。テレビ対応で増強したときは諦めてました。

このあたりの運用改善を主眼に、Mailgunに移行しました。結果、

* SPFレコードはMailgunのみになったので、スケールの上限が外れた
* Mailgunの過去2週間の送信ログで、カスタマーサポートチームがお客様と会話できるようになった

## crontabと、crontabで動かしてるシェルスクリプト

6割くらいのシェルスクリプトはGitHub管理されていたのですが、4割くらいはEC2サーバーに転がっていました。そのEC2サーバーでオペミスこいてシェルスクリプトが消滅したら、どうリカバリするんだと。GitHub管理に改めました。

crontabの6割くらいは、リリース時にwheneverで投入していましたが、残りはcrontab -eしていたようです。オペミス消滅どうリカバリの流れで、GitHub管理に改めました。

## ログファイル

EC2のEBSにひたすら蓄積していました。EBS、高いんですよね。しかもトラブルがおきるとSSHしてシェル芸で調査するという。1台だけならともかく、複数台編成のウェブサーバーだと、もう1台でサンプリングで調べるみたいな状況でした。

ログを保管してくれるSaaSはいくつか出始めたころでしたが、安いのと、とりあえず保管できればいいしで、CloudWatchLogsを選択しました。

## EC2の中身

crontabの管理状況や、zabbix設定がそんなだったので、もはや何も驚きません。EC2インスタンスの中身はブラックボックス。秘伝のタレが継ぎ足され続けてて、構築手順はAMIから立てるしかない状況でした。

MySQLの追い出し、crontabのコード化、シェルスクリプトのGitHub管理、の流れで、Ansibleで管理することにしました。PuppetやChefがまあまあ辛くて、Ansibleならsshできれば動くしいいんじゃね？みたいに流行りはじめた頃でした。

* ps, chkconfig, netstatなどで稼働してるデーモンを調べて、
* /etcのどこかに散らかってる設定ファイルをかき集めて、
* ansible経由でEC2インスタンスに設置できるようにして、

というリバースエンジニアリングでansible化を進めていきました。最終的に、Amazon提供のAMIから立てたEC2インスタンスを新規作成して、このansibleコードを使ってセットアップして、アプリをデプロイして、動作に差異がないことをもって、ブラックボックスが解消できました。

## Solrサーバー

Solrなので、定義変更するとインデックス作り直しになるのですが、クラスタがひとつだけだと果てしない困難があります。クラスタがふたつあればいいじゃん、いわゆるblue/green deploymentだぜ、からのちょろちょろっと手順を整備して、capistranoとansibleも調整して、で実現しました。

## AWSアカウント & VPC

ここまでで、EC2内の諸々がGitHub管理されて、新規作成からansible適用とアプリコードデプロイで完全動作することが保証できました。

しかしEC2が立っているのは、EC2 Classicネットワークです。残念です。これがために、ALB, WAFが使えず、EC2のt2やc4,m4などの世代が利用できません。さらに、AWSアカウントはひとつで、全サービスがごたまぜになってます。いろいろと奇跡的です。

AWSアカウント移設をしつつ、移設先はVPCにする、という引っ越しをしました。そのときの予備調査が https://qiita.com/sasasin/items/17135d5c5465fc53d385 だったりします。

一度に全要素を引っ越すのは、サービスのダウンタイムと私の体力を考えると無理だったので、

* RDS移設 
    * ElasticIPで許可して、アカウント跨ぎで接続できるようにした
* Solr移設
    * blue/greenのスタンバイ側を引越先で稼働、blue/greenスイッチ
* ウェブサーバー移設
* バッチサーバー移設
* S3移設

というように段階を踏んで実施しました。

# 総括

いやもう本当よくやったよ私。自画自賛。