(株)うるる に2015/06初に入社してから2018/08末で、インフラのカイゼンに一区切りついたのでまとめます。
10年モノというのは うるるで運営しているサービスが最長で10年 ほど経ってスゴイことになってました。
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移設
というように段階を踏んで実施しました。
総括
いやもう本当よくやったよ私。自画自賛。