ServerlessでAWS Lambdaのデプロイをいい感じにする
Serverless Frameworkとは
通常AWS Lambdaを使う上で面倒な手順としてある。
- 関数を作成する
- AWS マネジメントコンソールからLambdaの管理画面にアクセスする
- 関数をアップロードする(圧縮するとかもある)
- トリガーとなるイベントの設定など
上に書いたような手間を解消してくれるのが今回紹介する「Serverless Framework」(以下Serverless)です。
http://tikasan.hatenablog.com/entry/2018/06/27/083316
AWSしか使わない人へ
Serverless Frameworkは様々なクラウドへのサーバーレスをアプリケーションの展開を考えている人にはうってつけですが、AWSしか使わないなら、AWS SAMがおすすめでした。
インストール
Serverlessのインストールにはnode(v4以上)の環境が必要です。
❯ node -v v10.0.0 ❯ npm install -g serverless ... + serverless@1.27.3 added 310 packages in 19.063s ❯ serverless -v 1.27.3
IAMユーザーの作成
ServerlessはAWS APIを使って操作をします。なので、Adminstrator Acessを付与したServerless用のユーザーの作成をして、そのユーザーを使って色々な操作をすることになります。(defaultの自分のアカウントでも良いですが)
❯ vim ~/.aws/credentials [default] aws_access_key_id = hoge aws_secret_access_key = fuga [serverless] aws_access_key_id = hoge2 aws_secret_access_key = fuga2
❯ vim ~/.aws/config [default] output = json region = ap-northeast-1 [serverless] output = json region = ap-northeast-1
credentialsどうする問題は、公式が結構頑張って書いてくれてるので、そこ見たら良さそう。
Serverless Framework - AWS Lambda Guide - Credentials
今回は、専用のユーザーを作成するパターンでやっていきます。
事始め
さっそくServerlessのプロジェクトを作成してみましょう。ここからは長ったらしい serverless
ではなく、短縮形の sls
を使っていきます。slsには、templeateを作成する機能があり、これを使うと良い感じのsampleを見ることが出来ます。
選べるテンプレートは以下の通り。(すごい)
Template "true" is not supported. Supported templates are: "aws-nodejs", "aws-nodejs-typescript", "aws-nodejs-ecma-script", "aws-python", "aws-python3", "aws-groovy-gradle", "aws-java-maven", "aws-java-gradle", "aws-kotlin-jvm-maven", "aws-kotlin-jvm-gradle", "aws-kotlin-nodejs-gradle", "aws-scala-sbt", "aws-csharp", "aws-fsharp", "aws-go", "aws-go-dep", "azure-nodejs", "fn-nodejs", "fn-go", "google-nodejs", "kubeless-python", "kubeless-nodejs", "openwhisk-java-maven", "openwhisk-nodejs", "openwhisk-php", "openwhisk-python", "openwhisk-swift", "spotinst-nodejs", "spotinst-python", "spotinst-ruby", "spotinst-java8", "webtasks-nodejs", "plugin" and "hello-world".
~/go/src/github.com/pei0804/serverless-sample/serverless master* ❯ sls create --template aws-go Serverless: Generating boilerplate... _______ __ | _ .-----.----.--.--.-----.----| .-----.-----.-----. | |___| -__| _| | | -__| _| | -__|__ --|__ --| |____ |_____|__| \___/|_____|__| |__|_____|_____|_____| | | | The Serverless Application Framework | | serverless.com, v1.27.3 -------' Serverless: Successfully generated boilerplate for template: "aws-go" Serverless: NOTE: Please update the "service" property in serverless.yml with your service name ~/go/src/github.com/pei0804/serverless-sample/serverless master* ❯ ls Makefile hello serverless.yml world
では、何が書かれているか見てみましょう。
hello/main.go
よくあるhello worldサンプル
package main import ( "github.com/aws/aws-lambda-go/lambda" ) type Response struct { Message string `json:"message"` } func Handler() (Response, error) { return Response{ Message: "Go Serverless v1.0! Your function executed successfully!", }, nil } func main() { lambda.Start(Handler) }
world/main.go
package main import ( "github.com/aws/aws-lambda-go/lambda" ) type Response struct { Message string `json:"message"` } func Handler() (Response, error) { return Response{ Message: "Okay so your other function also executed successfully!", }, nil } func main() { lambda.Start(Handler) }
デプロイ先でも動くようにというお気持ちの入ったbuildコマンドが書かれていました。
build: go get github.com/aws/aws-lambda-go/lambda env GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go env GOOS=linux go build -ldflags="-s -w" -o bin/world world/main.go
serverless.yml
slsに関する設定が色々書いてある。ひとまず、serviceの名前と、regionだけ変えておく。
# Welcome to Serverless! # # This file is the main config file for your service. # It's very minimal at this point and uses default values. # You can always add more config options for more control. # We've included some commented out config examples here. # Just uncomment any of them to get that config option. # # For full config options, check the docs: # docs.serverless.com # # Happy Coding! service: hello <-- ここ自分のつけたい名前を適当につける # service: aws-go # NOTE: update this with your service name # You can pin your service to only deploy with a specific Serverless version # Check out our docs for more details # frameworkVersion: "=X.X.X" provider: name: aws runtime: go1.x # you can overwrite defaults here # stage: dev # region: us-east-1 region: ap-northeast-1 <-- 東京リージョンにしておく # you can add statements to the Lambda function's IAM Role here # iamRoleStatements: # - Effect: "Allow" # Action: # - "s3:ListBucket" # Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] } # - Effect: "Allow" # Action: # - "s3:PutObject" # Resource: # Fn::Join: # - "" # - - "arn:aws:s3:::" # - "Ref" : "ServerlessDeploymentBucket" # - "/*" # you can define service wide environment variables here # environment: # variable1: value1 package: exclude: - ./** include: - ./bin/** functions: hello: handler: bin/hello world: handler: bin/world # The following are a few example events you can configure # NOTE: Please make sure to change your handler code to work with those events # Check the event documentation for details # events: # events: # - http: # path: users/create # method: get # - s3: ${env:BUCKET} # - schedule: rate(10 minutes) # - sns: greeter-topic # - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000 # - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx # - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx # - iot: # sql: "SELECT * FROM 'some_topic'" # - cloudwatchEvent: # event: # source: # - "aws.ec2" # detail-type: # - "EC2 Instance State-change Notification" # detail: # state: # - pending # - cloudwatchLog: '/aws/lambda/hello' # - cognitoUserPool: # pool: MyUserPool # trigger: PreSignUp # Define function environment variables here # environment: # variable2: value2 # you can add CloudFormation resource templates here #resources: # Resources: # NewResource: # Type: AWS::S3::Bucket # Properties: # BucketName: my-new-bucket # Outputs: # NewOutput: # Description: "Description for the output" # Value: "Some output value"
デプロイと実行
~/go/src/github.com/pei0804/serverless-sample/serverless master* 16s ❯ make build go get github.com/aws/aws-lambda-go/lambda env GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go env GOOS=linux go build -ldflags="-s -w" -o bin/world world/main.go ~/go/src/github.com/pei0804/serverless-sample/serverless master* ❯ sls deploy Serverless: Packaging service... Serverless: Excluding development dependencies... Serverless: Creating Stack... Serverless: Checking Stack create progress... ..... Serverless: Stack create finished... Serverless: Uploading CloudFormation file to S3... Serverless: Uploading artifacts... Serverless: Uploading service .zip file to S3 (4.5 MB)... Serverless: Validating template... Serverless: Updating Stack... Serverless: Checking Stack update progress... ........................ Serverless: Stack update finished... Service Information service: hello stage: dev region: ap-northeast-1 stack: hello-dev api keys: None endpoints: None functions: hello: hello-dev-hello world: hello-dev-world ~/go/src/github.com/pei0804/serverless-sample/serverless master* ❯ sls invoke -f hello { "message": "Go Serverless v1.0! Your function executed successfully!" } ~/go/src/github.com/pei0804/serverless-sample/serverless master* ❯ sls invoke -f world { "message": "Okay so your other function also executed successfully!" } ~/go/src/github.com/pei0804/serverless-sample/serverless master* ❯ sls logs -f hello START RequestId: 7dbebc56-7995-11e8-be4f-4788beaf19d2 Version: $LATEST END RequestId: 7dbebc56-7995-11e8-be4f-4788beaf19d2 REPORT RequestId: 7dbebc56-7995-11e8-be4f-4788beaf19d2 Duration: 0.75 ms Billed Duration: 100 ms Memory Size: 1024 MB Max Memory Used: 27 MB
動いているっぽい。この時点で既に便利!!
マネジメントコンソールからも確認出来た。
stageとかprofileをcliからいじる
設定ファイルにハードコーディングせずに、stageとかprofile変えたいなーっていうアレ。やり方としては、sreverless.ymlのproviderのところに設定を加えれば良い感じになる。
内容としては、--profileに指定がなければdefaultを使う。--stageに指定がなければdevという感じ。
service: hello provider: name: aws runtime: go1.x profile: ${opt:profile, self:custom.defaultProfile} stage: ${opt:stage, self:custom.defaultStage} region: ap-northeast-1 custom: defaultStage: dev defaultProfile: default package: exclude: - ./** include: - ./bin/** functions: hello: handler: bin/hello world: handler: bin/world
cliでオプションで渡す。
~/go/src/github.com/pei0804/serverless-sample/serverless master* 15s ❯ sls deploy --profile serverless --stage production Serverless: Packaging service... Serverless: Excluding development dependencies... Serverless: Creating Stack... Serverless: Checking Stack create progress... ..... Serverless: Stack create finished... Serverless: Uploading CloudFormation file to S3... Serverless: Uploading artifacts... Serverless: Uploading service .zip file to S3 (4.5 MB)... Serverless: Validating template... Serverless: Updating Stack... Serverless: Checking Stack update progress... ........................ Serverless: Stack update finished... Service Information service: hello stage: production region: ap-northeast-1 stack: hello-production api keys: None endpoints: None functions: hello: hello-production-hello world: hello-production-world
いい感じ!!
とりあえず、今回はここまで、次回はロジックとハンドラ分けたり、もうちょっと踏み込んだ内容やってみる。
前はapexを使ったりしていたけど、serverlessもかなり良さそう。