kakakakakku blog

Weekly Tech Blog: Keep on Learning!

LocalStack と samlocal コマンドで SQS x Lambda 構成をローカル環境で実行する

開発中に AWS Lambda 関数をローカル環境で実行するなら AWS SAM CLI の sam local invoke -e event.json コマンドを使えば良く,また AWS Lambda 関数のベストプラクティスに載っている Lambda ハンドラーをコアロジックから分離します。 を意識して実装すれば,単体テストを軸に動作確認を進めることもできる.

とは言え,実際に AWS Lambda 関数のイベントソースマッピング(トリガー設定)を確認したいこともあり,今回は AWS SAM を使って構築する Amazon SQS キューと AWS Lambda 関数の組み合わせを samlocal コマンドを使って LocalStack にデプロイして動作確認をしてみた.結果的に期待した通りに動いた❗️

\( 'ω')/ LocalStack 便利すぎ〜

🚀 アーキテクチャ図

🚀 検証環境

template.yaml

検証に使った AWS SAM テンプレート(AWS CloudFormation テンプレート)を以下に載せておく.特別なことはなく AWS::SQS::QueueAWS::Serverless::Function を構築して,イベントソースマッピングを設定してある.ランタイムは何でも良く,今回は Python 3.9 にしてある.

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Resources:
  Queue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: kakakakakku-queue
      ReceiveMessageWaitTimeSeconds: 20
  Function:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: kakakakakku-function
      CodeUri: app/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Events:
        SqsEvent:
          Type: SQS
          Properties:
            Queue: !GetAtt Queue.Arn

app/app.py

AWS Lambda 関数で動かす Python コードはあくまで必要最低限にして,Amazon SQS キューのメッセージをログ出力(AWS CloudWatch Logs)している🐍

def lambda_handler(event, context):
    for record in event['Records']:
        print(record['body'])

GitHub にも置いておいた💡

github.com

🚀 samlocal コマンドを準備する

今回は AWS SAM (AWS CloudFormation) と LocalStack を組み合わせるため,LocalStack AWS CLI (awslocal コマンド) に加えて AWS SAM CLI for LocalStack (samlocal コマンド) をセットアップしておく.samlocal --version コマンドを実行して,通常の sam コマンドにバイパスされていれば OK❗️

$ pip install aws-sam-cli-local

$ samlocal --version
SAM CLI, version 1.81.0

github.com

🚀 LocalStack にデプロイする

次はさっそく LocalStack にデプロイする.AWS SAM CLI を使ったことがあれば「今まで通り」と言えば伝わると思う.sam コマンドではなく samlocal コマンドに置き換えて,あとは同じく builddeploy を実行する❗️すると samlocal コマンドによって,LocalStack にデプロイできる.

samlocal deploy コマンドの実行結果をできる限りそのまま載せておく.見慣れたログではあるけど,最後の arn:aws:cloudformation:ap-northeast-1:000000000000:changeSet/samcli-deploy1682430872/b79df315 を見て「ああ!LocalStack にデプロイしてたんだ!」と気付くレベル✌️

  • samconfig.toml を作る
  • AWS SAM 専用の Amazon S3 バケットを作る
    • 今回だと aws-sam-cli-managed-default-samclisourcebucket-055e11c4
  • AWS リソースを作る
    • AWS::SQS::Queue
    • AWS::Lambda::Function
    • AWS::IAM::Role
    • AWS::Lambda::EventSourceMapping
$ export DEFAULT_REGION=ap-northeast-1

$ samlocal build

$ samlocal deploy --guided

Configuring SAM deploy
======================

    Looking for config file [samconfig.toml] :  Not found

    Setting default arguments for 'sam deploy'
    =========================================
    Stack Name [sam-app]: sandbox-app
    AWS Region [ap-northeast-1]:
    #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
    Confirm changes before deploy [y/N]:
    #SAM needs permission to be able to create roles to connect to the resources in your template
    Allow SAM CLI IAM role creation [Y/n]:
    #Preserves the state of previously provisioned resources when an operation fails
    Disable rollback [y/N]:
    Save arguments to configuration file [Y/n]:
    SAM configuration file [samconfig.toml]:
    SAM configuration environment [default]:

    Looking for resources needed for deployment:
    Creating the required resources...
    Successfully created!

    Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-055e11c4
    A different default S3 bucket can be set in samconfig.toml and auto resolution of buckets turned off by setting resolve_s3=False

    Saved arguments to config file
    Running 'sam deploy' for future deployments will use the parameters saved above.
    The above parameters can be changed by modifying samconfig.toml
    Learn more about samconfig.toml syntax at
    https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html

    Uploading to sandbox-app/62f50535d41ccb37bda86914d0d680f3  405 / 405  (100.00%)

    Deploying with following values
    ===============================
    Stack name                   : sandbox-app
    Region                       : ap-northeast-1
    Confirm changeset            : False
    Disable rollback             : False
    Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-055e11c4
    Capabilities                 : ["CAPABILITY_IAM"]
    Parameter overrides          : {}
    Signing Profiles             : {}

Initiating deployment
=====================

    Uploading to sandbox-app/12ff669083061914f8a1286e9c315653.template  781 / 781  (100.00%)


Waiting for changeset to be created..

CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                                           LogicalResourceId                                                   ResourceType                                                        Replacement
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                                               Queue                                                               AWS::SQS::Queue                                                     N/A
+ Add                                                               Function                                                            AWS::Lambda::Function                                               N/A
+ Add                                                               FunctionRole                                                        AWS::IAM::Role                                                      N/A
+ Add                                                               FunctionSqsEvent                                                    AWS::Lambda::EventSourceMapping                                     N/A
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:000000000000:changeSet/samcli-deploy1682430872/b79df315


2023-04-25 00:00:00 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 5.0 seconds)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                                                      ResourceType                                                        LogicalResourceId                                                   ResourceStatusReason
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_COMPLETE                                                     AWS::SQS::Queue                                                     Queue                                                               -
CREATE_COMPLETE                                                     AWS::IAM::Role                                                      FunctionRole                                                        -
CREATE_COMPLETE                                                     AWS::Lambda::Function                                               Function                                                            -
CREATE_COMPLETE                                                     AWS::Lambda::EventSourceMapping                                     FunctionSqsEvent                                                    -
CREATE_COMPLETE                                                     AWS::CloudFormation::Stack                                          sandbox-app                                                         -
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Successfully created/updated stack - sandbox-app in ap-northeast-1

🚀 デプロイ結果を確認する

awslocal コマンドを使って LocalStack にデプロイされた AWS リソースを確認する(日付は適当にマスキングしてある).

Amazon SQS キュー

$ awslocal sqs list-queues
{
    "QueueUrls": [
        "http://localhost:4566/000000000000/kakakakakku-queue"
    ]
}

AWS Lambda 関数

$ awslocal lambda list-functions
{
    "Functions": [
        {
            "FunctionName": "kakakakakku-function",
            "FunctionArn": "arn:aws:lambda:ap-northeast-1:000000000000:function:kakakakakku-function",
            "Runtime": "python3.9",
            "Role": "arn:aws:iam::000000000000:role/sandbox-app-FunctionRole-c5268ca9",
            "Handler": "app.lambda_handler",
            "CodeSize": 405,
            "Description": "",
            "Timeout": 3,
            "MemorySize": 128,
            "LastModified": "2023-04-25T00:00:00.000000+09:00",
            "CodeSha256": "fpUHNomors6Sbn3Ii0zpVUYGBpzxbmxSXB950QZmisg=",
            "Version": "$LATEST",
            "TracingConfig": {
                "Mode": "PassThrough"
            },
            "RevisionId": "ee14fbd2-1412-431b-b615-7c87676f4330",
            "PackageType": "Zip",
            "Architectures": [
                "x86_64"
            ],
            "EphemeralStorage": {
                "Size": 512
            },
            "SnapStart": {
                "ApplyOn": "None",
                "OptimizationStatus": "Off"
            }
        }
    ]
}

AWS Lambda 関数(イベントソースマッピング)

$ awslocal lambda list-event-source-mappings
{
    "EventSourceMappings": [
        {
            "UUID": "98e14881-4802-4e3d-be48-ffdf6766a455",
            "BatchSize": 10,
            "MaximumBatchingWindowInSeconds": 0,
            "EventSourceArn": "arn:aws:sqs:ap-northeast-1:000000000000:kakakakakku-queue",
            "FunctionArn": "arn:aws:lambda:ap-northeast-1:000000000000:function:kakakakakku-function",
            "LastModified": "2023-04-25T00:00:00.000000+09:00",
            "State": "Enabled",
            "StateTransitionReason": "USER_INITIATED",
            "FunctionResponseTypes": []
        }
    ]
}

Amazon S3 バケット

$ awslocal s3api list-buckets
{
    "Buckets": [
        {
            "Name": "aws-sam-cli-managed-default-samclisourcebucket-055e11c4",
            "CreationDate": "2023-04-25T00:00:00+00:00"
        },
        {
            "Name": "awslambda-ap-northeast-1-tasks",
            "CreationDate": "2023-04-25T00:00:00+00:00"
        }
    ],
    "Owner": {
        "DisplayName": "webfile",
        "ID": "75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a"
    }
}

Amazon CloudWatch Logs ロググループ

Amazon CloudWatch Logs ロググループは AWS SAM (AWS CloudFormation) で構築していないので1個もなくて OK👌この後 AWS Lambda 関数を実行してログを確認するため,実行前の状況を確認しておきたかった.

$ awslocal logs describe-log-groups
{
    "logGroups": []
}

🚀 動作確認をする

次は awslocal コマンドを使って Amazon SQS キューにメッセージを送信して,AWS Lambda 関数のイベントソースマッピングの動作確認をする.

$ MESSAGE='{ "my-key": "my-value" }'
$ awslocal sqs send-message --queue-url http://localhost:4566/000000000000/kakakakakku-queue --message-body ${MESSAGE}
{
    "MD5OfMessageBody": "3234172c8554dd70c6b2dbaac5acf11e",
    "MessageId": "678a5cd4-8849-4969-bbd7-0b9df93703d3"
}

すると Amazon CloudWatch Logs ロググループに "{ \"my-key\": \"my-value\" }" というログを確認できて,期待通り AWS Lambda 関数が実行されたことがわかる❗️

$ awslocal logs describe-log-groups
{
    "logGroups": [
        {
            "logGroupName": "/aws/lambda/kakakakakku-function",
            "creationTime": 1682431237731,
            "metricFilterCount": 0,
            "arn": "arn:aws:logs:ap-northeast-1:000000000000:log-group:/aws/lambda/kakakakakku-function:*",
            "storedBytes": 286
        }
    ]
}

$ awslocal logs describe-log-streams --log-group-name /aws/lambda/kakakakakku-function
{
    "logStreams": [
        {
            "logStreamName": "2023/04/25/[$LATEST]fe281c36f2654eb40cce1a30fbcfd8eb",
            "creationTime": 1682431237736,
            "firstEventTimestamp": 1682431237714,
            "lastEventTimestamp": 1682431237728,
            "lastIngestionTime": 1682431237742,
            "uploadSequenceToken": "1",
            "arn": "arn:aws:logs:ap-northeast-1:000000000000:log-group:/aws/lambda/kakakakakku-function:log-stream:2023/04/25/[$LATEST]fe281c36f2654eb40cce1a30fbcfd8eb",
            "storedBytes": 286
        }
    ]
}

$ awslocal logs get-log-events --log-group-name /aws/lambda/kakakakakku-function --log-stream-name '2023/04/25/[$LATEST]fe281c36f2654eb40cce1a30fbcfd8eb'
{
    "events": [
        {
            "timestamp": 1682431237714,
            "message": "START RequestId: 93a8f37b-5d8b-4c96-81fc-4e7bc3d3239e Version: $LATEST",
            "ingestionTime": 1682431237742
        },
        {
            "timestamp": 1682431237718,
            "message": "{ \"my-key\": \"my-value\" }",
            "ingestionTime": 1682431237742
        },
        {
            "timestamp": 1682431237723,
            "message": "END RequestId: 93a8f37b-5d8b-4c96-81fc-4e7bc3d3239e",
            "ingestionTime": 1682431237742
        },
        {
            "timestamp": 1682431237728,
            "message": "REPORT RequestId: 93a8f37b-5d8b-4c96-81fc-4e7bc3d3239e\tDuration: 13.08 ms\tBilled Duration: 14 ms\tMemory Size: 128 MB\tMax Memory Used: 128 MB\t",
            "ingestionTime": 1682431237742
        }
    ],
    "nextForwardToken": "f/00000000000000000000000000000000000000000000000000000003",
    "nextBackwardToken": "b/00000000000000000000000000000000000000000000000000000000"
}

もちろん AWS CloudFormation スタック sandbox-app もできあがっている✌️

$ awslocal cloudformation list-stacks
{
    "StackSummaries": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-sam-cli-managed-default/5f4cfa71",
            "StackName": "aws-sam-cli-managed-default",
            "CreationTime": "2023-04-25T00:00:00.000000+00:00",
            "LastUpdatedTime": "2023-04-25T00:00:00.000000+00:00",
            "StackStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/sandbox-app/d0a1ffad",
            "StackName": "sandbox-app",
            "CreationTime": "2023-04-25T00:00:00.000000+00:00",
            "LastUpdatedTime": "2023-04-25T00:00:00.000000+00:00",
            "StackStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}

🚀 お掃除

使わなくなったら awslocal cloudformation delete-stack コマンドで AWS CloudFormation スタックを削除できる.ちゃんと削除後は StackStatus が DELETE_COMPLETE になっている.

$ awslocal cloudformation delete-stack --stack-name sandbox-app

$ awslocal cloudformation list-stacks
{
    "StackSummaries": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-sam-cli-managed-default/5f4cfa71",
            "StackName": "aws-sam-cli-managed-default",
            "CreationTime": "2023-04-25T00:00:00.000000+00:00",
            "LastUpdatedTime": "2023-04-25T00:00:00.000000+00:00",
            "StackStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/sandbox-app/d0a1ffad",
            "StackName": "sandbox-app",
            "CreationTime": "2023-04-25T00:00:00.000000+00:00",
            "LastUpdatedTime": "2023-04-25T00:00:00.000000+00:00",
            "DeletionTime": "2023-04-25T00:00:00.000000+00:00",
            "StackStatus": "DELETE_COMPLETE",
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}

$ awslocal lambda list-functions
{
    "Functions": []
}

🚀 まとめ

Amazon SQS キューと AWS Lambda 関数の組み合わせなど「イベントソースマッピング(トリガー設定)」の動作確認をローカル環境で行うために samlocal コマンドを使って LocalStack にデプロイしてみた.最終的には LocalStack でサポートされている API 次第ではあるけど,今回の簡単なシナリオでは期待通りに動いた❗️

ちなみに LocalStack を使うときは,基本 awslocal コマンドを使うけど,LocalStack Web Application の Resource Browser を使うと,一部の AWS リソースであれば画面から確認できて便利なときもある❗️最初はウェブサイトからどうやってローカル環境の LocalStack にアクセスしてるんだろ?と疑問だったけど,ちょっと調べてみたら https://localhost.localstack.cloud:4566/ に対して API を呼び出す仕組みになっていた💨

docs.localstack.cloud

\( 'ω')/ あ〜 LocalStack 便利〜

blank-go: Go で動く AWS Lambda 関数に入門しよう

AWS Lambda 関数を Go ランタイムで動かす Hello World レベルの初学者コンテンツを探していて,ドキュメントにも載っている blank-go プロジェクトがお手軽に使えて良かったので紹介したいと思う❗️初学者に教えるときに使えるぞ〜 \( 'ω')/

github.com

ちなみに AWS Lambda に入門するための blank-xxx は Go 以外にも Node.js / Python / Java など多くある❗️

docs.aws.amazon.com

blank-go 紹介

blank-go では AWS CLI を使って Go ランタイムで動く AWS Lambda 関数をデプロイできる.実装としては,Amazon SQS のイベント情報(実際に Amazon SQS キューと連携するのではなく event.json を渡す)や AWS Lambda のコンテキスト情報をログ出力する感じで,Go で AWS Lambda 関数を実装するときのお作法なども参考になる.特にコードを書く必要はなく,準備された Shell を実行していく.試すだけならすぐ終わるし簡単❗️

$ ./1-create-bucket.sh
$ ./2-deploy.sh
$ ./3-invoke.sh

docs.aws.amazon.com

登場する代表的なサービス/リソースは以下など.

  • AWS Lambda(blank-go アプリケーション)
  • Amazon S3(デプロイ用)
  • AWS CloudFormation(AWS SAM デプロイ用)
  • Amazon CloudWatch Logs(AWS Lambda 関数のログ出力用)
  • AWS X-Ray(AWS Lambda サービスと AWS Lambda 関数のトレース用)

ちなみに M1 / M2 など Apple Silicon の macOS で実行すると Lambda 関数の実行時に以下のエラーが出る.今回は MacBook Pro (Apple M1 Max) を使っていて遭遇した.

{"errorMessage":"fork/exec /var/task/main: exec format error","errorType":"PathError"}

その場合は ./2-deploy.shgo build コマンドに GOARCH=amd64 を追加する必要がある.Apple Silicon を使っている人ならすぐ気付くとは思うけど,blank-go は初学者コンテンツなので,手順に書いておくと良さそうでプルリクエストも出しておいた.

$ GOOS=linux GOARCH=amd64 go build main.go

github.com

またお掃除用の 4-cleanup.sh を実行すると AWS Lambda 関連だけではなく Amazon S3 と Amazon CloudWatch Logs も含めてすべて消してくれるので,ゴミが残らないのも良かった👍

$ ./4-cleanup.sh

さらに一歩踏み込む(追加課題)

もし blank-go を使って初学者に AWS Lambda x Go を教えるなら,ただ実行するだけではなく,もう少し視野を広げて体験してもらうのが良さそう❗️追加課題的なものを考えながら実際に試してみた.

1. AWS Lambda 関数をローカル実行してみよう✌️

blank-go のデプロイには AWS SAM が使われているため sam local invoke コマンドを実行すれば AWS Lambda 関数を実環境にデプロイせずにローカル実行できる.

$ sam --version
SAM CLI, version 1.78.0

$ sam build

$ sam local invoke -e event.json
Invoking main (go1.x)
Using local image: public.ecr.aws/lambda/go:1-rapid-x86_64.

START RequestId: f5633c0b-79c7-44e2-bdec-4ba460c7a42a Version: $LATEST
(中略)
END RequestId: f5633c0b-79c7-44e2-bdec-4ba460c7a42a
REPORT RequestId: f5633c0b-79c7-44e2-bdec-4ba460c7a42a  Init Duration: 0.87 ms    Duration: 690.84 ms   Billed Duration: 691 ms    Memory Size: 128 MB    Max Memory Used: 128 MB
"{\"FunctionCount\":1,\"TotalCodeSize\":6399551}"

さらに AWS Toolkit for Visual Studio CodeAWS Toolkit for JetBrains を使えば,エディタ上で AWS Lambda 関数のデバッグをすることもできる.AWS Lambda 関数だと開発体験が悪そう...と言われたりもする懸念の一部は解消できると思う.

2. テストを実行してみよう✌️

blank-go の手順では特に紹介されていないけど,function ディレクトリには main_test.go も含まれていて,Go のテストも実行できる.今回のコードは環境変数 AWS_REGION をログ出力する実装になっているため,以下のように実行すれば OK!

$ cd function
$ AWS_REGION='ap-northeast-1' go test
PASS
ok      github.com/awsdocs/aws-lambda-developer-guide/sample-apps/blank-go  0.484s

ちなみにドキュメントに載っているベストプラクティスに Lambda ハンドラーをコアロジックから分離します。 とあって,もう少し工夫するなら main.gohandleRequest() 関数とコアロジックの依存を減らせばもっとテストしやすくなると思う.とは言え,今回の blank-go ではコアロジックと言える実装がないのでこれはこれで OK!

AWS Lambda 関数を実装するときも今までと同じく「テストのしやすさ」という観点は大切だよね〜❗️というディスカッションに繋げられると良いと思う👍

docs.aws.amazon.com

3. GitHub Actions で自動デプロイをしてみよう✌️

blank-go だと AWS CLI (aws cloudformation deploy コマンドなど)をラップした Shell を使ってデプロイをしてるけど,せっかくなら GitHub Actions で自動デプロイする仕組みを作ってみる.blank-go のコードを抜き出して新しく GitHub リポジトリを作って GitHub Actions ワークフロー (.github/workflows/deploy.yml) を以下のように作る.

name: blank-go

on:
  push:
    branches: master

permissions:
  id-token: write
  contents: read

jobs:
  build:
    name: Deploy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: aws-actions/setup-sam@v2
      - uses: aws-actions/configure-aws-credentials@v2
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: ap-northeast-1
      - run: sam build --use-container
      - run: sam deploy

aws cloudformation deploy コマンドじゃなく sam deploy コマンドを使ってデプロイしたり,AWS IAM 権限を取得するところをアクセスキーではなく OpenID Connect (OIDC) の仕組みを使って一時的な認証情報を使ったりという工夫をしている❗️関連する設定は割愛するけど以下のドキュメントなどに載っている👌

docs.github.com

期待通りに自動デプロイできた〜

4. ドキュメントを調べてみよう✌️

などなど📝

まとめ

AWS Lambda x Go に入門できる Hello World レベルのコンテンツ blank-go「さらに一歩踏み込む追加課題」の紹介でした❗️

github.com

CircleCI 2.0 + Apex で Lambda をデプロイする

Lambda をデプロイする場合,最近だと Serverless Framework もしくは AWS Serverless Application Model を使う場面が多いけど,他の AWS サービスに依存せず Lambda だけをデプロイしたい場合には Apex も積極的に使っている.要件がシンプルな場合に特に便利で,過去にも事例を記事にしている.

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

CircleCI 1.0 + Apex

今までは「CircleCI 1.0 + Apex」という組み合わせで Lambda をデプロイしていた.特に難しいことはなく,以下のようなシンプルな circle.yml を作成して,CircleCI 上で毎回 Apex をインストールしていた.ただし,8月末に CircleCI 1.0 のサポートが終了するため,そろそろ移行を考える必要があった.

machine:
  timezone: Asia/Tokyo

dependencies:
  post:
    - curl https://raw.githubusercontent.com/apex/apex/master/install.sh | sudo sh
    - apex version

deployment:
  master:
    branch: master
    commands:
      - apex deploy

Dockerized Apex

CircleCI 2.0 は Docker コンテナを使ってジョブを実行するため,Apex のコンテナが必要になる.ただし Apex 公式では提供されていなく,あまり良さそうなものもなかったため,今回 Alpine ベースで軽量な Dockerized Apex を作成した.バージョンは v1.0.0-rc2v0.16.0 をサポートしている.Docker イメージは kakakakakku/apex - Docker Hub に公開した.

github.com

CircleCI 2.0 + Apex

「CircleCI 2.0 + Apex」の場合は CircleCI 2.0 の記法で .circleci/config.yml を作成して,Dockerized Apex を使えば,今まで通り Lambda をデプロイできる.Docker コンテナを使うことにより,実行時間の短縮にも繋がり,メリットもある.

version: 2

jobs:
  deploy:
    docker:
      - image: kakakakakku/apex
    steps:
      - checkout
      - run: apex version
      - run: apex deploy

workflows:
  version: 2
  apex:
    jobs:
      - deploy

CircleCI の Environment Variables で,以下の環境変数を設定するのを忘れずに!

  • AWS_REGION
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

f:id:kakku22:20180508090052p:plain

(検証環境でデプロイをしてみた結果)

まとめ

  • CircleCI 2.0 + Apex でも Lambda をデプロイすることができた
  • CircleCI 2.0 のために Dockerized Apex を作成した

関連記事

CircleCI 2.0 の新機能「ワークフロー機能」の紹介を前に書いたから合わせて読んでもらえると!

kakakakakku.hatenablog.com

Lambda / Kinesis / DynamoDB / X-Ray などを組み合わせた実装を学べる「サーバーレスアプリケーション開発ガイド」を読んだ

今月発売されたばかりの「サーバーレスアプリケーション開発ガイド」を読んだので,書評をまとめたいと思う.著者の西谷さん,献本ありがとうございます!

Amazon Web Servicesを使ったサーバーレスアプリケーション開発ガイド

Amazon Web Servicesを使ったサーバーレスアプリケーション開発ガイド

  • 作者:西谷 圭介
  • 発売日: 2018/03/16
  • メディア: 単行本(ソフトカバー)

なお,サポートページからソースコードをダウンロードできる.コマンドもソースコードもそこそこ量があるため,写経せずに試したいという人はダウンロードして使うと良いかと.

book.mynavi.jp

概要

「サーバレスとは何か?」という解説からはじまり,実際に数種類の「サーバレスアプリケーション」を実装しながら理解を深めていく流れになっている.特に,多くの AWS サービスを組み合わせて学べる点が素晴らしく,例えば X-Ray などは,僕もまだ試したことがなかったので,今回学ぶことができた.実装する「サーバレスアプリケーション」ごとに,組み合わせる AWS サービスをザッと挙げる.こんなにある!

  • Amazon CloudWatch のアラームをトリガーに自動処理をする
    • Kinesis
    • CloudWatch
    • SNS
    • Lambda
  • Web サイトの状態を定期的にチェックする
    • Lambda
    • CloudWatch Events
  • Amazon Kinesis を使って Twitter のデータを受け取る
    • EC2
    • Kinesis
    • Lambda
    • DynamoDB
  • 写真投稿サイト
    • API Gateway
    • Lambda
    • DynamoDB
    • Rekognition
    • S3
    • Cognito
    • CloudFormation
    • Serverless Application Model (AWS SAM)
  • デリバリプロセスの自動化
    • CloudFormation
    • Serverless Application Model (AWS SAM)
    • CodeBuild
    • CodePipeline
  • トラブルシューティング
    • CloudWatch
    • CloudWatch Logs
    • X-Ray

本書の特徴は「ほぼ全てのオペレーションを AWS CLI で行う」という点だと思う.管理コンソールのデザインが変わっても AWS CLI のオペレーションは大幅に変わらないというメリットがあるし,オペレーションを積極的に Infrastructure as Code にするという意味でも AWS CLI をベースに学べるのはメリットだと思う.ただし,管理コンソールを意識しなくなるため,ちょっとでも気を抜くと「今,何をしてるんだっけ?」と方向性を見失ってしまう場面があった.このあたりはトレードオフだし,西谷さんのブログ記事にも意図が詳細に書かれている.

keisuke69.hatenablog.jp

Kinesis リシャーディング

まず「Amazon CloudWatch のアラームをトリガーに自動処理をする」を実際に試してみた.アーキテクチャは以下のようになっていて,Kinesis のデータストリームに閾値以上のレコードが登録された場合に,自動的にリシャーディングを行う.

f:id:kakku22:20180326204618p:plain

Kinesis にレコードを登録するために,以下の put-records.py を使った(データストリーム名は sample となる).AWS CLI は量が多くなってしまうため,本書を読んでもらえればと!

import boto3
import datetime
import time
import uuid

kinesis = boto3.client('kinesis')
stream_name = 'sample'

partition_key = str(uuid.uuid4())
data = datetime.datetime.utcnow().strftime('%s')

for i in range(15):
    kinesis.put_record(
        StreamName=stream_name,
        Data=data,
        PartitionKey=partition_key,
    )

作成した Lambda 関数の構成は,以下のようになっている.

f:id:kakku22:20180326204947p:plain

実際にリシャーディングを行った結果が以下となる.ちゃんと OpenShardCount の値が 1 → 2 に変わっている.

# Before
$ aws kinesis describe-stream-summary --stream-name sample
{
    "StreamDescriptionSummary": {
        "OpenShardCount": 1,
        "EncryptionType": "NONE",
        "StreamStatus": "ACTIVE",
        "StreamName": "sample",
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:111111111111:stream/sample",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamCreationTimestamp": 1521993626.0,
        "RetentionPeriodHours": 24
    }
}

# Put
$ python put-records.py

# After
$ aws kinesis describe-stream-summary --stream-name sample
{
    "StreamDescriptionSummary": {
        "OpenShardCount": 2,
        "EncryptionType": "NONE",
        "StreamStatus": "ACTIVE",
        "StreamName": "sample",
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:111111111111:stream/sample",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamCreationTimestamp": 1521993626.0,
        "RetentionPeriodHours": 24
    }
}

X-Ray

トラブルシューティングの事例として紹介されている X-Ray も実際に試してみた.設定は特に難しくなく,Lambda のトレースモードを有効にして,あとは X-Ray の結果を見るだけだった.X-Ray は今まで使ったことがなかったので,実際に処理内部のトレース結果が見れて良かった.

$ aws lambda update-function-configuration \
--function-name s3-get-object --tracing-config Mode=Active

f:id:kakku22:20180326205003p:plain

まとめ

  • 「サーバーレスアプリケーション開発ガイド」を読んだ
  • AWS サービスを組み合わせて数種類のアプリケーションを実装できた
  • Lambda だけじゃなく Kinesis / DynamoDB / AWS SAM などに興味があるなら読むべき
  • 本書のメインコンテンツとも言える「写真投稿サイト」は Vue.js で実装されていてフロントエンドの勉強にもなった
    • 途中まで写経してたけど,量が多くて,途中からソースコードをダウンロードして進めた

関連記事

去年に読んだ「サーバーレスシングルページアプリケーション」と似ている部分も多かった.ただし,フロントエンドは jQuery → Vue.js になっているし,組み合わせる AWS サービスも多いし,今から読むなら「サーバーレスアプリケーション開発ガイド」かなぁーと.

kakakakakku.hatenablog.com

同じく去年に読んだ「実践 AWS Lambda」も関連書籍と言える.もし AWS CLI メインで改版されるなら,もう1度読む!

kakakakakku.hatenablog.com

CROSS 2017 : Serverless Ninja Warriors でパネルディスカッションに参加してきた

今日 9/8 に横浜で開催された CROSS 2017 で,パネルディスカッションに参加してきた.テーマは Serverless Ninja Warriors で,サーバレスのガチ勢に囲まれて緊張したけど,楽しかったし,モチベーションも高まった.ありがとうございました!

2017.cross-party.com

資料

自己紹介として,簡単な資料を作成して最初に話をした.SpeakerDeck にアップロードするほどでもないため,そのまま画像で貼ってしまう.

話した内容としては,ザッと以下のような感じ.僕のポジションとしては「非ガチ勢」だったので,サーバレスに興味があるけど試したことがない人や,Lambda を管理コンソールで実装していて運用に困っている人などの参考になれば良いなと思っていた.

  • 個人的なサーバレスの定義は「FaaS の特性(ある意味で制約とも言える)を活かしたアーキテクチャ全般」と考えている(今のところ…)
  • サーバレスに限らず,スモールスタートを意識してチームに成功体験を作ると,導入障壁が下がる
    • そのために社内ツール系は最適
    • デプロイ/テストなど,ラストマイルも意識するとプロダクションレディな知見が得られる
  • CircleCI + Apex の組み合わせは非常に便利
    • Apex は複数ファンクションの管理も,複数環境へのデプロイもできる
    • ローカル環境は python-lambda-local を使っている

f:id:kakku22:20170908175225j:plain

f:id:kakku22:20170908175347j:plain

f:id:kakku22:20170908175406j:plain

質疑応答など

「CloudWatch Events など,Lambda 以外の AWS リソースはどのように管理しているのか?」という質問があり,ここは現状だと管理コンソールでポチポチしている.サービス全体で CloudFormation を導入するべきだと思うし,Apex + Terraform の構成にしても良いけど,現時点では既存のリソースへの影響が怖くて対応できていないという感じ.やらなきゃ!

「環境ごとにどのようにデプロイしているのか?」という質問もあり,これは Apex の Multiple Environments 機能を使っている.さらに Lambda の環境変数を Multiple Environments の定義ファイルに書けるため,それで invoke する Lambda の ARN などを管理している.あと IAM でも厳格にリソースを制限している.詳細は以下の記事を参照してもらえればと!

kakakakakku.hatenablog.com

補足など

ローカル環境の話が全体的にあまり無かったけど,僕は python-lambda-local を使っている.詳しくは以下の記事に!

kakakakakku.hatenablog.com

今日は話すタイミングが無かったけど,Apex の話をすると「Go 動くんでしょ?」とよく聞かれたりする.前に発表した資料の後半にまとめているけど,結局は Node.js の子プロセスで Go バイナリを動かして,プロセス間通信をしているだけなので,絶対に必要なら検討しても良いけど,AWS 公式でサポートされるまで待っても良いのでは?というのが個人的な判断かな.

kakakakakku.hatenablog.com

今回紹介したアーキテクチャは CloudWatch Events で Lambda を起動して SQS からメッセージを取得するため,ポーリング系の処理になっている.現時点では SQS のキュー操作は Lambda のイベントになっていないため,イベントドリブンにはなっていないけど,公式サポートが入ると嬉しいなとは思う.

会場で感じたこと

会場の各ホールが分離されていないため,隣のセッションの声がガンガン入ってきたり,マイクで音を拾えないと後ろの席まで届かなかったり,大規模カンファレンスの会場としては適していないのではないかなと思った.パネルディスカッションの序盤でそれに気付いたため,僕はかなり大きな声で話すようにした.

まとめ

今回パネルディスカッションに参加させてもらえて非常に刺激的だった.サーバレスとは何か?という疑問を自分なりに考え直せたことも良かったし,なによりも,パネルディスカッションに一緒に参加した皆さんの技術レベルが本当に高く,ディスカッションをするだけでも楽しかった.モチベーションも高まったし,もっともっと攻めて行かないとなと感じた.本当にありがとうございました!