クラウドワークス エンジニアブログ

日本最大級のクラウドソーシング「クラウドワークス」の開発の裏側をお届けするエンジニアブログ

AWSで動いているサービスをHerokuに移行した話

f:id:Tomato-360:20170802142647p:plain

こんにちは。好きなオーラバトラーはレプラカーンの那須(@nasum)です。ハイパー化には衝撃を受けました。

今回はAWS上で動いたサービスをHerokuに移した話を書きます。

背景

Webアプリケーションを動かす環境として、Amazon Web Services(AWS)やGoogle Cloud Platform(GCP)といったクラウド環境を利用するケースが多いと思われます。クラウドワークスでもAWSを活用しており、EC2でインスタンスを立ち上げRDSでデータベースを構築し、ELBでロードバランシングするなどクラウド環境をふんだんに活用した構成となっています。

クラウドワークスの提供するサービスの1つであるクラウドテックもAWS上で構築され上記のような構成でアプリケーションを構築していました。幸いにして事業は伸びていてこれからクラウドワークスを支える柱として存在感を出していけるサービスとなっています。

しかしAWSを用いたサービスを運用していく上で問題も色々出てきていました。

問題

問題としては以下の3つがありました

  • インフラの人員不足
  • コード化されていないインフラ
  • 積もっていく要求

まず問題の1つとしてインフラの人員が不足していました。クラウドテックのチームにはインフラを専門とした人員がおらず、もし何らかの脆弱性が発見された時すぐに対処できる状態ではありませんでした。アプリケーションがこれからどんどん大きくなり事業的に重要になってくることが見込まれるにもかかわらず、セキュリティに不安を抱えているというのは避けたいところです。

問題の2つめとしてはコード化されていないインフラです。Chefなどでインフラがコード化されていないため、Rubyのバージョンを上げるには一つ一つサーバーに入って手動で上げる必要がありました。アプリケーション開発にスピードを求められる昨今、インフラのアップデートに時間がかかってしまうというのは由々しき問題でした。

最後の問題は積もっていく要求です。サービスを大きく成長させるための改善や機能追加のアイディアは日々増える一方で、エンジニアはサービスの成長に寄与する施策にかける工数が大きくなりがちで、その基盤を支えるインフラの整備が後回しになっていました。

以上の問題を解決するためにAWS上で構築されていたアプリケーションをHerokuに移すことを今回決定しました。インフラの管理を楽にし、エンジニアはアプリケーションの開発に集中できる状態を作り、事業に貢献していくのが目的です。

移行作戦

移行の作戦は以下のようにたて、段階を踏んで実行しました。

  • 現状の把握
  • Herokuのアドオンの調査
  • HerokuでStaging環境を作って手動テスト
  • 移行の手順書の作成
  • リハーサル
  • 移行

以下各段階について細かく書いていきます。

現状の把握

まず一番大変だったのが現状の把握でした。クラウドテックには途中からジョインしたので、ほとんどインフラの情報を知らない状態からのスタートでした。

方法としてはまず愚直に社内の情報を洗いました。社内Wikiから情報を探し、今回の移行のためにQiita:Teamにまとめていくという作業を延々と行いました。これを行っている間はほとんど日本語との格闘だったと思います。

f:id:Tomato-360:20170801125323p:plain

▲Qiita:Teamでまとめた文書。書くことで記憶にも残った。

Herokuのアドオンの調査

インフラの現状を確認できたら次はHerokuに移行するにあたり、必要になるアドオンをまとめました。Herokuはミドルウェア系はほとんどアドオンとして用意されているため、クラウドテックで使用していたMySQLやRedisなどはほとんどHerokuのアドオンを使いました。

ここでの調査はアドオンの料金なども含めています。実際に必要となる要求に従ってプランを選び、いくら掛かるかも見積もりを行いました。

HerokuでStaging環境を作って手動テスト

使用するアドオンが決定されたのでHerokuのステージング環境でテストを行うことができます。

Staging環境を構築するにあたり、Herokuの流儀に合わせるためにコードを編集しStaging環境を構築しました。

Staging環境が構築できたらちゃんとHerokuで動いているか手動テストを行います。この手動テストは愚直にすべての画面を手動で動かしテストを行います。アプリケーションの機能やURLをまとめたSpreadSheetを作り、手動で一つずつ動作確認を行いました。

割としんどくて馬鹿げている作業ですが、プラットフォームを移行するという重要な失敗できない作業は現状人手でやるしか方法がありません。歯を食いしばって4人で分担して作業を行いました。

f:id:Tomato-360:20170801131937p:plain

▲SpreadSheetで管理していた一例。画面名・URL・担当が書かれている。

担当を決めてその範囲でテストを行うという手法は、クラウドワークスのRailsのアップグレード時に行った作戦を参考にしました。

engineer.crowdworks.jp

移行の手順書の作成

動作確認ができたら次は手順書の作成です。今回はプラットフォームの移行なのでDNS周りも絡んでいて非常に厄介でした。

手順書作成で気をつけたのは

  • AWSで動いているものを動かしつつHerokuに移行していく方法
  • 前提条件・終了条件
  • 切り戻しを始めるタイムリミット
  • リリース作業の状態遷移図

の4つです。

AWSで動いているものを動かしつつHerokuに移行していく方法としてざっくり手順を書くと、

  1. AWS側でメンテ画面を出す(DNSはAWS側を向いている)
  2. Herokuで使用するDBにデータを引っ越す
  3. Heroku側で動作確認をする
  4. Heroku側でメンテ画面を出す(まだDNSはAWS側を向いている)
  5. ネームサーバをHerokuのアドオンのDNSサーバPointDNSに切り替える
  6. 切り替わるのを待つ
  7. 切り替わってHeroku側のメンテ画面が出ているのを確認する
  8. タスクをスケジューラに登録する
  9. メンテ画面を閉じてサービスが動くのを確認する
  10. メンテ完了

という手順を行いました。

この手順を誰でもできるように叩くコマンドをちゃんと列挙し、コピペで全てできるように手順書を構築しました。切り戻しの手順も同様に書き不測の事態にも備えました。

ある程度書いたらレビューを依頼し、認識不足のところや曖昧になっているところを指摘してもらい、手順書の完成度をあげていきました。このレビューを行うというところはわりと大事で、どうしても自分だけで手順書を書くと甘く見積もりがちになってしまうので、経験豊富なメンバーが近くにいればレビューはちゃんと行ったほうが良いです。

またレビュアーとのコミュニケーションを円滑にするために、状態遷移図のようなものを書くことも大事です。

▲状態遷移図、というより双六

状態遷移図を書くことで文書では説明しきれなかった情報を伝えることができるので認識を合わせるのに便利です。

リハーサル

Staging環境を用意し、手順書がかければあとはリハーサルを行います。

リハーサルはできるだけ現状を再現したものを用意できるとよいです。今回は本番とほぼ同じ状態を再現したStaging環境がすでにあったので、これを用いて移行のリハーサルを行いました。

またクラウドテックでは、ネイキッド・ドメインでサービスを提供していたために、DNSのネームサーバ切り替えも必要になりました。そのため新たなテスト用のドメインを購入し、AWSのRoute53からHerokuアドオンのPointDNSへの切り替えが正常に行えることを確認するためのリハーサルも行いました。

リハーサルを行うときは正常に移行できるパターンと、失敗して切り戻しを行うパターンをちゃんと行うのが大事です。今回は、移行作業の途中で切り戻しの判断を行いましたが、事前にリハーサルを行っていたことで、スムーズに、安全に切り戻しを行うことができました。プラットフォームの移行は何が起こるかわからないのでリハーサルで切り戻しまで確認を行うのが大事です。

移行

ここまで行えばあとは移行当日に手順書に従って実行するだけです。移行の時期はクラウドテックのサービスの特性上、月末月初は行うことができないので、月中の2週間がリリースタイミングになりました。

移行する際事前に事業部側と話を通しておくのも大事で、移行作業中の広告をストップしてもらったり、動作していないことにあとで気づいた時、ユーザに通知する方法を相談したりとやることは多いです。大事なのはプラットフォームの移行は開発だけの問題ではなく、事業全体も関わってくるということを意識するということです。

移行当日はマージとリリースを最小限にとどめ、深夜メンテに備えます。深夜メンテ中に問題が発生しなければ成功です。

MySQLはAWSのバージニアリージョンのRDSを利用

Heroku移行にあたりサービスの要であるDBをどうするかは慎重に考えねばなりませんでした。

一番楽に済ますのはDBを現在使用している東京リージョンのRDSを継続利用することです。しかし、Herokuはアメリカにデータセンターを持つことから、アプリケーションがDBにアクセスするためにアメリカ・日本間を往復してしまい、DBアクセスのレイテンシが増大してしまうという問題がありました。実際Herokuで動かしているアプリケーションのあるページを表示するときに、データベース接続にかかっていた時間が東京リージョンでは 3640ms と、許容できないほど遅い結果になっていました。

なので今回はバージニアのリージョンのRDSを使用することでレイテンシをおさえることにしました。何故バージニアのリージョンにしたかというと、Herokuのサポートに問い合わせた結果 US east region という回答が得られたからです。ちゃんと聞くのも大事です。

バージニアのDBに接続した所、データベースアクセスにかかった時間は 35ms 程度に短縮されました。日本とアメリカの遠さが伺えます。

ちなみにHerokuのアドオンでClearDBというMySQLのアドオンがあり、それも検討したのですが、レプリケーションの機能がないため見送りました。

移行時のトラブル

今回の移行の実施にあたり、1度切り戻しを実行しています。

起きた問題

起きた問題はSSLの証明書を発行できなかったことです。HerokuのダッシュボードからLet`s Encryptを用いてSSLの発行が行えるのですが、正常に発行されずHerokuのダッシュボードがエラーを示しました。何度か再トライしてうまくいかなかったため、手順書にしたがい切り戻しを行いました。

原因と対策

原因はDNSがまだAWS側を向いているうちに発行のオペレーションを行ってしまったため、Let`s Encryptの認証が正しく行われなかったことにあるようでした。

Let`s Encrypt では certbot が認証用のキーを配置し、それを認証局が確認しにいかないと行けないのですが、DNSがまだAWS側を向いていると認証用のキーの確認が行えず、認証ができずSSLの発行が失敗するようでした。この確認も実際HerokuのStaging環境で再度確認し、失敗と成功を確認しました。

対策としては、ネームサーバの切り替えが終わったことをちゃんと確認してからSSLの発行オペレーションを実行するようにすることで対応しました。

この対策の難点としては、ネームサーバの切り替えが終了したあとHeroku側で表示するメンテナンス画面がhttpsでアクセス出来ないということです。今までhttpsでアクセスしていた人はメンテ画面が見れなくなります。画面が見れなくなることから問い合わせが発生する可能性がありましたが、SSLの発行自体はStagingで確認した所15分ぐらいで発行できたため今回は許容しました。SSLの発行が終わりメンテ画面がhttpsで閲覧ができることを確認した後次の作業を行いました。

まとめ

以上ざーっとまとめてみました。AWSからHerokuへ移行する苦労が何となく伝っていると幸いです。これに手掛けた時間がどれくらいか書いてなかったのですが、だいたい3ヶ月ぐらいでやりました。

大事なことは準備を怠らないことと、リハーサルをちゃんと切り戻しまで行うことです。もっというと誰でもできる状態になっているのが理想です。

細かい問題点は結構色々あって、ここで書くと長くなりすぎてしまうためにだいぶ割愛しました。細かい話や失敗話が聞きたければ適当なワインあたりを飲ませるとべらべら喋ると思うのでおすすめです。

We’re Hiring!

クラウドソーシングのクラウドワークス では、フリーランスを支援する聖戦士(エンジニア)を募集しています。

www.wantedly.com

© 2016 CrowdWorks, Inc., All rights reserved.