Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
7
Help us understand the problem. What is going on with this article?
@maaaashin324

Serverless Framework で DynamoDB を構築する

More than 1 year has passed since last update.

この記事は CodeChrysalis Advent Calendar 2019 の記事です。

はじめに

Serverless Framework はYAMLでサーバサイドの環境構築ができる、Infrastructure As Code の真骨頂です。確かにAWS等のコンソールでもポチポチクリックしながら環境構築はできますが、

  1. 変更の管理ができない
  2. 画面でポチポチクリックするのが本当に面倒(Lazy...)

なのでServerless Framework の CLI でコマンド一発で全てが構築されるのはとても気持ちが良い。今回はその中でもAWSのDynamoDBをどのように構築するかを紹介します。

まずはYAML

早速YAMLを紹介します。

service: cc-database

custom:
  stage: ${opt:stage, self:provider.stage}

  ccGSIForStudentId: ${self:custom.stage}-dynamodbCcGSIForStudentId
  ccTableName: ${self:custom.stage}-dynamodbCc

  tableThroughputs:
    prod: 5
    default: 1
  tableThroughput: ${self:custom.tableThroughputs.${self:custom.stage}, self:custom.tableThroughputs.default}

provider:
  name: aws
  stage: dev
  profile: cc-admin
  region: ap-northeast-1

resources:
  Resources:
    CcDynamoDbTable:
      Type: AWS::DynamoDB::Table
      DeletionPolicy: Retain
      Properties:
        TableName: ${self:custom.catalogsTableName}
        AttributeDefinitions:
          - AttributeName: cohortId
            AttributeType: S
          - AttributeName: studentId
            AttributeType: S
        KeySchema:
          - AttributeName: cohortId
            KeyType: HASH
          - AttributeName: studentId
            KeyType: RANGE
        ProvisionedThroughput:
          ReadCapacityUnits: ${self:custom.tableThroughput}
          WriteCapacityUnits: ${self:custom.tableThroughput}
        GlobalSecondaryIndexes:
          - IndexName: ${self:custom.ccGSIForStudentId}
            KeySchema:
              - AttributeName: studentId
                KeyType: HASH
            Projection:
              ProjectionType: ALL
            ProvisionedThroughput:
              ReadCapacityUnits: ${self:custom.tableThroughput}
              WriteCapacityUnits: ${self:custom.tableThroughput}

  Outputs:
    CcDynamoDbTableArn:
      Value:
        Fn::GetAtt:
          - CcDynamoDbTable
          - Arn
      Export:
        Name: ${self:custom.stage}-CcDynamoDbTableArn

要素を解説

必ず必要な要素

service, provider, resources は定義が必ず必要です。

service

そのサービスの名前を定義します。
ここでサービスはモノリスサービスかマイクロサービスにするのかを決める必要があります。一つのYAMLにサーバサイドのすべての要素を入れてモノリスサービスにしても良いし、それぞれをサービスに分けてマイクロサービスにしても良いし、それは設計次第です。どちらが良いかはこのドキュメントのテーマではないので深追いしません。

この説明ではこのサービスはデータベースだけ(つまりマイクロサービス)として、cc-databaseとしました。

provider

ここではどのクラウドサービスを利用するかを定義します。今回はAWSなので以下のとおり。

  name: aws
  stage: dev
  profile: cc-admin
  region: ap-northeast-1

stageはデフォルトの環境を定義しておき、逆に言えば明確に指定しないとproduction環境にデプロイしないようにしています。

profileはserverless-frameworkでデプロイするときのユーザーをあらかじめIAMで作成しておき、ここで指定します。regionは比較的親しみのあるワードだと思いますが、お使いになるリージョンを指定します。

resources

ここで実際にデプロイしたいサービスの内容を記述します。もしAWSを利用する場合はSyntaxはCloudFormationに準じます。

Type: AWS::DynamoDB::Table

これでどのプロダクトをデプロイするかを指定します。今回はDynamoDBを指定しました。

DeletionPolicy: Retain

Serverless Framework からデータベースを変更したり削除したりしてもデータを残す指定をしています。開発時点では Delete でも良いかもしれませんが、本番サービスに入ってからデータを消してしまうと大惨事です。保持する設定をしています。

Properties:

ここで実際に作成するテーブル、ローカルインデックス、グローバルセカンダリインデックスを指定します。

TableName: ${self:custom.catalogsTableName}

テーブル名を定義しています。customについては後ほど解説します。

AttributeDefinitions:
  - AttributeName: cohortId
    AttributeType: S
  - AttributeName: studentId
    AttributeType: S

キーとして使う要素をAttributeDefinitionsですべて洗い出す必要があります。要素の名前とそのデータ型を指定します。またテーブルだけではなくインデックスで使う要素についてもここで洗い出す必要があります。

KeySchema:
  - AttributeName: cohortId
    KeyType: HASH
  - AttributeName: studentId
    KeyType: RANGE

ここではテーブルのキーを指定します。パーティーションキーをcohortId、ソートキーをstudentIdにしています。

ProvisionedThroughput:
  ReadCapacityUnits: ${self:custom.tableThroughput}
  WriteCapacityUnits: ${self:custom.tableThroughput}

ここでスループットを指定します。読み込みと書き込みでそれぞれ指定する必要があります。オートスケールにしたくないのでこの状態にしています。

GlobalSecondaryIndexes:
  - IndexName: ${self:custom.ccGSIForStudentId}
    KeySchema:
      - AttributeName: studentId
KeyType: HASH
    Projection:
      ProjectionType: ALL
    ProvisionedThroughput:
      ReadCapacityUnits: ${self:custom.tableThroughput}
      WriteCapacityUnits: ${self:custom.tableThroughput}

こちらはグローバルセカンダリインデックスの設定です。ほぼテーブルと同じですが、Projectionだけインデックス特有で、どのカラムをインデックスに持たせるかの設定です。今はALLにしているのですべてを射影しますが、一部のカラムだけで良ければ変更します。

Outputs:
  CcDynamoDbTableArn:
    Value:
        Fn::GetAtt:
            - CcDynamoDbTable
            - Arn
        Export:
            Name: ${self:custom.stage}-CcDynamoDbTableArn

もし他のマイクロサービスからDynamoDBのArnを読み取りたい場合はここでOutputsを指定しておくと、"Fn::ImportValue"で他のマイクロサービスを指定するYAMLに書くことで読み込めます。例えばLambdaがDynamoDBにアクセスするための設定で必要です。

custom

ここは変数のようなもので、定義は必須ではないが、定義しておくと便利なものを記述します。

custom:
  stage: ${opt:stage, self:provider.stage}

  ccGSIForStudentId: ${self:custom.stage}-dynamodbCcGSIForStudentId
  ccTableName: ${self:custom.stage}-dynamodbCc

  tableThroughputs:
    prod: 5
    default: 1
  tableThroughput: ${self:custom.tableThroughputs.${self:custom.stage}, self:custom.tableThroughputs.default}

たとえばここで

stage: ${opt:stage, self:provider.stage}

はCLIを実行するときの引数にSTAGEが引き渡されたらそれを使用するし、そうでなければproviderに指定されているSTAGE、すなわちdevを使用する設定としています。

テーブル名、グローバルセカンダリインデックスの名前、スループットの値を変数化しておき、この内部のYAMLや外部のYAMLから読み込むようにしています。

補足ですが、外部のYAMLから当該YAMLを読み込むためには

${file(./database/serverless.yml):custom.ccTableName}

を使うことで読み込めます。例えばこれはテーブル名を読み込んでいます。

さいごに

Code Chrysalisは東京を拠点にした12週間の短期集中型ソフトウェアエンジニア養成学校です。ソフトウェアエンジニアになるための12週間特別集中コース:イマーシブやプログラミング初心者向けの講座もありますので、ぜひ見てみてください。

7
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
maaaashin324
デジタル庁ITマネジメントスペシャリスト。 Code Chrysalis Japan で日本語プログラム事業責任者兼務。 中央省庁のミッションクリティカルシステムの開発、BCP策定と構築ののち、ソフトウェアエンジニアに転身し、スタートアップのCTOを務め、現職に至る。日本大手企業向けにアジャイルな開発をビジネス面とテクノロジー面からトレーニングしている。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
7
Help us understand the problem. What is going on with this article?