Serverless Frameworkで作るお手軽アプリケーション

Kaizen Platformでアプリケーションエンジニアをしている白井(@kaito2280)です。

今回はServerless Frameworkを使ったお手軽アプリケーションの作成をtips等を交えてご紹介したいと思います。

Serverless Frameworkとは

サーバーレスのアプリケーションを作るのに便利な構成管理ツールです。オープンソースのCLIとServerless社がホストしているダッシュボードがあります。

今回の例はこのCLIを利用してアプリを作成します。

Serverless Frameworkでは、AWSやGCPなどのプロバイダーに対応しています。対応プロバイダーはこちら

今回の例では、AWSのLambda/API Gateway/S3/Cloud Frontを利用します。

Getting Started

aws-cli, nodeの設定が完了している前提です。

今回は社内で多く採用されてる言語のRubyを使用することにしました。

まずは、下記のコマンドを実行してみてください。

npm install -g serverless
serverless create -t aws-ruby -p myserverless
cd myserverless/

こちらでmyserverlessディレクトリにhandler.rbserverless.ymlの2つのファイルが作成されていることがわかります。

この状態で

sls deploy

を行うと、Lambdaの関数が作成されます。(slsserverlessの短縮形です。)

また、handler.rbに定義されているhello関数を叩く場合、

sls invoke -f hello

を実行することでhello関数を実行し、その結果が返ってきます。

serverless.ymlに下記のようにhttpのeventsを追加することでdeploy時にAPI Gatewayも同時に作成されます。

functions:
  search:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get

その他設定もserverless.ymlに追加し、deployすることで簡単に作成できます。

さらに、作成したアプリは、

sls remove

をすることで削除できます。

このようにServerless Frameworkを使用すると、サクッと作ってサクッと消すことができ、サーバレスアプリケーションを簡単に試すことができます。

今回作った機能

今回は、Kaizen Adという動画制作を支援するプラットフォーム上で、ユーザーが動画制作用の素材を外部サービスから無料で検索できる機能をServerless Frameworkを用いて作成しました。

構成は以下の通りです。

f:id:kaizenplatform:20210324135928p:plain

Serverless Frameworkを使用するとこれくらいの規模のサービスであれば簡単に構築が可能です。

また、すべての設定情報がserverless.ymlの1ファイルに収まるので、メンテナビリティにも優れてると思います。

以前弊社ブログでご紹介したPulumiでも似たような体験を得ることができますが、Pulumiはリソース全体の構成管理という側面が強く、簡単にアプリケーションを作るという意味だとplugin等も充実しているServerless Frameworkの方が速度が出ると思います。

API Gatewayの前にCroudFrontを置いている理由はレスポンスキャッシュを使用して検索を高速化したかったためです。

また、S3にアクセスログを溜めておきAthenaで分析しています。

最終的なserverless.ymlはこのようになっています。(多少省略している部分があります。)

service: search-material
frameworkVersion: '2'

provider:
  name: aws
  runtime: ruby2.7
  timeout: 10
  memorySize: 256
  stage: ${opt:stage, self:custom.defaultStage}
  region: xxx
  logRetentionInDays: 90
  
functions:
  search:
    handler: handler.search
    events:
      - http:
          path: search
          method: get
          
    environment:
      STAGE: ${self:provider.stage}
      PEXELS_API_KEY: ${ssm:/xxx/${self:provider.stage}/PEXELS_API_KEY~true}
      UNSPLASH_API_KEY: ${ssm:/xxx/${self:provider.stage}/UNSPLASH_API_KEY~true}
      UNSPLASH_API_SECRET: ${ssm:/xxx/${self:provider.stage}/UNSPLASH_API_SECRET~true}
      PIXABAY_API_KEY: ${ssm:/xxx/${self:provider.stage}/PIXABAY_API_KEY~true}

resources:
  Resources:
    LogBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: xxx-cloudfront-log-${self:provider.stage}
        VersioningConfiguration:
          Status: Enabled

plugins:
  - serverless-api-cloudfront
  - serverless-prune-plugin
  - serverless-ruby-layer

custom:
  defaultStage: dev
  priceClass:
    dev: PriceClass_200
    qa: PriceClass_200
    prd: PriceClass_All
  domain:
    dev: xxx
    qa: xxx
    prd: xxx
  certificateArn:
    dev: arn:aws:acm:xxx
    qa: arn:aws:acm:xxx
    prd: arn:aws:acm:xxx
  # settings for serverless-api-cloudfront
  apiCloudFront:
    domain: ${self:custom.domain.${self:provider.stage}}
    certificate: ${self:custom.certificateArn.${self:provider.stage}}
    priceClass: ${self:custom.priceClass.${self:provider.stage}}
    logging:
      bucket: xxx-cloudfront-log-${self:provider.stage}.s3.amazonaws.com
  # settings for serverless-prune-plugin
  prune:
    automatic: true
    includeLayers: true
    number: 10

package:
  exclude:
    - node_modules/**
    - package.json
    - package-lock.json
    - Gemfile
    - Gemfile.lock
    - README.md

Tips

  • serverless-prune-pluginの導入

LambdaはdeployされるごとにVersionを保持するため、運用・保守し続けると使用しない過去のLambda関数が残り続けることになります。Lambda上ではコードの合計ストレージに制限があるため、できるだけ無駄な関数は残さないほうが良いでしょう。

このプラグインを入れておくことで指定した世代より前のVersionの関数を削除してくれるようになります。

  • Parameter Storeの導入

環境変数の管理といえば煩雑になりがちですが、Serverless Frameworkでは最近一般的に使われるようになってるAWS Systems ManagerのParameter Storeに対応しています。

${ssm:/xxx/HOGE~true}

このような記法を使うことでSecureStringで保存した環境変数をdeploy時に複合して参照してくれるようになります。

  • Lambdaリソースのチューニング

Lambdaを使用する際に悩むことの一つとしてメモリサイズが挙げられます。

メモリサイズを大きくすることで割り当てられるコンピューティングリソースやネットワーク帯域も比例して大きくなると言われており、実行速度と料金の落とし所を自分で探ることになります。

しかし、AWS Lambda Power Tuningというものを使用することでメモリサイズを簡単に最適化することができます。

詳しい利用方法はクラスメソッドさんの記事を参照してください。

最終的には以下のようなグラフが出力され、今回作成したLambda関数には256MB割り当てると実効速度とコストのバランスが良さそうだということがわかりました。

f:id:kaizenplatform:20210324140204p:plain

最後に

今であれば、Lambda上でコンテナがサポートされ、またそれがServerless Frameworkでもサポートされたため、もっと違った作り方があるのではないかと思います。

手軽にアプリケーションを作りたい場面があればそちらにも挑戦してみたいと思います。

本番使用に耐えうるアプリケーションがインフラ含め簡単に作成できるので、開発で速度を出したい場合やユーザー動向を探るためのお試しリリースをする場合の選択肢にしていただければと思います。

We're hiring!

Kaizen Platformで一緒に働いてくれる方を絶賛募集中です!

話を聞いてみるだけでもいいので、ご興味ある方はぜひ! hrmos.co hrmos.co hrmos.co