サーバーレス
使われてもいない時間帯に、常時稼働してるサーバーって無駄じゃない?リクエストが来た分だけ、処理すればいいじゃん!
サーバー監視とかめんどくさくない?ビジネスロジックだけに注力したい!
などなど、サーバーレスと言う言葉がバズワードになってる感があり、どうせ騒いでるだけしょ?っていうのはありますが、触ってもないのにディスるのも嫌なので、PlayPASSとは非常にマッチしてそうだったので、試しに実装してみました。
開発するにあたって
- 有名なところでは「サーバーレスフレームワーク」というNode.js製のフレームワークがありますが、すべて自分で1から試したかったので、不採用としました。
- Python製のフレームワークもあるみたいですね。
- 多くの部分がフレームワークだと隠蔽されているので、細かい調整とか、すべて自分で確認したかったので、フレームワークは今回は使用しませんでした。
どう実装する?
フロントエンドとAPIサイドを完全分離します!!
- これにより、実装の競合がなくなります
- 実際に開発している方はよくわかると思いますが、デザイン部分と、実装ロジック部分が混じった開発を行うと非常に手間がかかります
- FEエンジニアは、HTML,CSS,JSに注力できる
- APIサイドは、APIの開発に専念できます
- APIの仕様さえ決まっていれば、FEとAPI側でそれぞれ開発に着手できるメリットがあります!
- APIの設計、ドキュメントはSwagger等を用いれば、更に楽になります
- APIの実装が終わってなくても、モックも楽にできます
- これから話しますが、API GatewayでもSwaggerはサポートされているので相性はいいです
アーキテクト
単純な以下のようなアーキテクトになるかと思います
- フロントエンド
- S3 + CloudFront + (WAFアクセス制限)
- APIサイド
- API Gateway + Lambda
- Lambdaは、社内のAPIを呼び出すようにします(オーケストレーション層)
言語、開発環境
- フロントエンド
- HTML5
- Facebook製のReact.jsを採用
- HTMLの中にJS書くの?問題が、デザインとロジック問題と同じようにあります。
- その部分を取り除くために、プレゼンテーション層の部分に特化したReactを採用しました。
- プレゼンテーション層以外も実装している、Reactを利用したReduxというフレームワークがあるのですが、そこまでの規模でもないので、採用しませんでした。
- JS自体は、EC6で書いて、Babelで現行のJSにトランスパイルするようにします
- CSSは生のCSS、PostCSSとかでもよかったのですが、今回は生CSSで、、
- webpackを採用し、モジュールを管理します
- browserSyncの採用
- 開発する段階でも品質をあげたいので、1つブラウザ操作で複数のブラウザも同時操作できるものになります
- 上記は、すべてMacのローカルPC上で開発します。ローカルでサーバーを立ち上げ、開発します
- APIサイド
- Lambdaで使用する言語はNode.js採用
- フロントもJSゴリゴリ書くので、裏側もNode.jsにしました
- タスクランナーとして、Gulpを採用
- Lambdaの開発もMacのローカルPC上で開発します
- タスクランナーで、開発したLambda関数を圧縮して、S3にアップロードします
- APIの設計をSwaggerですると、API Gatewayにそのままimportできます。
- API Gateway用にカスタマイズしたSwaggerテンプレートもあります。
- Lambdaで使用する言語はNode.js採用
開発
APIの開発
今回は、以下のようなAPIを実装します
- 認証API
- プレイパスコードの確認API
- プレイパスコードの消費API
認証には、JWTを利用し、ログインを実現します。
各APIが、tokenを必要とし、そのtokenがなければaccess deniedになります。
API Gateway自体にアクセス制限はないので、認証なしのAPIを社内からのみ実行したい場合は、アクセス元IPが取得できるので、そこで判断するのがいいのかなと思います。
Lambdaに環境変数を設定することができるので、開発環境、検証、STG、本番と環境ごとに違う処理を走らせる事ができます。本番以外なら、アクセス制限をするみたいなこともできます。
Lambdaには、バージョン管理とエイリアスの機能があります。
API Gatewayには、ステージという機能があります。
Lambdaのエイリアスが、API Gatewayのステージと同期が取れていれば、うまくデプロイがまわせるのかな?と思います。
Lambda: バージョン:1, エイリアス:v1 API Gateway: ステージ: v1 API URL: https://hogehoge/v1/foo/bar |
フロントエンド開発
- プレイパスコードの入力画面とコード消費完了画面の2画面しかないので、Reactで実装します。
- さらに、2画面しかないので、SPAを導入します。そのためには、Reactだけではダメなので、React-Routerを導入します
- Reactはコンポーネントというものが基準なので、そのコンポーネントを必要な分用意します。
- 今回だと以下のようなコンポートを用意し、状態によって出し分けます(この状態管理が複雑になってくると、Reactだけではカオスになるので、Redux等のフレームワークが登場します)
- Headerコンポーネント
- Footerコンポーネント
- CodeInputコンポーネント
- Modalコンポーネント
- ErrorMessageコンポーネント
- LaunchAppコンポーネント
出来上がったものは、webpackでトランスパイルし、S3にアップロードし、CloudFront + WAF機能で、アクセス制限をかけて、社内からのみアクセスできるようにします。
こんな感じになった
- 初期画面
-
コード入力
-
モーダル
-
完了
苦労したところ、できないところ
- いろいろと世界観違う・・・。なれるのに時間がかかる。
- 今まで当たり前のように、サーバーでApacheとか、NginxとかでWebサーバーを用意し、言語をインストールして、フレームワークをいれて、実装する!ということをしていたのがやらなくてもよくなりました。
- アクセス制限だったり、CI/CDだったりがまだまだ整っていないところもあるので、面倒くさい部分もある。
- デバッグが超めんどくさい。
- ログを取るのをどうするのか?っていうのも考える必要がある
- S3上でSPAを表現するのが難しい
- CI/CDまわりをどうするのか?が設計が難しい。
- デプロイとリリースをわけたい場合、安全にリリースしたい場合等、いろいろ考える必要がある
- Macだとローカル開発できたけど、Windowsはわからない
- フロントとAPIを分離すると、フロント側は、HTML、JS、CSSで表現するようになります。SEOとかOGPとか、レガシークローラとかからアクセスくるとかいろいろ考える必要がある
- 負荷試験的なものはまだやってません。どれくらいさばけるのかにもよりますね。
- フロント側
- API側
- 品質部分では、テストコード等を、APIテストと、画面テストの2つ用意すれば、ある程度担保できるのかなと思っています。実装していませんが。
考察
サーバーレスのメリットは、いい意味で制約があることです。たとえば、Lambdaにアップロードできるソースコードには限界があるし、そのおかげでわかりやすく保つことができます。
サーバーがあるということは、サーバーが状態を持つことに等しいので、複雑度が増します。サーバーレスは、その分シンプルになります。
なので、耐障害性や、保守運用性が圧倒的に強くなります。これは、心理的安全性がかなりいい状態ですよね。自分たちは、ビジネスロジックに注力すればいいので、余計なことを考えずにすみます。
また、イベント駆動なので、常時稼働ではなく、必要になったときだけ処理する!ということになります。
このお陰で必要なコストのみがかかるようになり、夜間アクセスすくないのにお金が発生している!とかがなくなります。これは、メインのメリットというよりかは、副次的なメリットですね。
もちろん、すべてのWEBアプリをサーバーレス化はしないほうが良いと思います。
決済部分とか、セキュアな部分をサーバーレスだけで実現するのは難しいかもしせません。
最後に
デメリットもあるが、余計なことを考えず、ビジネス部分に注力できるので、採用してもいいのかなと思います。
これから、新サービスを開発してリリースしたい場合は、MVPをサーバーレスで作ってみるのもが良いかもしれないとちょっと思いました。コストもないし、素早くリリースもできるので。
この記事を書いた人
- PM(プロダクトマネージャー)目指して奮闘中、プログラムから、アーキテクト設計、サービス検討から、チームマネジメント、DevOps、いろいろやってます。
最近書いた記事
- 2017.11.22Design Sprint in Yahoo! ロッジ
- 2017.11.21iOS11 HEIF、HEVCの新コーデック
- 2017.11.21SRE 〜サイトリライアビリティエンジニアリング〜
- 2017.10.31リーンキャンバスを実践してみよう