Apache/Nginxによるリバースプロキシ(歴史的経緯が満載)をALBによって再実装した話

概要

これまでに終了したサービスなどの事情によりデータセンター上でApacheやNginxを使って、はてなで所有している様々なドメインに対するリバースプロキシを構成していました。簡単に言うとリダイレクトするだけなのですが、 48個程度のドメインとリダイレクト先の対応関係がありました。歴史的経緯というやつですね。これらのリバースプロキシの利用状況を調査し、統合方針の策定、ALBで再実装し、Route53でALBに切り替え、つい先日データセンター上のリバースプロキシたちを退役させることができました。今回はこの一連の対応での苦労ポイントについてご紹介します。

利用状況調査

2つのロール、合計5台のXen DomUでこれらのリバースプロキシは動作していました。幸運なことにWebサーバで読み込まれていた設定ファイルは1つのファイルにまとまっており、利用状況調査で難航することはありませんでした。またすべての設定がバージョン管理されていたことも良かったです。

調査項目は、

  • HTTPリクエストを受ける際のHost
  • リダイレクト先のURIパターン
  • ALBで実現可能か
  • リダイレクト内容(ホスト変更のみ/ホスト変更とプロトコル変更/ポート番号変更とホスト名変更)

としました。もし設定ファイルが複数のファイルにまたがっていたり、正規表現などを利用した複雑な条件でのrewrite設定などが入っていたら調査にかかる工数が膨れ上がっていたことや手戻りが発生していた可能性があります。ゾッとしますね。ここまで調査を終えた時点でチームに共有し、ALBで実現可能かどうかを最低限のテストパターンで実験することにしました。テストパターンの組み合わせは以下のようになりました。これ以外はもともとのリバースプロキシで実現されていなかったためテストパターンとしていません。

  • リスナー80、ホスト変更のみ
  • リスナー80、プロトコル変更のみ
  • リスナー80、ホスト変更とプロトコル変更
  • リスナー443、ホスト変更のみ
  • リスナー80/443以外のポート、ポート番号変更とホスト名変更

すべてのパターンをALBで実現可能ということと、リダイレクト先がIPアドレスの場合は対応できないことがわかりました。また後述しますが、この時点での実験内容はAWSのWeb画面であるマネジメントコンソール上で行っているという前提があります。はてなではCloudFormationによる構成管理が行われていることや、aws-cdk利用の機運の高まりもあるので今回のALBに関する設定全てをコードで管理したい欲求はチーム内で共有できていました。

統合方針の策定

  • 今回作成するALBは多くのFQDNを収容することが想定されるのでCloudFormationなどを使ってメンテナンスしやすい状態で構築するという
  • 2つのロールで実現されていたリバースプロキシたちを1つのALBにまとめる

などの方針策定をテックリードが行いました。終了サービスに関するリダイレクトをALBで実装しない判断もこのタイミングで行われました。

ALBで再実装

方針は決まったものの、実際実現できるのだろうかと不安になった点がありました。ALBのリダイレクト設定をCloudFormationなどで扱えるのかどうかがわからなかったからです。実際、再実装のタスクに取り掛かろうとしたタイミングではCloudFormationからはALBにおけるRedirect Actionの設定を行えない状況にあることがサポートへの問い合わせでわかりました。そのため一旦タスクを塩漬けにしました。

しかし、下記の記事の通りCloudFormationで実現できる見込みが立ちました。ありがたいアップデートでしたね。 https://dev.classmethod.jp/cloud/aws/aws-cloudformation-update-support-resource-and-using-elbv2-listener/

塩漬けにしていたタスクに再び着手しましたが、48個程度のドメインとリダイレクト先の対応関係をCloudFormationのYAMLファイルに落とし込む必要がありました(結果的にYAMLファイルは1000行を超えました)。これを手作業で行うことはできないと判断しました。なぜなら間違えが発生しそうであること、実装者である自分には集中を切らさずに手作業できる自信がないからなどの理由がありました。筆者はRubyが好きです。pryで処理を止めてデバッグできたり、漸進的にコードを書くことができる点が好きです。こうした利点を生かしてCloudFormationのYAMLファイルを部分的に自動作成するプログラムをRubyで書くことで手作業を避けました。

Route53でALBに切り替え

これらの再実装がうまくいったことをどのように確認したらいいのか悩ましいところでした。しかし、はてな社内においてはRSpecを利用したDNSのクエリテストの仕組みが存在しています。infratasterのinfrataster-plugin-dnsを使用したものです。今回の再実装においてもこの仕組みを利用しました。リポジトリのREADMEには以下のように書かれています。

クエリテストで infrataster を使用する利点は以下のとおりです。

  • 毎回、同じテストを実施することで、予期しない RR 削除/変更に気づける
  • dig などの手動テストではなく、機械的にテストすることで属人性を極力排することが可能

背景について補足説明をしておくと、はてなでは基本的にRoute53を利用してDNSのリソースレコード(RR)を管理しており、CloudFormation経由でこれらを管理しています。リバースプロキシに向いているトラフィックをRoute53でALBに切り替える作業も、CloudFormationのYAMLを書いて反映するのみで終えることができました。変更前後でクエリテストを行い、意図した結果になることを確認できたので安心して変更を行うことができました。

退役

切り替えが無事に済んだので、これまで仕事をしてくれていたリバースプロキシはめでたく退役することになりました。しかし、アクセスが来ていないことを確認してから退役したいという話になるのも当然の流れでした。アクセスログを確認、分析してみたものの判断に困ることとなりました。微妙にちょろちょろアクセスがあったのです…。この問題に関しては、アクセスログに記録されているIPアドレスとUser Agentごとに分類し、IPアドレスを逆引きしてどこからのアクセスがどのくらい多いのかを分析し、日本語で状況をまとめて判断をテックリードやプロダクトオーナー、チームメンバーに仰ぐことで捨てる勇気を持つに至ることができました。

まとめ

apache/nginxによるリバースプロキシ(歴史的経緯が満載)をALBによって再実装し退役に至るまでの技術的判断や技術的実装の概要を説明しました。レガシーシステムとの闘いは苦痛のように語られがちですが、計測・合意を行いながら進めることで現代的な形に生まれ変わることができると思います。むしろチャンスと捉えることもできそうです。今回はありがたいことに再実装に成功することができました。今後は可能な限り失敗についてのヒストリーも何かしらの形で共有したいなと思っています。