API 開発を Lambda と API Gateway の組み合わせで開発することが多くなってきました。
しかし、AWS のサービスはコンソールからポチポチと設定できてしまうので保守・運用する側からは設定情報が Git などに残らずに困ってしまいます。
そこでこれらの環境を Git で管理できるようにすべくソースコードで環境を構築してしまうチュートリアルを用意しました。
概要
AWS Lambda と Amazon API Gateway を本番環境で利用するときの Docker 開発環境です。
ここでは API 定義に Swagger を利用しています。
目次
環境構成
・前提条件
・開発環境で作成するファイル
・AWS 上に作成されるリソース
開発環境作成手順
・フォルダ構成
・AWS SAM CLI 用 の Python ベースの dockerfile 作成
・docker-compose.yml の作成
・swagger.yml の作成
・docker-compose の起動
・AWS SAM CLI を使った Lambda 関数の作成
・コンテナへのアタッチ
・AWS SAM CLI の実行と初期プロジェクトの作成
・template.yaml の実装
・ソースコードの実装
・S3 バケットの作成
・swagger.yml を S3 へアップロード
本番デプロイ準備
・samconfig.toml の作成
・ビルド
本番デプロイ
・作成されたリソースの確認
いざコード開発の開始!!
削除コマンド
最後に
環境構成
作成するファイルや実際に AWS 上に作成されるリソースです。
前提条件
- 著者は Mac 環境で動作検証を行っております。
- Docker を利用するのでインストールしておいてください。
- ホストサーバーに
~/.aws
フォルダと config ファイルにcredential や profile 情報が設定されていることを前提で進めます。 まだ、設定していない方は AWS CLI のインストールと AWS CLI の設定方法を参考にしてください。
開発環境で作成するファイル
- AWS SAM CLI と node.js のビルド環境を動かす Python用の Dockerfile
- API Gateway と Lambda の環境を構築する template.yaml
- API Gateway の API エンドポイントなどを定義する swagger.yml
- SAM のビルド & デプロイ用の設定ファイル samconfig.toml
- Node.js のパッケージ管理ファイル package.json
- AWS SAM CLI と Swagger Editor のコンテナを起動する docker-compose.yml
- lambda で実行されるソースコード一式
※ 開発環境と言っても、今回ご紹介する手順は最終的に AWS 上へデプロイする形になります。
AWS SAM では lambda をローカルでエミュレートできるみたいですが今回は試していません。
AWS 上に作成されるリソース
- Swagger の swagger.yml ファイル と SAM の template.yaml を保存する S3 バケット (手動作成)
- API Gateway
- SAM から自動生成される Lambda 用の IAM Role
- Lambda (nodejs14)
開発環境作成手順
では、開発環境を作成していきます。
フォルダ構成
下記が作成するフォルダ構成です。
Project
│── Dockerfiles
│ └── python
│ └── Dockerfile
├── README.md
├── docker-compose.yml
├── sam-app
│ ├── README.md
│ ├── events
│ ├── hello-world
│ │ ├── app.js
│ │ ├── node_modules
│ │ ├── package.json
│ │ ├── tests
│ ├── samconfig.toml
│ └── template.yaml
└── swagger.yml
Dockerfiles: 利用するコンテナを定義した dockerfile 群
sam-app: AWS SAM CLI で作成される初期ソースコードのテンプレート
docker-compose.yml: Dockerfiles で定義したコンテナを管理 & 実行
swagger.yml: Swagger で定義した OPEN API 設計ファイル
AWS SAM CLI 用 の Python ベースの dockerfile 作成
AWS SAM CLI を実行する Dockerfile を作成します。ついでに node.js をビルドする npm も Python コンテナにインストールしてしまいます。ここは node コンテナと分けてもらっても構わないですが、特に Web サーバとして動かす必要がないので、 Python コンテナに npm を同居させています。
FROM python:3.9-alpine
ENV NODE_PATH /usr/lib/node_modules/
# install nodejs
RUN apk update \
&& apk add --no-cache \
nodejs \
npm \
gcc \
libc-dev \
git
# install aws-cli
RUN pip3 install awscli
# install aws-sam-cli
RUN pip3 install -U aws-sam-cli
# change work directory
RUN mkdir -p /app
WORKDIR /app
docker-compose.yml の作成
docker-compose.yml です。先ほど作成した AWS SAM CLI 用の Dockerfile と Swagger Editor をローカルで動かすコンテナを実行します。
version: "3.5"
services:
sam:
build:
context: ./dockerfiles/python/
dockerfile: Dockerfile
tty: true # 後でコンテナ内にアタッチするので tty と stdin_open を true にする
stdin_open: true
image: sam
working_dir: /app
volumes:
- .:/app # ホストのプロジェクトフォルダをコンテナ内の /app にマウント
- ~/.aws:/root/.aws # aws cli をコンテナから操作できるようにホストの .aws をマウント
container_name: sam
swagger:
ports:
- "8081:8080"
image: swaggerapi/swagger-editor
working_dir: /app
environment: # コンテナ内の swagger 定義ファイルパス
- SWAGGER_FILE=/app/swagger.yml
volumes:
- .:/app
- ~/.aws:/root/.aws
container_name: swagger
swagger.yml の作成
swagger.yml に API 定義を記述していきます。今回はサンプルとして、Swagger 公式が上げている OpenAPI 3.0 の petstore を参考に AWS API Gateway に対応させるように改造していきます。
今回サンプル用に改造した yaml ファイルが下記になります。
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
responses:
'200':
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
x-amazon-apigateway-integration:
uri: # APIからキックするLambda関数のARN
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PetStoreFunction.Arn}/invocations
passthroughBehavior: when_no_templates
httpMethod: GET
type: aws_proxy
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
x-amazon-apigateway-integration:
uri: # APIからキックするLambda関数のARN
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PetStoreFunction.Arn}/invocations
passthroughBehavior: when_no_templates
httpMethod: POST
type: aws_proxy
########### 以下省略 ###########
components:
########### 以下省略 ###########
追加した箇所は、下記2箇所です。
x-amazon-apigateway-integration:
uri: # APIからキックするLambda関数のARN
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PetStoreFunction.Arn}/invocations
passthroughBehavior: when_no_templates
httpMethod: POST ## POST のエンドポイントは GET を指定する
type: aws_proxy
x-amazon-apigateway-integration:
uri: # APIからキックするLambda関数のARN
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PetStoreFunction.Arn}/invocations
passthroughBehavior: when_no_templates
httpMethod: GET ## GET のエンドポイントは GET を指定する
type: aws_proxy
他はすべて、参考にした github のコードのままになります。
ここでは、API Gateway がキックする Lambda を定義しています。 Swagger で定義した API Gateway のエンドポイントパスを叩くと、ここで定義した lambda が実行されるといった処理になります。
x-amazon-apigateway-integration
に定義する httpMethod
は swagger で定義したエンドポイントパスに対応するメソッドを指定してください。
また uri
には後述する Lambda 関数の ARN を指定します。したがって ${PetStoreFunction.Arn}
は、ご自身の環境の Lambda 関数名.arn
を指定してください
docker-compose の起動
ここで一度 docker-compose up
で Docker コンテナを起動してみます。
起動が完了したら localhost:8081
にアクセスしてみます。
下記のように Swagger Editor が表示されたら OK です。
ブラウザの Swagger Editor で修正した yaml ファイルはローカルには自動で反映されないので、必ずローカルのIDE または エディタから編集してブラウザで確認といった形で修正内容を確認しましょう。
もしブラウザで修正したい場合は yaml ファイルをブラウザで修正後ダウンロードもできます。
AWS SAM CLI を使った Lambda 関数の作成
続いて、立ち上げた AWS SAM CLI 用のコンテナ(コンテナ名: sam)にアクセスして AWS SAM CLI を実行し初期プロジェクトを作成します。
コンテナへのアタッチ
▼ コマンドの方は下記コマンドを実行します。
$ docker exec -it sam /bin/sh
▼ VSCodeの場合は Docker Extension からコンテナ内へアタッチすることができます。
AWS SAM CLI の実行と初期プロジェクトの作成
アタッチしたコンテナ内で AWS SAM CLI を実行して初期プロジェクトを作成します。
AWS SAM CLI の AWS 公式チュートリアルを参考にしています。
▼ 実行した SAM CLI のコマンド(選択した選択肢のみ記載しています)
/app $ sam --version
# SAM CLI, version 1.18.1
/app $ sam init
Which template source would you like to use?
1 - AWS Quick Start Templates
What package type would you like to use?
1 - Zip (artifact is a zip uploaded to S3)
Which runtime would you like to use?
1 - nodejs14.x
AWS quick start application templates:
1 - Hello World Example
# 出力結果
-----------------------
Generating application:
-----------------------
Name: sam-app
Runtime: nodejs14.x
Dependency Manager: npm
Application Template: hello-world
Output Directory: .
Next steps can be found in the README file at ./sam-app/README.md
上記のようにテンプレートを作成するための選択肢が出てきます。
今回は nodejs で lambda を開発するので Runtime は nodejs14.x
を選びました。
デプロイ先は S3
にしております。
その他の選択肢は上記を参考にしてください。
テンプレートが作成されるとプロジェクトフォルダに hello-world
フォルダが作成されます。
template.yaml の実装
ここでは、チュートリアルで作成された template.yaml
を編集し swagger に対応させるように修正します。
追記する観点は下記2項目です。
- API Gateway の定義を追加
- Lambda function にエンドポイントパスイベントを定義
※ 上記2点の修正箇所に伴って Outputs の値なども修正しております。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
Globals:
Function:
Timeout: 3
Parameters:
# swagger.yml をアップロードしているバケット名
BucketName:
Type: String
Resources:
# PetStore 用の API Gateway を定義
PetStoreApi:
Type: AWS::Serverless::Api
Properties:
Name: !Ref "AWS::StackName"
StageName: prod
OpenApiVersion: 3.0.0
DefinitionBody:
Fn::Transform:
Name: AWS::Include
Parameters:
Location: !Sub s3://${BucketName}/swagger.yml
# Lambda 関数の設定を定義 (Hello-world のコードを流用)
PetStoreFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs14.x
Events:
PetsGet:
Type: Api
Properties:
Path: /pets
Method: get
RestApiId: !Ref PetStoreApi # API を参照
PetsPetIdGet:
Type: Api
Properties:
Path: /pets/{petId}
Method: get
RestApiId: !Ref PetStoreApi # API を参照
PetsPost:
Type: Api
Properties:
Path: /pets
Method: post
RestApiId: !Ref PetStoreApi # API を参照
Outputs:
PetStoreApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${PetStoreApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/pet/"
PetStoreFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt PetStoreFunction.Arn
PetStoreFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt PetStoreFunctionRole.Arn
注目するところは下記設定です。
-
PetStoreApi
にOpenApiVersion: 3.0.0
を指定する。 -
PetStoreApi
のDefinitionBody
に swagger.yml をアップロードした S3 バケット URL をセットする。
OpenApiVersion: 3.0.0
DefinitionBody:
Fn::Transform:
Name: AWS::Include
Parameters:
Location: !Sub s3://${BucketName}/swagger.yml
-
PetStoreFunction
のEvents
に swagger.yml で定義したエンドポイントパスを定義する。
Events:
PetsGet:
Type: Api
Properties:
Path: /pets
Method: get
RestApiId: !Ref PetStoreApi # API を参照
ソースコードの実装
Lambda Function のソースコードを実装します。
ここでは、サンプルのためチュートリアルのコードのままにします。
S3 バケットの作成
ビルドされた template.yaml やコード、 swagger.yml を保存する S3 バケットを手動で作成します。
/app $ aws s3 mb s3://sam-app-bucket-pfr379vgrp0 --profile default
swagger.yml を S3 へアップロード
先ほど作成した S3 バケットに swagger.yml ファイルをアップロードします。
/app $ aws s3 cp swagger.yml s3://sam-app-bucket-pfr379vgrp0/swagger.yml --profile default
以上が開発環境の作成です。次に AWS 環境へデプロイする準備を行います。
本番デプロイ準備
本番へデプロイするための準備を行います。
samconfig.toml の作成
デプロイするための情報を toml 形式で sam-app
直下に保存します。
version=0.1
[default.deploy.parameters]
stack_name = "sam-app"
s3_bucket = "sam-app-bucket-pfr379vgrp0"
s3_prefix = "sam-app"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
ビルド
AWS SAM CLI を利用してコードのビルドを行います。
/app $ cd sam-app
/app/sam-app $ sam build
ビルドが完了し、.aws-sam
フォルダに build
フォルダが作成されていればビルドが成功です。
ちなみに自動で npm install
コマンドが実行され node_module
をビルドに含めてくれているみたいです。
本番デプロイ
最後にデプロイを行います。
/app/sam-app $ sam deploy --profile default --config-env default --parameter-overrides BucketName=sam-app-bucket-pfr379vgrp0
### 省略 ###
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
2021-04-14 08:23:23 - Waiting for stack create/update to complete
CloudFormation events from changeset
### 省略 ###
Successfully created/updated stack - sam-app in ap-northeast-1
オプション | 解説 |
---|---|
--profile | AWS CLI の ~/.aws/config に設定した profile。自身のデプロイ先のAWSアカウントを指定してください。 デフォルト: default |
--config-env | samconig.toml の設定情報 deploy.parameters の前の文字列を指定します。 デフォルト: default |
---parameter-overrides | template.yaml の Parameters に定義したパラメータをここで指定できます。 |
Successfully が表示されたらデプロイの完了です。
作成されたリソースの確認
いざコード開発の開始!!
これで環境構築と、デプロイができました!!
あとは、Lambda Function の開発を行い、コードを修正したら上記手順でまたビルド & デプロイ すると AWS 上で自身で作成した API が確認できます。
削除コマンド
今回作成したリソースは認証のかかっていない API になっています。
なので削除コマンドも載せておきます。
/app $ aws cloudformation delete-stack --stack-name sam-app --profile default
最後に
Swagger と API Gateway を連携することで Swagger の API 定義書と API Gateway の実際のリソースが同期されるようになりました。
連携しておけば、「API定義書が古い!!」といった事象も起こりにくくなると思います。
こういった初期プロジェクトの作成はなかなか全員の開発者が触れるものではないので貴重な体験です。
また、プロジェクトの最初にしか実行しないので、悪戦苦闘することが多いです。
そういった方に見てもらえると幸いですm(_ _)m
今回は手動でデプロイしましたが、これらを自動で開発、ステージ、本番へデプロイしたりテストステージを組み込んだ CI・CD 環境を作ることもできます。
それらは次回ご紹介しようと思いますm(_ _)m