Edited at

Serverless FrameworkでVPC作るところからHello Worldまで全部自動化してみた!


はじめに

この記事は 「ハンズラボ Advent Calendar 2018」 22日目の記事です。

業務でAWSを利用することになったため、いろいろ自動化したいと思ってServerless Frameworkについて調べた内容をまとめました。

具体的には、Serverless Frameworkを使って以下の作業を行なっていきます。


  1. 事前準備(stage, profile, regionなどの設定)

  2. VPCの作成

  3. InternetGatewayの作成

  4. EIPの作成

  5. NatGatewayの作成

  6. Private Subnetの作成

  7. Public Subnetの作成

  8. APIGateway(Public Subnet)の作成

  9. Lambda(Private Subnet)の作成

  10. Serverlessでdeployしてみる

  11. Labmdaを実際に実行してみる

  12. 最後に

なお、本記事はAWSを初めて2ヶ月弱。

Serverless Frameworkを使い出して1週間の状態でいろいろ調べた結果をまとめた内容になっています。

このため、不備などあればぜひコメントで教えていただけるとうれしいです!


1. 事前準備(stage, profile, regionなどの設定)

今回は東京リージョンで、python3.7を指定して環境構築を行なっていきます。

profileは適宜ご自身の環境のものを利用してもらえればと思います。

また、serverless-python-requirementspluginも利用しますので、インストールをお願いします。


serverless.yml

provider:

name: aws
stage: ${opt:stage, 'stg'}
profile: serverless-sample-${self:provider.stage}
region: ap-northeast-1
runtime: python3.7
timeout: 30
memorySize: 128
versionFunctions: false
environment:
TZ: Asia/Tokyo

plugins:
- serverless-python-requirements

custom:
pythonRequirements:
dockerizePip: true
prefix: ${self:service}-${self:provider.stage}



1. VPCの作成

Resources配下に以下を追記します。

今回はサンプル環境のため、DeletionPolicyにDeleteを指定しています。


serverless.yml

# リソースの構築

resources:
Resources:

SampleVPC:
Type: AWS::EC2::VPC
DeletionPolicy: Delete
Properties:
CidrBlock: 10.1.0.0/16
Tags:
- Key: Name
Value: SampleVPC



2. InternetGatewayの作成

Resources配下に以下を追記します。


serverless.yml

    SampleInternetGateway:

Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: SampleInternetGateway

VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref SampleVPC
InternetGatewayId: !Ref SampleInternetGateway



3. EIPの作成

Resources配下に以下を追記します。

なお、他のResourceと同じようにPropertiesでTagsを試したところ、未サポートでしたのでコメントアウトしてあります。

EIPはVPC内に作成できる上限値があったりするので注意が必要です。


serverless.yml

    SampleElasticIp:

Type: AWS::EC2::EIP
Properties:
Domain: vpc
# Tags:
# - Key: Name
# Value: SampleElasticIp


4. NatGatewayの作成

Resources配下に以下を追記します。

なお、AllocationIdの指定でしばらくハマりました。

当初は、!Ref SampleElasticIpとしていたのですが、この指定だとEIPのIPアドレスが取得されてしまい、NatGatewayの作成で失敗してしまうため、注意が必要です。


serverless.yml

    SampleNatGateway:

DependsOn: SampleElasticIp
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt SampleElasticIp.AllocationId
SubnetId: !Ref SamplePublicSubnet
Tags:
- Key: Name
Value: SampleNatGateway


5 PrivateSubnetの作成

Resources配下に以下を追記します。


serverless.yml

    SamplePrivateSubnet:

DependsOn: SampleVPC
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SampleVPC
# AvailabilityZone: ${self:provider.region}a
CidrBlock: 10.1.1.0/24
Tags:
- Key: Name
Value: SamplePrivateSubnet

SamplePrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref SampleVPC
Tags:
- Key: Name
Value: SamplePrivateRouteTable

SamplePrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref SamplePrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref SampleNatGateway

SubnetRouteTableAssociationPrivateSubnet:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SamplePrivateSubnet
RouteTableId: !Ref SamplePrivateRouteTable



6. PublicSubnetの作成

Resources配下に以下を追記します。


serverless.yml

    SamplePublicSubnet:

DependsOn: SampleVPC
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SampleVPC
# AvailabilityZone: ${self:provider.region}a
CidrBlock: 10.1.11.0/24
Tags:
- Key: Name
Value: SamplePublicSubnet

SamplePublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref SampleVPC
Tags:
- Key: Name
Value: SamplePublicRouteTable

SamplePublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref SamplePublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref SampleInternetGateway

SubnetRouteTableAssociationPublicSubnet:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SamplePublicSubnet
RouteTableId: !Ref SamplePublicRouteTable



7. APIGatewayの作成

Resources配下に以下を追記します。

今回はサンプル環境のため、DeletionPolicyにDeleteを指定しています。


serverless.yml

    SampleApiGatewayRestApi:

Type: AWS::ApiGateway::RestApi
DeletionPolicy: Delete
Properties:
EndpointConfiguration:
Types:
- REGIONAL
Name: ${self:service}-${self:provider.stage}


8. SecurityGroupの作成

Resources配下に以下を追記します。


serverless.yml

    SampleSecurityGroup:

DependsOn: SampleVPC
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: SecurityGroup for Sample Functions
VpcId: !Ref SampleVPC


9. Lambdaの作成

Resources配下に以下を追記します。


serverless.yml

functions:

api:
# warmup: true
name: ${self:custom.prefix}-api
handler: lambda_function.lambda_handler
module: functions/api
vpc:
securityGroupIds:
- !Ref SampleSecurityGroup
subnetIds:
- !Ref SamplePrivateSubnet
events:
- http:
integration: lambda-proxy
path: helloworld
method: POST
cors: true
environment:
test: api-test
batch:
name: ${self:custom.prefix}-batch
handler: lambda_function.lambda_handler
module: functions/batch
vpc:
securityGroupIds:
- !Ref SampleSecurityGroup
subnetIds:
- !Ref SamplePrivateSubnet
environment:
test: batch-test

apiディレクトリ配下にapi用のPythonスクリプトlambda_function.pyおよび、空のファイルrequirements.txtを用意してください。

※ requirements.txtserverless-python-requirementsを利用している関係で必要となります。


api/lambda_function.py

import os

import logging

logger = logging.getLogger()
logLevel = logging.WARNING

def lambda_handler(event, context):

# Immediate response for WarmUP plugin
if event.get('source', None) == 'serverless-plugin-warmup':
logger.info('WarmUP - Lambda is warm!')
return 'Lambda is warm!'

return {
"statusCode": 200,
"body": "{\"message\": \"hello lambda api!\", \"input\": {\"test\": \"" + os.environ["test"] + "\"}}"
}


batchディレクトリ配下にbatch用のPythonスクリプトlambda_function.pyおよび、空のファイルrequirements.txtを用意してください。

※ requirements.txtserverless-python-requirementsを利用している関係で必要となります。


batch/lambda_function.py

import os

import logging

logger = logging.getLogger()
logLevel = logging.WARNING

def lambda_handler(event, context):
return {
"message": "hello lambda batch!", "input": {"test": os.environ["test"]}
}



10. Serverlessでdeployしてみる

profileの設定などを確認して、以下のコマンドを実行します。

$ serverless deploy

1から環境を構築するため、数分かかります。

のんびり気長に待ってください。

以下のような結果が表示されれば環境構築成功です。

Serverless: Packaging service...

Serverless: Excluding development dependencies...
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 (1.64 KB)...
Serverless: Uploading service .zip file to S3 (1.64 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.................................................................................
Serverless: Stack update finished...
Service Information
service: serverless-sample
stage: stg
region: ap-northeast-1
stack: serverless-sample-stg
api keys:
None
endpoints:
POST - https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/stg/helloworld
functions:
api: serverless-sample-stg-api
batch: serverless-sample-stg-batch
layers:
None


11. Labmdaを実際に実行してみる


11.1. functionのapiを実行する

functionのapiはapigatewayと関連付けしているため、作成されたendpointをcurlで実行してみます。

$ curl -X POST -H "Content-Type: application/json" https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/stg/helloworld

以下のようなレスポンスが返却されてくれば成功です。

{"message": "hello lambda api!", "input": {"test": "api-test"}}


11.2. functionのbatchを実行する

functionのbatchはapigatewayと関連付けしていないため、serverlessコマンドで実行します。

$ serverless invoke -f batch

以下のようなレスポンスが返却されてくれば成功です。

{

"message": "hello lambda batch!",
"input": {
"test": "batch-test"
}
}


12. 最後に

UnixやLinuxをオンプレ環境で構築したことなどはあったのですが、AWSでServerless Frameworkなどを使って環境構築などをすれば、再現性もあり非常に便利だなと感じました。

今後もAWSについてもっと勉強していきたいと思います。

「ハンズラボ Advent Calendar 2018」 の23日目は、@daisudaisuke さんの「Amazon Managed Blockchainでフリマアプリ作りたい Part1」です!