2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

serverless deployしたLambdaとDynamoDBの接続で詰まったお話

Last updated at Posted at 2023-03-02

はじめに

serverless deploy後にLambdaとDynamoDBの接続で色々詰まった点をまとめてみます。ファイルに関しては数が多いため記載は一部にしています

前提

  • Docker in Dcokerでserverless deploy
    開発環境のコンテナの中でデプロイコマンド(sls deploy)を実行しています

  • React+Rails+DynamoDB+APIGateway+Lambda

  • フロント(React)からバックエンド(Rails)にパラメータを渡せている

ディレクトリ構成(一部)

この記事の環境に関しては前回の続きになります

sample-project
┣ backend
┃  ┗ config
┃      ┗ aws.yml
┣ Dockerfile
┣ serverless.yml
┣ docker-compose.yml

詰まった点

フロントからパラメータを送ると、DynamoDB側で500エラーが発生

CloudWatchでログを確認すると以下のエラーが出ました

task time out after 25seconds...

このときバックエンド側でパラメータは受け取れていたので、
LambdaとDynamoDBが接続できているか、以下の点をserverless.ymlで確認しましたが問題は見つかりませんでした

  • DynamoDBのアクセス権限をroleに設定できているか
  • DynamoDBのテーブルに対して参照権限を設定できているか

エラー文で検索をかけてみると以下の記事を見つけました

こちらの記事を参考にし、Lambdaの実行制限時間を25秒から適当に180秒まで増やして再度動作を確認したところ、エラー文が以下に変わりました

sample-project/serverless.yml
service: sample-project-api

provider:
  name: aws
  runtime: ruby2.7
  timeout: 180

Failed to open TCP connection to dynamodb-hoge-local:8000 (getaddrinfo: Name or service not known)

接続先が本番環境のDynamoDBではなく、開発環境のDynamoDBになっていました
開発環境でフロントからパラメータを送った際はDynamoDBにレコードが作成されているため、本番環境では認証もできていなさそうでした

そこでDynamoDBとの接続や認証まわりについて確認することにしました

本番環境のDynamoDBで認証ができていない

まず開発環境のコンテナ内で.envから認証情報を取得できているか確認するとnilでした

# 開発環境用のコンテナに入ってrails c
> Rails.env

これを解決するためにはAWS Parameter StoreやSecrets Managerを利用するようです
今回はAWS Parameter Storeを使いました

serverless.ymlに以下のような書き方をすると、
パラメータストアに入れた情報を取得できるようです

sample-project/serverless.yml

  environment:
    QIITA_DYNAMODB_ACCESS_KEY_ID: ${ssm:/sample-project/AWS_ACCESS_KEY_ID}
    QIITA_DYNAMODB_SECRET_ACCESS_KEY: ${ssm:/sample-project/AWS_SECRET_ACCESS_KEY}
    RAILS_ENV: production

この時、Lambdaで予約されている環境変数名と被らないようにする必要があったので「QIITA_DYNAMODB_」を頭につけています

パラメータストアに情報を入れる際は以下のようなコマンドを実行します

# 開発環境のコンテナに入る
aws ssm put-parameter --name "/sample-project/AWS_ACCESS_KEY_ID" \
--type "Secure String" --value "hogehogehogehoge"

aws ssm put-parameter --name "/sample-project/AWS_SECRET_ACCESS_KEY" \
--type "Secure String" --value "fugafugafugafuga"

接続先が本番環境のDynamoDBではなく、開発環境のDynamoDBになっている

次に開発環境のDynamoDBに接続しようとしていた点ですが、
aws.ymlの設定に不足がありました
以下の記事を参考に、本番環境用の設定を追加しました

backend/config/aws.yml
default: &default
  access_key_id: <%= ENV['QIITA_DYNAMODB_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['QIITA_DYNAMODB_SECRET_ACCESS_KEY'] %>
  region: ap-northeast-1

development:
  <<: *default
  endpoint: http://dynamodb-hoge-local:8000

production:
  <<: *default
  • これで開発環境のコンテナからserverless deployした際にACCESS_KEY_ID/KEYを環境変数としてrailsに渡すことができます
  • developmentにのみendpointを指定しているのは、GUIとして使用しているdynamodb-adminの参照先にdynamodb-localを指定する必要があるためです

次に本番用のDockefileでenvの切り替えができるようにコマンドを追加しました

backend/Dockerfile
# 本番用
ARG RUBY_TAG

FROM public.ecr.aws/lambda/ruby:${RUBY_TAG} as builder

ENV LANG C.UTF-8

RUN yum update -y && yum groupinstall -y "Development Tools"

WORKDIR /var/task

# 追加分
ENV RAILS_ENV=production
ENV RACK_ENV=production

ARG BUNDLE_VER

RUN gem install bundler -v ${BUNDLE_VER}

COPY lambda.rb /var/task
COPY ./Gemfile /var/task
COPY ./Gemfile.lock /var/task
ENV GEM_HOME=/var/task
RUN bundle install

ADD . /var/task/

CMD ["lambda.App::Handler.process"]

これでsls removeした後に改めてsls deployを行い、フロントからパラメータを送るとDynamoDBにレコードが作成されることを確認できました!!

おまけ

最終的なserverless.yml

sample-project/serverless.yml
service: sample-project-api

provider:
  name: aws
  runtime: ruby2.7
  timeout: 180
  stage: ${opt:stage, 'dev'}
  region: ap-northeast-1
  deploymentBucket:
    name: sample-project-api-dev-slsdeploymentbucket
  ecr:
    scanOnPush: true
    images:
      lambda_docker:
        path: ./backend
        buildArgs:
          BUNDLE_VER: ${env:BUNDLE_VER, '2.3.5'}
          RUBY_TAG: ${env:RUBY_TAG, '2.7'}
  environment:
    RAILS_ENV: production
    SECRET_KEY_BASE: hogehogehogehoge
    QIITA_DYNAMODB_ACCESS_KEY_ID: ${ssm:/sample-project/AWS_ACCESS_KEY_ID}
    QIITA_DYNAMODB_SECRET_ACCESS_KEY: ${ssm:/sample-project/AWS_SECRET_ACCESS_KEY}

  iamRoleStatements:
    - Effect: 'Allow'
      Action:
        - dynamodb:*
      Resource:
        - arn:aws:dynamodb:ap-northeast-1:○○:table/*

custom:
  defaultStage: dev
  deploymentBucket:
    blockPublicAccess: true

functions:
  api:
    timeout: 25
    image:
      name: lambda_docker
    events:
      - http:
          path: /
          method: ANY
          cors: &cors
            origin: http://localhost:43000
            headers:
              - Content-Type
              - X-Amz-Date
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token
              - X-Amz-User-Agent
              - Access-Control-Allow-Headers
              - Access-Control-Allow-Origin
              - Time-Zone
              - Cache-Control
            allowCredentials: false

      - http:
          path: /{proxy+}
          method: ANY
          cors: *cors

resources:
  Resources:
    HogeTable:
      Type: AWS::DynamoDB::Table
      Properties: 
        TableName: dynamoid__${self:provider.environment.RAILS_ENV}_hoge
        BillingMode: PAY_PER_REQUEST
        AttributeDefinitions:
          - AttributeName: "id"
            AttributeType: "S"
        KeySchema:
          - AttributeName: "id"
            KeyType: "HASH"

plugins:
  - serverless-deployment-bucket

おわりに

LambdaとDynamoDB間の繋ぎこみや細かい箇所でたくさん詰まりましたがなんとかできました。引き続いて理解を深めていきます。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?