AWS API Gatewayで軽量WEBサイトを構築

前回は入り口の準備をしたので、楽しい中身の話をしていくのですが、実はそんなに大した話ではありません。普通にWEBサイトを作るだけです。

API Gateway を使って軽量なWEBサイトを作れたら、半分はこんな良い感じのことがあるかもよってのと、半分は暇を持て余したエンジニアの娯楽じゃねーかくらいに見てもらえれば幸いでござんす。



目的

軽量情報の取り扱い

わりと長く、INFOレベルの情報の扱いに悩みがありました。

例えばすぐ見る必要はないけど、たまに見るために残したいレベルのアラート。毎日収集・集計してるパフォーマンス関連の記録だけど、見るのは月イチくらい。そういう、残さないわけにはいかないけど、残す場所に困る情報をどうするか。

そういう情報の例を上げてみます。

SNS → Email のMLに送る
各ユーザーに無駄に蓄積されるし、実際必要なのはほぼ最新数件のみ。アドレスと受信者リストの管理も面倒だし、ていうかEメールとかそろそろ排除したくねっていう。

手動でダウンロードして閲覧
とりあえずS3とかに蓄積だけしておいて、必要なときに手元にダウンロードして、テキストエディタとか表計算ソフトで表示する。マジださくねって。

WEB用フレームワークとインスタンスで管理画面
アプリケーションをサクッと作るのはいいけど、インスタンスが無駄。T系のEC2すら起動したくないレベルにCPUリソースが無駄無駄無駄。

などなど。必要とする頻度が低いので、グループチャットに送るとかも、SRE的観点では日々のノイズとなって良くない。こいつらを、なんとかしてぇなぁと思いつつ、そっとしておくよくあるヤツでした。

ピコーン(AA略

年末年始に期限が切れそうなリフレッシュ休暇をくっつけて長期休暇してたら、開幕やる気がでなくてPythonで気分転換でもすっかなーって考えてたら、ふと電球が光って API Gateway + Lambda Python でWEBサイト作ったら楽しくね?

ってトイレで思いついて、ついでに役に立って負債にならないよーにできそう!ってことで手掛けた次第。つまり俺のヤル気の礎でもある。

流れだけみたら完全に手段先行型のクソエンジニア:-)


WEBサイトの仕組み

API GatewayでWEBサイト!?

AWS API Gateway の『API』とは──

昨今だと、システムとシステムが情報をやり取りしたり、特定の処理を命令するような、プログラムの一部であるイメージが強いと思います。実際私も、API Gatewayを最初に使った時は、JSONでリストを返すようなものを作りました。

名前に『API』がついてるからHTMLを返すと違和感があるかもだけど、中身はなんでもやりたい放題のただのPythonだし、むしろAPI GatewayがHTTP対応してきた、その真の意味を俺が与えてやる!くらいの勢いでやったるでごわす。

自分、クラウドでお茶目なことすることに定評ありやす😎

サーバーレスWEBサイト

公式だとこの辺。
一般の人でも、似たようなことやってそうなの見ましたが、それらは参考にしません。なぜなら、俺がやりたいだけだから。

クライアントがブラウザで、サーバーがAPI Gateway HTTP版。
リクエストがHTTP(S)で、レスポンスがHTML + Javascript。

Content-Type は text/html が基本。必要があれば、text/plain や application/json も返せるようにしとけばよろし。

使用するもの

構築に使うものは以下の感じ。意地でも常駐課金はしないスタイル。

S3 + LifecycleJSONデータ置き場。定期削除で整理・節約
ACMAPI GatewayのSSL/TLS
API Gateway v2 HTTP + Authorizer認証付きのHTTPS入り口
Lambda Python3認証・フレームワーク・データ処理など
jinja2Viewのテンプレート
TabulatorJSONを表で表示

これだけで何したいか大体わかるでしょう。PHPやRubyでViewをイジったことはあるけど、Pythonではなかったから、単にやってみたかったという。ある意味、正しいエンジニアリング仕草である(キリッ


S3にデータ保管

今回は、RDSのスロークエリを管理画面で簡単に見れるようにするとしましょう。

元々、1日に1回、1日分のスロークエリログを取得・集計したデータを作成していました。それを、適当に成形して SNS -> Email に送っていたのを、JSONにしてS3に保存するように変更しました。

  • 各サービス用アカウントから、SRE用アカウントのバケットへ集約保存
    • s3://$BUCKET/slowquerylog/$SERVICE/YYYYMMDD_HHII/slowquerylog.json
  • 別垢から送れるようバケットポリシーを編集
  • Lifecycleで数十日単位でストレージクラス変更や削除

  • これを取得して、見やすくしてあげるだけです。
    (スロークエリの集計については、別途記事にするかもしないかも)


    ルーティング

    ほぼ、前記事と似た内容なので、端折りますが

    lambda_handler をこんな風にして、リクエストパスと関数名を紐付けて実行したり、適切なレスポンス形式で返したりします。

    今回のは小規模なので、同ファイルに def を追記しましたが、もう少し規模が大きい場合は、ファイルを分けてクラスを読み込む形にするなど、お好みで改良していくことになるでしょう。

    もしくは、既存の軽量なフレームワークをうまいこと組み込むとか、そういうチャレンジも楽しいかもしれません。


    トップページ

    path = / の場合は、default としているので、こんな感じ。boto3でデータを読み込んで、Viewに必要な変数を作成し、HTMLを返します。(細かい処理部は独自のクラス分けしてるので割愛)

    View生成

    Viewはここでまとめていて、

    その先の module はこんな感じ。テンプレートファイルを読み込んで、値を渡してHTMLを生成します。

    なので、Lambda で使うライブラリとして、./python/ 配下に jinja2 をインストールしておきます。(私の場合はレイヤーとしてアップロードしています)


    テンプレート作成

    メインのテンプレートでは、共通テンプレートを読み込みつつ、メインコンテンツを生成。

    共通となるテンプレートで上下を記述。tabulator のCSSだけ、面倒になってここに記述。(必要なときにBODYで読む技術がワイになかった)

    jinja2 のドキュメントをみたりググりながらやれば、記法はとてもシンプルですぐ慣れます。Pythonのようで微妙にPython3じゃない感じがあるけど、まぁほぼPythonなので。

    仕上がりView

    シンプルなリストの出来上がり。



    このくらいが最初の練習としてはほどよい成功体験。


    スロークエリログ

    トップページからSlowQueryLogに遷移したら、そのサービスの最新データを表示しつつ、過去データも選択できるくらいにしときます。

    いちいち表示用の表をデザインするとか時間の無駄なので、Tabulator を使ってJSONを記述してカスタマイズするだけでいいようにします。

    JSONデータ作成

    S3からデータを持ってきて、json.loads してゴニョゴニョ成形とかしてから、json.dumps で一行の文字列にしてViewに渡します。


    Viewコンテンツ

    ガツンとJSONを記述しつつ、表のカスタマイズを書きます。


    include “tabulator.tpl” には、Javascriptを外部から読み込まさせてもらっています。


    JSONの中身

    Tabulator に読み込ませたJSONは一行ですが、jq で表示するとこんな感じ。各サービスで集計した基礎データに、日時文字列など Tabulator で成形できないものはPythonで作って追加しました。

    Tabulator でも前後の行のデータと照らし合わせて if とか色々使えるので、見た目を整えるためにどっちでやるか、を考えるのが楽しいところ。


    仕上がりView

    ブログ用にデータと見た目は適当に編集しましたが、ゲージで色表示したり、項目の並び替えができたり、ページングがついたり、いろんな機能がついています。



    表のテンプレート選択を筆頭に、行単位・セル単位、プログラムちっくなカスタマイズなど、本当に多機能ですが、ドキュメントを眺めて遊んでいれば、すぐ慣れてたいていのことはできるようになります。

    自分でHTMLやCSSを書く必要がほぼない、というだけで、優先順位の高くないデータをさらりと見れるようにしたりする気力が湧きやすくなると思いませんか。「あぁ、JSONでS3に置いてくれたらいいよ」みたいな軽いフットワーク。

    RDS管理画面にスロークエリログを取りにいくのってかなりダルい部類なのに中身もアレなわけで。それを全サービス分、いつでも好きなときに、集計結果を極小コストで見れるように!なんということでしょう~♪




    今回の仕上げたモノによって、自分が満足するという1番の目的と、軽量データの処遇というお悩み解決は果たしたわけですが── これを軸に改良していくことで、EC2インスタンスを排除できる可能性を感じるわけです。完全に後付けですけど。

    たとえT系インスタンスでも、EC2があるだけで起動コストと管理コストが大なり小なり発生するわけで、それをこういった少しの工夫で無くせるかもしれない、というのは意外に大きい気がしています。

    開発環境やフレームワーク的には、規模に合わせて、より整備する必要はあるので、インフラエンジニアに数少ないプログラムの楽しみの1つとして温めていきたいと思います:-)