こんにちは。BIGLOBE 永末です。 BIGLOBE では近年クラウドの活用を積極的に進めています。
この度、独自開発していたレガシーシステムを、Amazon Web Services(AWS)上にサーバレス構成で作り直しました。簡単な構成なのでさくっとAWSへ移行する予定だったのですが、当初思い描いていたようには進まなかったので、失敗の過程を含めて移行の概要を紹介させていただきます。
システムの概要
作り替えを行ったのは、利用者のIPアドレスから国情報を解析し、国内or国外向けの静的コンテンツを表示するWEBサービスとなります。
※実際のサービス仕様は上記とは異なります(説明のために改変・省略しています)
AWS上でのシステム構成
AWSへ移行するにあたり、まずはサービスシステムのAWS上での構成を検討しました。 下記が当初考えていた構成です。
Route53 の位置情報ルーティングを利用して、国内or国外向けの CloudFront に振り分けています。コンテンツデータはS3に格納します。国情報を判定する独自プログラムが不要となり、利用するマネージドサービスも3つだけとシンプルでいい感じです。
念のため AWS に詳しい社外の人にもレビューを受けて「これで行きましょう」となりプロジェクトを進めていました。が、実際に構築してみたところ CloudFront の仕様で同じ名前のCNAME(代替ドメイン)を2つ以上の CloudFront ディストリビューションに設定することができず、本構成は実現できないことが判明。他の構成を検討することになりました。
次に考えたのが下記構成です。
CloudFront でセットされた CloudFront-Viewer-Country ヘッダを Lambda@Edge で解析し、国内or国外のコンテンツに振り分けます。判定プログラムが存在するので、IPアドレスの判定をカスタマイズできるというメリットはあるのですが、判定プログラムの開発と保守が必要になってしまうので、この構成も没になりました。
他にも API Gateway と Lambda を使った構成など色々検討し、最終的に採用した構成が下記となります。
最初の構成案と似ていますが、CloudFront の1つを ALB に変更しています。国外向けのコンテンツは ALB の固定レスポンスで表示します。ALB の固定レスポンスは1024文字以内と制限が厳しいのですが、今回はコンテンツサイズが小さかったため、この構成を採用することができました。
ALB の料金が発生してしまいますが、全てマネージドサービスで運用することができ、判定プログラムも不要であることから、本構成を採用しました。
CloudFront のログ検索機能の実装
サービス部分のシステム構成は決まってうまく動いたので、次に CloudFront のログを検索する機能に取りかかりました。
CloudFront のログは S3 上の複数のオブジェクトに記録されるため、アクセスログを検索しようとすると、該当時間帯のログオブジェクトを全てダウロードして検索をかけることになります。サービスの運用上もっと高速にログ検索を行える必要があったため、Athena を使って検索することにしました。ただ、全ログを Athena で検索すると AWS 利用料が高額になるため、Glue のパーティションを設定することにしました。
上記要件を満たすために考えたのが以下の構成です。
下記のように動作します。
- CloudFront が S3 へログを配置する
- 定期実行型でログ移動用の Lambda が実行される
- ログオブジェクトを Glue クローラで判断できる S3 パスへ移動する
- 定期実行されたGlueクローラーが Data Catalog にパーティションを作成する
- Athenaにてパーティション指定で探索が可能となる
- 定期実行型でお掃除用の Lambda が実行される
- 起動された Lambda が不要なパーティションを削除する
上記構成で想定どおり動作して開発が進んでいいたのですが、テストフェーズで問題が発生しました。CloudFront へのユーザアクセスがすごく少なく、S3 上に出力されたログが1行しかなかった場合、Glue クローラーがパーティション作成をスキップしてしまったのです。
調べたところ、Glue クローラーはオブジェクトの行数が少ないと、データの形式を判別するための情報が足りないことにより、処理をスキップすることがあるようです。AWSのドキュメントには書いてなさそうで、テストフェーズまで気付くことができませんでした(見落としている可能性はありますが..)。
実際のサービスでは常時ユーザアクセスがあるので、CloudFront のログが1行になることはないのですが、仕様としてよろしくないため本構成は没となりました。
その後、別の構成を検討して辿り着いたのが次の構成です。パーティション作成を Glue クローラーではなく Lambda で実行するように変更しています。
- CloudFront が S3 へログを配置する
- 定期実行型でログ移動用の Lambda が実行される
- ログファイルを Glue パーティション用のS3パスに移動する
- 定期実行型でパーティション作成用の Lambda が実行される
- 1ヵ月先まで Data Catalog にパーティションを作成する
- Athenaにてパーティション指定で探索が可能となる
Glueクローラを用いてパーティション作成を行うのではなく、1ヵ月先までパーティションを事前に作成するようにしています。これにより、ログの行数に関わらず、確実にパーティションが存在する状態にすることができました。
パーティションを数年後まで事前作成することも可能ですが、作成に時間がかかることと、他システムでも流用することを考え、定期的に数か月先まで作成する方式としました。
別案としてMSCK を定期実行することも考えましたが、実行頻度やパスが固定であることと、先にパーティションを作っておいた方が確実であるため、今回は本方式を採用しました。
ALB のログ検索についてはほぼ構成が同じなため、今回は割愛します。
本プロジェクトで得られた効果(予定)
「AWS上にサーバレス構成で作り直しました」と最初に書きましたが、実は 2020年6月現在、まだサービスインできていません。すみません。 本プロジェクトにより、以下の効果を期待しています。
- サーバレスになることにより、サーバ障害から解放される
- OS、ミドルウェアの脆弱性対応およびEoL対応から解放される
- 独自プログラムの保守から解放される
ログ検索部分の Lambda については、言語ランタイムの EoL対応などの保守が必要ですが、この Lambda は他の CloudFront を使うシステムでも広く流用予定です。
運用業務から解放されることにより、運用に使っていた時間を新しいサービスの開発に回すことができる見込みです。
最後に
シンプルな構成なのでさくっと AWS 化できると思ってやってみたら、意外と手間取った例を紹介させていただきました。
AWS のコンポーネントを組み合わせた絵を描いてみるとうまく動くように見えるのですが、実装してみると仕様の制限で動かなかった、ということがよくあります。簡単な検証をしながら本格的にプロジェクトを進めるのがよいかと思います。
以上です。
BIGLOBEではサービスのAWSへの移行に伴い一緒に盛り上げてくれるメンバーを募集しています。
※ Amazon Web Servicesは、米国その他諸国における、Amazon.com, Inc. またはその関連会社の商標です。