こちらの記事は6 things I’ve learned in my first 6 months using serverlessの和訳になります。
サーバーレスの世界は適切なツールさえ見つければミドルレイヤーを省けるのでとても良いものです。
10月に行われたServerlessconfの後、自分の会社を全てサーバーレスにすることに決めました。最初の2ヶ月は Python Flask appにLambdaを導入するのに必死でしたが、そのおかげでより良い方法を思いつきました。
そして6ヶ月後、私たちにとって4番目に大きいプロジェクトをサーバーレスでデプロイすることになったのです。以下の内容がデプロイするまでに私たちが学んだ教訓、意見です。
##レッスン1 Pythonの使用は避けましょう
Flaskは昔ながらのリクエスト、レスポンスのスタイルで、サーバーによって管理されるセッションがあるWebサイトにとってはぴったりのフレームワークです。とてもいいのですが、今の時代のインタラクティブなWebサイトにとっては輪ゴムと水切りワイパーで家を建てるようなものです。
昔のやり方:Python Flask appをElastic Beanstalkで起動し、データをRDSに保存する
Webページに動きを出すためにクライアントサイドをやっていくうちにJavaScriptを使わざるを得なくなっていきます。結局Pythonテンプレートをカスタマイズせざるを得なくなり、技術的負債を産み出してしまいます。
Flaskでの解決方法は複数の言語を使ってその場しのぎの解決策にますますなっていきました。このアプローチが間違っていると私はすぐに気がつき、なぜPythonをつかっているのかがわからなくなってきました。
Nodeに移行してからは全てが管理しやすく合理的で、一つの言語で済むようになりました。WebpackでのNode/Expressのシンプルな環境設定、そしてPythonデベロッパーからからかわれていたJavaScriptの厄介な構文が取り除かれたES6をも使うことができます。
Zappa/Flaskを使って同じようなことをするのは、恐ろしく過酷です。しかしLambda上で動くNode/Expressのアプリを作るのは5分で簡単にできます。なので私の会社はPythonを使うのをやめ、Javascriptのエコシステムを活用する事にしたのです。
モノリシックなLambda関数
では私たちは何を犠牲にしたのか。Pythonを使うデベロッパーはPythonのいいところを語りますが、実用的なJavaScriptの非同期処理に比べたらただの小道具でしかありません。それにもうPythonのバージョン2や3(アップグレードするかもわかりませんが)の心配もする必要がなくなったのです。少なくとも私たちのプロジェクトでは簡単に変更することができました。
Ben Kehoe はサーバーレスに関する自身の見解を訴えているので、そちらも合わせて見てみてください。
##レッスン2 ミドルレイヤーを省きましょう
サーバーレスの利点について気づくのにかなりの時間を要しました。私たちがウェブアプリばかり作っているからか、もしくは年かもしれません。
私たちが手掛けたいくつかのウェブアプリは、状況に対応するために、セッションを記憶するNode /Expressの層がありました。
- ユーザーが同じLambdaを何回もクリックしたと思い込んで間違った時
- DynamoDBにセッションIDを何度も何度も記憶させた時
いったい何をやっていたのでしょう。。。
「移行」の時期、私たちはラムダにWebサーバーのような働きを持たせていました。これは間違いであり、とても悪いことです。なので結局HTMLのページからJavascriptでREST APIを呼んでいました。このやり方はとても原始的で、メンテナンス性も悪くすぐにダメになりました。結局私たちはミドルレイヤーを無くしました。サーバーレスではミドルレイヤーは取り除かなければいけません。
状態はクライアント側で保持し、logicはLambdaで保持する
##レッスン3 Vueを使いましょう
全てをフロントエンドにまとめられるのはとても楽ですが、すぐにぐちゃぐちゃになってしまいます。最終的には恥ずかしさのあまりコードをチェックするのをやめてしまいます。「コードを確認しないこと」はデベロッパーにとっては致命的です。
シングルぺージアプリケーション(SPAs)の世界に入りユーザーインタフェースを作るにあたって、人気のReactと出会いました。Reactはとてもいいのですが、Webpack/Babelのセットアップや、JSXなどと学ぶことがたくさんあります。いつかは使うかも知れないものでしたが、早急に必要な代わりとしては荷が重すぎました。
幸いなことにVue.jsと出会い、私のサーバーレスの人生は至福を迎えました。Vueは1日で学べます。
Vue.js、 AWS Lambda、Travis CI、 そして Github を使って作ったページhttps://t.co/Ck6sz39ks4を見てみてください。元はHerokuにPug/Sass/Expressを使ってあげていました。コストはほぼ0になり、GitHubにバックアップされているので、コードがどれだけ汚いかを一目で確認できるようになりました。 — @danhannigan
Vueは私たちのデザインモデルにぴったりフィットしました。全てのコンポーネントが個々の内容、デザインとコードを管理します。これにより様々な顧客のプロジェクトや役割分担を管理するのが楽になっただけでなく、サーバーレスも可能になったのです。
このオープンソースのJavascriptフレームワークは優秀なデバッグのツール、とても優れた構成、そしてたくさんの時間を節約してくれるWebpackが備わっています。ルーターを置いて管理用のプラグインを使えばFacebookのエンジニアのように沢山のリアルタイムアプリを作ることができます。シングルぺージアプリケーションがこんなに素晴らしいなんて誰が思っていたでしょうか。
サーバーレスの観点から見て、Vueは全てのファイルをindex.html と bundle.jsのファイルにコンパイルします。主にS3にアップロードする為です。npm run build
がコンパイルするコマンドになります。
考えてもみて下さい。一昔前まではアプリを作るのにElastic Beanstalk や必要な時にはAutoscalingを使い、かなりの量のインフラを管理してたでしょう。
シングルぺージアプリケーションの醍醐味は「デプロイ」する時になります。index.html、bundle.jsやその他依存ファイルをCloudFrontと連携させたS3にアップロードするだけです。テキストファイルを管理するだけで、安定したディストリビューションとローディング、異なるバージョン管理、そして好きなデプロイ方法が提供されます。
スケーリングは自由自在で、使用した分だけ払います。そのためアプリのインフラ管理は必要でなくなります。
Vueでは基本的にはブラウザ内でデスクトップアプリを作ることができますが、それはユーザーエクスペリエンスを格段に上げる事を意味します。全ての状態はHTTPリクエスト無しで管理でき、トランジションといったスタンダードなUIトリックで誤魔化すことによりアプリケーションが正しく動作しているように見せることが出来ます。
##レッスン4 DynamoDBを使いましょう
多くの点でサーバーレスにするのに一番厄介なのがDynamoDBを正しく理解することです。。皆最初の段階で必ず何らかのミスをするので、全てを投げ出し、良くわかっていて使い勝手の良いRDSに結局戻ってしまいます。
私自身も今までデータベースに過剰なビジネスロジックを置いていたことは否めませんが、RDBMSはレガシーで拡張性に乏しく、アジャイルシステムには合いません。
DynamoDBは全く別の生き物です。きちんと使いこなせば、NoSQLデータベースはとても速く拡張性があり、余計なコストはかかりません。ですがどのように動くのかを見極める為に特に初めの段階でたくさんの時間を費やさなければいけません。
— Amazon Web Services (@awscloud) Apr 27, 2018
Dynamoのテーブルは空の文字列を挿入することはできません。そしてバックアップは自動ではありません。もしパーティションとソートキーを間違えたら、テーブルを一から作り直さなければいけません。SQLクエリに似せようとするとテーブルが少なすぎたり、時には多すぎたりしてしまいます。RDSに慣れていると、Dynamoはまるでエイリアンのように思えてしまいます。
沢山のチュートリアルや試行錯誤の後ついにDynamoDBを習得しました。以下が学んだことです。
-
DynamoDBがどのような仕組みになっているかを理解しないといけません。インデックスをどのように扱うか、クエリをどのようにデータにするか。全部知ってるべき事を学ばずに始めることは簡単ですが、結局失敗してRDBMSに間違ったタイミングで戻っていく人達が沢山います。失敗してもやり通さなければいけません。
-
DynamoDBを語る上であまり語られないことが、あたかもSQLのトリガーのようにストリームを使ってテーブルのイベントにコードを繋げる事ができる事です。これはとても頼もしいです。
-
DynamoDBが他のストレージシステム(RDBMS、 Redshift 、もしくはただのテキストファイル)と繋げられる事、そして急激なトラフィックの増加や膨大なデータを含んだデータベースに対応できることを忘れてはいけません。DynamoDBはレコードの有効期限を決めるTTLの機能があります。これは一時的なデータを他の場所にプッシュする際に大変役立ちます。
##レッスン5 Serverless Frameworkを使いましょう
Lambdaを使い始めた頃はイライラしながらAWSのコンソールに直接コードを打ち込み、ちょっとした事をやるだけなのにかなりの労力を費やしエラーメッセージが出る事に腹が立ちました。IDEと生産する環境が整っていなかったのです。
Serverless Frameworkを見つけた時はここ何年も味わった事のないような興奮を覚えました。
sls deploy
はとてもパワフルで、私たちが書いたコードをローカルから直接Amazonにデプロイします。もし何か不具合がありログを確認したいなら、sls logs -f functionname -t
をタイプしCloudWatchのログをローカルで確認することができます。
これにより全てが変わりました。Serverless FrameworkのCommitter達はAWSやGCPが最初から提供すべき事をやっているので賞賛されるに値します。Serverless Frameworkは素晴らしく、私たちに多くの恩恵をもたらします。
— Simon Wardley #EEA (@swardley) Nov 17, 2016
##レッスン6 JWTを使いましょう
従来のアプリではユーザーを一度承認したら、セッションIDによってそのユーザーを随時確認しています。この方法はとても便利で、1度認証を行えば、ユーザーのログイン状況やその期限についてはセッションIDが何とかしてくれます。
しかしこのやり方には落とし穴があります。サーバーがミドルレイヤーにある時でないと使えないのですが、私たちはそのサーバーを無くしてしまいました。さらにはクロスサイトリクエストフォージェリ (CSRF) といった外部からの攻撃にもさらされる可能性がある上に簡単には他のサービスにID をパスできません。つまりこのやり方はレガシーなやり方なのです。
レガシーな構成やCSRFの攻撃は避けたいものです。そこで登場するのが、JWTトークンです。これがどのように動作するかを学んだ時はとても心が穏やかになりましたが、説明には図を要します。
ステップ1、JWTをダウンロードし、全てのサービスに繋げます。
よくある最初のステップ:認可プロセスがJWTトークンを受け取る
次のステップが魔法のよう:どんなLambda関数でも受け入れてバリデーションをしてくれます。
基本的にはリクエストが送られる度に認証が行われます。クライアントは複数のサーバーレスコードと繋げることができます。セキュリティに強い上にモノリシック対策やCSRFはJWTには必要ありません。サーバーレスコード上で必要なのは、オーソライザーをカスタムし、JWTのヘッダーが有効かを確認するだけです。(ボイラープレートを使って)
JWTのせいで他の承認システムは難しく見えてしまいます。Auth0(たまにCognito)を使い始めてから他は見なくなりました。サーバーレス認証はとても簡単で効率的です。
— James Beswick (@jbew) Apr 28, 2018
##学んだこと
AWSを長年使ってきたにも関わらず、こんなに満足感を得たのは初めてです。EC2の分野に関しても沢山の人に助けて頂きました。Cloud Guruのサーバーレスコンフェレンスの後、未開拓の分野で希望の光を見つけた気分になりました。
— Serverlessconf (@Serverlessconf) Apr 23, 2018
私たちの最初の試みでは今あるツールやテクニックを使おうとして失敗しました。軌道に乗り始めたその数ヶ月後、正式に100%サーバーレスでプロジェクトを作り始めました。コードの移行にあたり起こった様々な困難がいい勉強になったと心から信じています。
私たちはサーバーレスのインフラや自由自在なスケールを持ち、70 - 90%のコスト削減をしたスムーズなリアルタイムSPAアプリを作っています。その結果に私は嬉しさと驚きを隠せません。今まで以上にサーバーレステクノロジーが革命的なアプリをクラウドの世界にもたらす事を信じてなりません。
翻訳協力
Author: James Beswick
Thank you so much for letting us share your knowledge!
翻訳/記事作成: @azumana
記事の翻訳から作成まで幅広くフォローアップ頂きましたm(_ _)m