はじめに
AWS Copilot で Phoenix Framework の本番環境を構築するシリーズです
実装したサンプルはこちらに格納しています
ストレージの追加
前回の時点では、クラスタリングはできていますが、
チャットした内容は保存されていません
本番運用するシステムならば、データ保存(永続化)は必要でしょう
AWS Copilot では、ストレージをサービスに追加することにより、データ保存が可能になります
copilot storage init
でストレージを対話形式で追加できます
Only found one workload, defaulting to: lb-svc
What type of storage would you like to associate with lb-svc? [Use arrows to move, type to filter, ? for more help]
> DynamoDB (NoSQL)
S3 (Objects)
Aurora Serverless (SQL)
選択肢は DynamoDB
か S3
か Aurora Serverless
です
今回はチャットなので、 DynamoDB を使ってみましょう
...
Storage type: DynamoDB
What would you like to name this DynamoDB Table? [? for help]
次にテーブル名を入力します
messages
と入力した場合、出来上がるテーブル名は
react-chat-test-lb-svc-messages
になります
つまり <アプリケーション名>-<環境名>-<サービス名>-<入力したテーブル名>
です
続いてパーティションキーやソートキーを入力していきます
最終的に以下のように表示されます
Recommended follow-up actions:
- Update lb-svc's code to leverage the injected environment variable MESSAGES_NAME.
For example, in JavaScript you can write:
```
const storageName = process.env.MESSAGES_NAME
```
- Run `copilot deploy --name lb-svc` to deploy your storage resources.
そして、 copilot/lb-svc/addons/messages.yml
が以下の内容で作成されます
Parameters:
App:
Type: String
Description: Your application's name.
Env:
Type: String
Description: The environment name your service, job, or workflow is being deployed to.
Name:
Type: String
Description: The name of the service, job, or workflow being deployed.
Resources:
messages:
Metadata:
'aws:copilot:description': 'An Amazon DynamoDB table for messages'
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub ${App}-${Env}-${Name}-messages_x
AttributeDefinitions:
- AttributeName: channel_name
AttributeType: "S"
- AttributeName: message_id
AttributeType: "S"
BillingMode: PAY_PER_REQUEST
KeySchema:
- AttributeName: channel_name
KeyType: HASH
- AttributeName: message_id
KeyType: RANGE
messagesAccessPolicy:
Metadata:
'aws:copilot:description': 'An IAM ManagedPolicy for your service to access the messages db'
Type: AWS::IAM::ManagedPolicy
Properties:
Description: !Sub
- Grants CRUD access to the Dynamo DB table ${Table}
- { Table: !Ref messages }
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: DDBActions
Effect: Allow
Action:
- dynamodb:BatchGet*
- dynamodb:DescribeStream
- dynamodb:DescribeTable
- dynamodb:Get*
- dynamodb:Query
- dynamodb:Scan
- dynamodb:BatchWrite*
- dynamodb:Create*
- dynamodb:Delete*
- dynamodb:Update*
- dynamodb:PutItem
Resource: !Sub ${ messages.Arn}
- Sid: DDBLSIActions
Action:
- dynamodb:Query
- dynamodb:Scan
Effect: Allow
Resource: !Sub ${ messages.Arn}/index/*
Outputs:
messagesName:
Description: "The name of this DynamoDB."
Value: !Ref messages
messagesAccessPolicy:
Description: "The IAM::ManagedPolicy to attach to the task role."
Value: !Ref messagesAccessPolicy
addon として CloudFormation のテンプレートが作られるわけですね
この状態でまたデプロイします
copilot svc deploy \
--name lb-svc \
--env test
デプロイが完了した後、 AWS のコンソールを見ると確かに DynamoDB にテーブルが作成されています
また、 ECS のタスクに環境変数も追加されています
コンテナ内からはこの環境変数を使ってテーブルを指定すれば良いわけですね
ちなみに、テーブルのキーを変更した場合、そのままデプロイすると以下のようなエラーになります
...
- An Amazon DynamoDB table for messages [update complete] [0.0s]
CloudFormation cannot update a stack when a custom-named resource requ
ires replacing. Rename react-chat-test-lb-svc-messages and update the
stack again.
...
キーを変える場合、 addons/messages.yml
内のテーブル名を変更する必要があります
テーブル名を変えたくない場合、一度名前を変更してデプロイした後、
テーブル名を元に戻して再度デプロイすることになります
Elixir でのテーブル名設定
DynamoDB へのアクセス方法紹介の記事ではないので、ポイントだけ書きます
まず、 react_chat/config/config.exs
にテーブル名取得用の設定を追加します
config :react_chat, ReactChatWeb.RoomChannel, table_name: System.get_env("MESSAGES_NAME")
また、環境変数 MESSAGES_NAME
は実行時のコンテナに設定されます
config.exs
や prod.exs
はビルド時の環境変数を使うため、
実行時の環境変数を使う場合は runtime.exs
に設定を書いておく必要があります
したがって、 react_chat/config/runtime.exs
にも設定を追加する必要があります
if config_env() == :prod do
...
# 次の行を追加
config :react_chat, ReactChatWeb.RoomChannel, table_name: System.get_env("MESSAGES_NAME")
end
まとめ
AWS Copilot で簡単に DynamoDB のテーブルを追加することができました
デフォルトで作ったら DynamoDB が BillingMode: PAY_PER_REQUEST
になっていたので、
コスト最適にするならここもいじる必要があります
RDB を使いたい場合は Aurora Serverless を選択することになると思いますが、こちらはまだ未検証です
本番利用したときどれだけの性能、コストになるのか、、、
リアルタイム処理では DynamoDB を使って、
バッチ処理結果を Aurora Serverless に入れるような感じにすればコスト最適にできそう