どーも、シローです。
今回は前回(https://shiro-secret-base.com/?p=994)に引き続き、ServerlessFrameworkを使ってWebSocketの実装を紹介します。
前回の確認
前回ではDockerでserverlessコンテナとdynamodbコンテナを作成しました。
docker-compose ps
でコンテナが稼働していることを前提として進めていきます。
1 2 3 4 5 |
$ docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------------------------------------- serverless-chat-copy_dynamodb_1 java -jar DynamoDBLocal.ja ... Up 0.0.0.0:8889->8000/tcp,:::8889->8000/tcp serverless-chat-copy_serverless_1 docker-entrypoint.sh node Up 0.0.0.0:3334->3000/tcp,:::3334->3000/tcp |
serverlessコンテナに入りServerlessFrameworkプロジェクトの雛形を作成
まずはコンテナに入ります。
1 2 |
$ docker-compose exec serverless /bin/bash root@bc3d3c3ab55d:/app# |
sls create --template aws-nodejs
でプロジェクトの雛形を作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
root@bc3d3c3ab55d:/app# sls create --template aws-nodejs Serverless: Generating boilerplate... _______ __ | _ .-----.----.--.--.-----.----| .-----.-----.-----. | |___| -__| _| | | -__| _| | -__|__ --|__ --| |____ |_____|__| \___/|_____|__| |__|_____|_____|_____| | | | The Serverless Application Framework | | serverless.com, v2.49.0 -------' Serverless: Successfully generated boilerplate for template: "aws-nodejs" Serverless: NOTE: Please update the "service" property in serverless.yml with your service name root@bc3d3c3ab55d:/app# ls handler.js serverless.yml |
次にwebsocketを行うためのLambda関数のファイルを作成します。
最終的にディレクトリが次のようになります。
1 2 3 4 5 6 7 8 9 10 11 |
$ tree . ├── functions │ └── socket │ ├── connect │ │ └── index.js │ ├── disconnect │ │ └── index.js │ └── sendMessage │ └── index.js └── serverless.yml |
serverless.ymlの記述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# Welcome to Serverless! # # This file is the main config file for your service. # It's very minimal at this point and uses default values. # You can always add more config options for more control. # We've included some commented out config examples here. # Just uncomment any of them to get that config option. # # For full config options, check the docs: # docs.serverless.com # # Happy Coding! service: app # app and org for use with dashboard.serverless.com #app: your-app-name #org: your-org-name # You can pin your service to only deploy with a specific Serverless version # Check out our docs for more details frameworkVersion: '2' provider: name: aws runtime: nodejs12.x lambdaHashingVersion: 20201221 plugins: - serverless-offline - serverless-websockets-plugin functions: connect: handler: functions/socket/connect/index.handler events: - websocket: $connect disconnect: handler: functions/socket/disconnect/index.handler events: - websocket: $disconnect sendMessage: handler: functions/socket/sendMessage/index.handler events: - websocket: sendMessage custom: serverless-offline: websocketPort: 3000 |
ざっくりとは
- WebSocketに接続: functions/socket/connect/index.handler
- 接続を切る: functions/socket/disconnect/index.handler
- メッセージを送信: functions/socket/sendMessage/index.handler
functions/socket/connect/index.handlerの記述
1 2 3 4 5 6 7 |
exports.handler = async (event, context, callback) => { console.log('connected') callback(null, { statusCode: 200, body: 'connected' }) } |
functions/socket/disconnect/index.handlerの記述
1 2 3 4 5 6 7 |
exports.handler = async (event, context, callback) => { console.log('disconnected') callback(null, { statusCode: 200, body: 'disconnected' }) } |
functions/socket/sendMessage/index.handlerの記述
1 2 3 4 5 6 7 8 |
exports.handler = async (event, context, callback) => { console.log('sendMessage') console.log(event.body) callback(null, { statusCode: 200, body: 'sendMessage' }) } |
Dockerfileとstartup.shの修正
ServerlessFrameworkのWebSocketにコンテナ立ち上げ時に接続できるようにDockerfile
とdocker-compose.yml
の修正をします。
Dockerfileの記述
./docker/serverless/Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
FROM node:14 ARG AWS_ACCESS_KEY_ID ARG AWS_SECRET_ACCESS_KEY ARG AWS_REGION RUN echo ${AWS_ACCESS_KEY_ID} RUN apt-get update RUN apt-get install -y \ python3-pip \ jq \ && pip3 install --upgrade pip \ && apt-get clean RUN pip3 --no-cache-dir install --upgrade awscli RUN pip3 --no-cache-dir install yq RUN npm install -g serverless RUN npm install -g serverless-offline RUN npm install -g serverless-websockets-plugin RUN npm i -g wscat RUN aws configure set region ${AWS_REGION} RUN sls config credentials --provider aws --key ${AWS_ACCESS_KEY_ID} --secret ${AWS_SECRET_ACCESS_KEY} EXPOSE 3000 COPY startup.sh /opt/startup.sh RUN chmod 777 /opt/startup.sh CMD ["/bin/bash", "/opt/startup.sh"] |
下3行をコメントアウトしています。
startup.shの記述
./docker/serverless/startup.sh
1 2 3 4 5 |
#!/bin/bash cd /app sls offline start --host 0.0.0.0 --port 3000 |
プロジェクトのディレクトリに入ってsls offline
でローカルでサーバレス環境を稼働するようにしています。
Dockerをビルドし直して再度、コンテナを起動する
Dockerfileを変更したので、反映させるためにビルドする必要があります。
1 |
$ docker-compose build serverless |
コンテナを起動します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ docker-compose up Docker Compose is now in the Docker CLI, try `docker compose up` Starting serverless-chat-copy_dynamodb_1 ... done Starting serverless-chat-copy_serverless_1 ... done Attaching to serverless-chat-copy_dynamodb_1, serverless-chat-copy_serverless_1 dynamodb_1 | Initializing DynamoDB Local with the following configuration: dynamodb_1 | Port: 8000 dynamodb_1 | InMemory: false dynamodb_1 | DbPath: ./data dynamodb_1 | SharedDb: true dynamodb_1 | shouldDelayTransientStatuses: false dynamodb_1 | CorsParams: * dynamodb_1 | serverless_1 | offline: Starting Offline: dev/us-east-1. serverless_1 | offline: Offline [http for lambda] listening on http://0.0.0.0:3002 serverless_1 | offline: Function names exposed for local invocation by aws-sdk: serverless_1 | * connect: app-dev-connect # <= この serverless_1 | * disconnect: app-dev-disconnect # <= 3行が serverless_1 | * sendMessage: app-dev-sendMessage # <= 見えれば大丈夫そう serverless_1 | offline: route '$connect' serverless_1 | offline: route '$disconnect' serverless_1 | offline: route 'sendMessage' serverless_1 | offline: Offline [websocket] listening on ws://0.0.0.0:3000 serverless_1 | offline: Offline [http for websocket] listening on http://0.0.0.0:3000 |
出力が↑のようになっていればおそらくうまく行ってます。
試しにローカルで立ち上げたソケットに接続してみる
ソケットに接続してみます。
docker-compose.ymlでポートフォワードで指定した"3334"ポートがローカルから接続できるポート番号になっています。
接続にはwscat
コマンドを使います。npm install -g wscat
でインストールできます。参考 => (https://www.npmjs.com/package/wscat)
接続&メッセージ投稿
1 2 3 4 |
$ wscat -c 'ws://localhost:3334' Connected (press CTRL+C to quit) > {"action": "sendMessage", "message": "hoge"} > |
実際に動かしてみた動画
クラウドコンピューティングの技術の中でも、昨今注目を集めているのがサーバーレスアーキテクチャです。
FaaS(Function-As-A-Service)とも呼ばれるサーバーレスアーキテクチャは、ファンクション(関数)と呼ばれるマイクロサービスを実装し、組み合わせながら、サービスを構築していくアーキテクチャです。