C++幼女先輩

プログラミング成分多め

AWSサーバレスを使いたい。 その資格はない、おぉその資格はない

モチベーション

プログラマとして、EC2なりECSにモノリシックなサーバを作る方が慣れているが
サーバレスを積極的に使いたい
どちらもメリットはあるが
サーバレス(ファンクション単位)にすると、ライブラリを使ったり管理が面倒だったり
デプロイ作業がやりにくかったりする
お互いの機能を呼び出すにもAPIで無駄なリクエスト投げ合ったり。。
ただし、小さい関数を作るには非常に向いているし、サーバ料金が安くなる事が多い
なんといっても、サーバ管理やスケーリング等が全て不要になる

昔はnode.jsが多かったが、今はランタイムも色々選べるようになったし
カスタムランタイムを使えば何の言語でも実行可能

これはやらなければならない

フレームワーク

サーバレスはデプロイが面倒
モノリシックサーバの場合はEC2なりコンテナを作り、ソースをコピーすればいいが
サーバレスだと、API Gatewayを設定したり、Lambdaの関数をUploadして設定したり
AWSコンソールで色々と設定が必要
デプロイも、関数毎にわかれているので、関数の数だけデプロイが必要
デプロイ忘れの関数が残ってると本当に大変
なので、何らかのフレームワークを使うのが良いと思う

今回はAWS限定で

CloudFormation

AWSの公式の IaaC(Infrastructure as Code)
要は面倒なAPI GatewayやLambda、あるいはDynamoDB等のデプロイを
スクリプトを書いて自動化できる
Terraformみたいなやつ
基本的にAWSのデプロイはこれを使うので下記のフレームワークもCFを使用している

Amplify、AppSync

GraphQLベースのサーバレスアプリケーション用のフレームワーク
という認識

SAM(AWS Serverless Application Model )

AWS公式のサーバレス用フレームワーク
下記のServerlessFrameworkと機能的によく似ている
が、AWS限定である

ServerlessFramework

オープンソースのサーバレスのデプロイやテストを行うフレームワーク
上記のSAMはAWS専用だが、こちらはAzure、GCP、ALIクラウド、テンセントクラウド・・に対応している
ServerlessFrameworkの方が進んでたが、最近はSAMも十分に機能があると思うのでどちらを使っても良い
ただ、ServerlessFrameworkの方が情報が多い気がするので、今回はこちらを使う

作るもの

API GatewayがWebsocket対応していて、使ってみたかったので、Websocketにする
まずはチャットサービスを作ろうと思う

準備

aws-cli、node、その他必要なものは入っている認識で

serverless-frameworkをインストール

serverlessコマンドでテンプレート作成やデプロイが出来るが、エイリアスとして sls slssが割り当てられている
sls コマンドでプログラムのテンプレートを作成可能
slsを入力すると

❯ AWS - Node.js - Starter 
  AWS - Node.js - HTTP API 
  AWS - Node.js - Scheduled Task 
  AWS - Node.js - SQS Worker 
  AWS - Node.js - Express API 
  AWS - Node.js - Express API with DynamoDB 
  AWS - Python - Starter 
  AWS - Python - HTTP API 
  AWS - Python - Scheduled Task 
  AWS - Python - SQS Worker 
  AWS - Python - Flask API 
  AWS - Python - Flask API with DynamoDB 
  Other 

と、テンプレートを選ぶ事が可能だが、一覧にないものを選ぶには、-t オプションを使う

sls create -t aws-nodejs-typescript -n sample
と打つと、Typescriptを使った、sampleアプリのテンプレートが生成される

途中でAWSのCredencialを設定したり、IAMのロールが必要
IAMはAdmin権限のあるユーザーを作りその情報を入力すれば通った

今回はメニューより、Express API with DynamoDB を選びそこから改良する事に
Typescript化は今度やる

このテンプレートは、DynamoDBを使用し、REST APIにより usersで登録、user/:userId で情報取得
のようなものになっている

sls deploy で、AWSで上記の構成とコードのアップロードが出来る
以降は、毎回全部deployしなくとも関数単位でのdeployも可能
sls deploy function -f エントリポイント
簡単にGithubと連携する事も出来るっぽいが、それは後日しよう

ただし、今回はローカルでテスト実行しようと思う
serverless-offlineと、serverless-dynamodb-local をインストールする必要がある
このあたりは、npmコマンドでインストールする
これらはServerlessFrameworkのプラグインである

npm i serverless-offline serverless-dynamodb-local

dynamodb-localに関しては本体(AWS提供)をインストールする必要がある

sls dynamodb install

ただし、dynamodb-localはJavaで動くのでJREが必要

そして、上記プラグインを serverless.ymlに記載する

plugins:
#  - serverless-webpack
  - serverless-dynamodb-local
  - serverless-offline

webpackは今は使わないが、今後使う予定
プラグインは順番も重要なので必ず上記の順番で書くように

sls offline start
でオフラインで動くはずである・・・ が、上手く動作しない
シンプルなテンプレート(DynamoDBを使わない)だとちゃんと動作するので
dynamodb-localの動作に問題があるようだ

試しにサーバにデプロイしたらちゃんと動いた
ただし、色々と serverless.ymlやコードをいじったり、AWSのリージョン指定したりCredencialをいじったらそのうち動くようになった
まあ、WindowsでWSL2上で動かしたりしているので、内部IPアドレスまわりの問題かもしれない

dynamodb-localの動作確認は aws dynamodb list-tables --endpoint-url http://localhost:8000 などで出来る。

Websocket化

github.com

これを見ながら書けばいけた
とりあえず覚えておくこととして

serverless.ymlに

functions:
  connect:
    handler: onconnect/app.handler
    events:
      - websocket:
          route: $connect
  disconnect:
    handler: ondisconnect/app.handler
    events:
      - websocket:
          route: $disconnect
  sendmessage:
    handler: sendmessage/app.handler
    events:
      - websocket:
          route: sendmessage

こんな感じでRouteを指定し、それぞれのhandlerコードを書いた
あとは上記URLを参考に。。

sls offline start
でオフライン実行できる

ただし、RestAPIのようにCurlで叩けないので、Websocket用のツール wscatをインストールする

wscat -c ws://localhost:3001/dev
とすると、Websocketに接続し、プロンプト状態になる

{"message":"sendmessage", "data":"hello world"}

というデータを送るとレスポンスが返ってくる

hello world

ローカルでの動作も確認できた

github.com

やり残し作業

  • TypeScript化
  • 自動Deploy
  • Client(S3とCloudFront あと、Reactかなあ?)
  • ルーム機能(DynamoDBのキー変更)
  • メッセージに発言者ID等を付与
  • ログイン(名前入力&LocalStorage保存程度)
  • ログインユーザ一覧