AWS LambdaのCI環境について ~表参道.rb #24~

  • 3
    いいね
  • 0
    コメント

自己紹介

@ebihara99999


ところで

私事ですが明日結婚します。
めでたいLTです



発表すること

  • AWS Summit 2017でのt_wadaさんの講演がすごく参考になったので、AWS Lambdaで自動テストを行う仕組みを導入した
  • その際の知見やハマりどころを発表する

t_wadaさんの講演?

Testable Lambda: Working Effectively with Legacy Lambda

公式Lambdaチュートリアルを例として扱い、Lambda開発で自動テストを導入していくお話

スライド:
https://speakerdeck.com/twada/testable-lambda-working-effectively-with-legacy-lambda

動画: https://www.youtube.com/watch?v=C0zNc4bdWhY


t_wadaさんの講演?

拙記事もご覧ください(ご本人にはてぶして頂いて嬉しい)。

http://biibiebisuke.hatenablog.com/entry/2017/06/03/132538


講演内容

AWS公式のLambdaチュートリアルのコードをリファクタリングしながらテストを書いていく

  • ローカル環境でのテスト
    localstack超便利
  • 本番環境相当のテスト AWS SAMを利用したCI環境の構築 ← 今日はこれについて
  • production環境でのサービス間のテスト

題材

構成としては、本家のLambdaチュートリアルと同様。

srcBucketにファイルが格納されたら何らかの処理を行い、結果をdestBucketに吐き出す。

lambda-flow.png

引用: http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-s3-example.html


SAM(Serverless Application Model)とは

  • サーバレスアーキテクチャ構築フレームワーク
  • CloudFormationの拡張
  • サーバーレスアプリケーションのリソースに最適化された専用のリソースタイプを定義できる
  • 本家にサンプル色々ある

AWS Summit 2017での吉田さんの講演がとても参考になります
動画: https://www.youtube.com/watch?v=ZDvcCY8QRWA

参考:
https://aws.amazon.com/jp/about-aws/whats-new/2016/11/introducing-the-aws-serverless-application-model/
http://dev.classmethod.jp/cloud/aws/aws-serverless-application-model/


実現したいCI環境

push後ブランチごとに実際のAWSサービスを利用した環境を立ち上げて、テストが終わったら使用した環境を削除したい(CircleCI使用)。

  • スタック名をブランチを含む形にしたい
  • テストで使用するリソース(今回はS3のバケット)も、ブランチ名を含む命名規則とし、想定可能な名称にしたい

リソースの名称を指定しないと下記のようにユニークな値を振ってくれるが、それではテストで利用できない(「hogeバケットにファイルが存在すること」など)。

例
arn:aws:iam:*******:role/lambda-tutorial-ProcessorFunctionRole-1GFMCGG1ORHNM

実現したいCI環境

例として、

  • CloudFormationスタック名
    ${プロジェクト名}-${ブランチ}
例: lambda-tutorial-develop
  • Sourceバケット名
    ${プロジェクト名}-\${ブランチ}-source
例: lambda-tutorial-develop-source

などなど


実現したいCI環境

後掃除もしっかり

  • S3のバケットはオブジェクト(ファイル)が存在している場合は消せないので、delete-stackを実行する前にs3バケット内のオブジェクトを削除しておく必要がある

具体的な設定(CircleCI編)

CircleCIの環境変数

  • PROJECT_NAME: lambda-tutorial
  • REGION
  • S3_BUCKET: CloudFormationのソース置き場
  • CIRCLE_BRANCH: CircleCIで保持している環境変数。ブランチ名を格納している

具体的な設定(CircleCI編)

circle.yml

machine:
  timezone: Asia/Tokyo
  node:
    version: 6.1.0
dependencies:
  override:
    - sudo pip install awscli
    - npm install
  post:
    - aws configure set region $REGION
test:
  pre:
    - aws cloudformation package --template-file app-spec.yml --output-template-file app-spec.deploy --s3-bucket $S3_BUCKET_NAME
    - aws cloudformation deploy --template-file app-spec.deploy --stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}" --capabilities CAPABILITY_NAMED_IAM 
  override: 
    - mocha test/large/index-test.js --timeout 10000
  post:
    - aws s3 rm --recursive s3://"${PROJECT_NAME}-${CIRCLE_BRANCH}"-source
    - aws s3 rm --recursive s3://"${PROJECT_NAME}-${CIRCLE_BRANCH}"-dest
    - aws cloudformation delete-stack --stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}"
deployment:
  production:
    branch: master
    commands:
      - aws cloudformation package --template-file app-spec.yml --output-template-file app-spec.deploy --s3-bucket $S3_BUCKET_NAME
      - aws cloudformation deploy --template-file app-spec.deploy --stack-name "${PROJECT_NAME}" --capabilities CAPABILITY_NAMED_IAM

ポイント(CircleCI編)

  • --capabilities CAPABILITY_NAMED_IAMつけないとダメ
  • CloudFormationへデプロイ時に--stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}"のように、stack名にブランチ名を含めてしまうこと

SAM(CloudFormation)のテンプレートでブランチ名を取得するよりCircleCIで取得する方がはるかに楽。

test:
  pre:
    - aws cloudformation package --template-file app-spec.yml --output-template-file app-spec.deploy --s3-bucket $S3_BUCKET_NAME
    - aws cloudformation deploy --template-file app-spec.deploy --stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}" --capabilities CAPABILITY_NAMED_IAM

ポイント(CircleCI編)

  • S3バケット内にオブジェクトが残っているとdelete-stackできないので、先にオブジェクトを削除しておく
post:
    - aws s3 rm --recursive s3://"${PROJECT_NAME}-${CIRCLE_BRANCH}"-source
    - aws s3 rm --recursive s3://"${PROJECT_NAME}-${CIRCLE_BRANCH}"-dest
    - aws cloudformation delete-stack --stack-name "${PROJECT_NAME}-${CIRCLE_BRANCH}"

設定(SAM編)

app-spec.yml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: A function that is triggered off an upload to a bucket. It does something to the uploaded file and put the proccessed file to another bucket. 
Resources:
  ProcessorFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs6.10
      CodeUri: ./
      Timeout: 40
      Policies: AmazonS3FullAccess
      Environment:
        Variables:
          STACK_NAME: !Sub "${AWS::StackName}"
      Events:
        ImgUpload:
          Type: S3
          Properties:
            Bucket: !Ref SourceBucket
            Events: s3:ObjectCreated:*
  SourceBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-source"
  DestinationBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-dest"

ポイント(SAM編)

  • スタック名の取得 CloudFormationの擬似パラメータで、!Sub "${AWS::StackName}"でスタック名を取得できるので、こちらを利用する。

デプロイ時にスタック名にブランチ名も含めて渡しているのでapp-spec.ymlではブランチ名について考慮する必要はない。


その他はまりどころ

  • ブランチ名はハイフンを使うこと

CloudFormationのスタック名はアンダーバーを使えない。
スタック名: lambda-tutorial-update_sam_configurationはinvalidになってしまう


触れられなかったお役立ち資料

SAMの概要から好ましいディレクトリ構成、CIパイプラインの構築まで幅広く非常に詳しく説明されています。 

私の設定ではディレクトリ構成やLambdaパッケージに含むファイルの選別が雑なところがあるので、こちらを参考にして直していきたいと思います。


最後に

ご清聴ありがとうございました