Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

この記事は 「ハンズラボ 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」です!

zizi4n5
東急ハンズの内製iPadPOSアプリ、HandsPOS開発チームでテックリードをしています。
hands-lab
ハンズラボは小売業特化型ITソリューション企業です。数十万に及ぶ膨大な商品マスタを扱ってきた豊富なノウハウで、お客様の現場に最適なシステムを提案・開発します。 エンジニア募集中
https://www.hands-lab.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away