#はじめに
皆さん、こちらの記事はご覧になりましたか?私も記事が出た当日に見てはいたのですが、同僚にも「めっちゃ速いよ!」と言われたのですが、スルーしてました。
でも、百聞は一見に如かずなんですよね。
re:Invent 2021のLeadership SessionであるAccelerating your serverless journey with AWS LambdaでSAM AccelerateとStep Functionsのデモが披露されていたのですが、それを見て、
「あ、すぐ使いたい」と思って、使ってみたのです。
ということで、今日は、こちらのブログで詳しく紹介されていますが、自分で試したことをまとめたいと思います
なお、執筆時点(2021/12/06)で当機能はPublic Previewです。
#サマリ
- SAM AccelerateはLambda関数のコードの変更時に迅速なデプロイが可能
-
sam build -c
は依存関係の変更がない場合のビルドが高速化されローカル開発で重宝しそう。 -
sam logs
も素敵。
#環境
タイトルにもある通り、Cloud9 を新規に立ち上げて整備してみます。なお、構築したのは、2021/12/05ですので、最新とは異なる可能性があります。
Cloud9の起動と初期セットアップ
Cloud9の起動
まずは、Cloud9を用意しました。
はい、出来上がり。 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535037/b6bf1cd7-f64b-aad4-7b0d-bed250637fdf.png)ディスク拡張
次に初期サイズではディスクが足りなくなる可能性があることから、念のため、EBSを30GBに拡張します。
手順
こちらの手順にあるスクリプトをコピーして、Cloud9のエディターでresize.shとして作成します。続いて以下のコマンドを実行すれば、数秒で拡張が完了。
$ sh resize.sh 30
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 19 100 19 0 0 1583 0 --:--:-- --:--:-- --:--:-- 1583
{
"VolumeModification": {
"TargetSize": 30,
"OriginalMultiAttachEnabled": false,
"TargetVolumeType": "gp2",
"ModificationState": "modifying",
"TargetMultiAttachEnabled": false,
"VolumeId": "vol-064045755a07c2231",
"TargetIops": 100,
"StartTime": "2021-12-04T05:35:49.000Z",
"Progress": 0,
"OriginalVolumeType": "gp2",
"OriginalIops": 100,
"OriginalSize": 10
}
}
CHANGED: partition=1 start=4096 old: size=20967391 end=20971487 new: size=62910431 end=62914527
meta-data=/dev/xvda1 isize=512 agcount=6, agsize=524159 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1 spinodes=0
data = bsize=4096 blocks=2620923, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
data blocks changed from 2620923 to 7863803
AWS CLI/AWS SAMのアップデート
そこに、AWS CLIの最新版の導入手順と、AWS SAMの最新版の導入手順を見ながら、環境を用意します。
手順
$ aws --version
aws-cli/1.19.112 Python/2.7.18 Linux/4.14.252-195.483.amzn2.x86_64 botocore/1.20.112
$ sam --version
SAM CLI, version 1.33.0
# 結構新しい
SAMはまあまあ新しいですが、AWS CLIは超古いですね。これは確実にUpdateが必要です。
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 43.3M 100 43.3M 0 0 101M 0 --:--:-- --:--:-- --:--:-- 101M
$ unzip awscliv2.zip
# (省略)
$sudo ./aws/install --update
You can now run: /usr/local/bin/aws --version
$ curl -L https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip --output aws-sam-cli-linux-x86_64.zip
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 155 100 155 0 0 3655 0 --:--:-- --:--:-- --:--:-- 3690
100 665 100 665 0 0 13878 0 --:--:-- --:--:-- --:--:-- 13878
100 50.7M 100 50.7M 0 0 53.2M 0 --:--:-- --:--:-- --:--:-- 63.3M
$unzip aws-sam-cli-linux-x86_64.zip -d sam-installation
$sudo ./sam-installation/install --update
You can now run: /usr/local/bin/sam --version
ということで、アップデートとできてるか、ターミナルを立ち上げて確認
$ aws --version;sam --version
aws-cli/2.4.5 Python/3.8.8 Linux/4.14.252-195.483.amzn2.x86_64 exe/x86_64.amzn.2 prompt/off
SAM CLI, version 1.36.0
はい、これで、現時点での最新化が完了。
Pyenvの導入とPython 3.9.9を導入
ついでに、pyenvを導入して、python を3.9.9にしておきます。
手順
$ python -V
Python 3.7.10
Pyenvの導入
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
$ ~/.pyenv/bin/pyenv --version
pyenv 2.2.2-1-gf2925393
$ vi ~/.bashrc
# PATHを通す & pythonの実行パスの差し替えられるように設定。以下に行を追加
# export PATH="$HOME/.pyenv/bin:$PATH"
# eval "$(pyenv init -)"
$ cat ~/.bashrc | grep pyenv
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
$ pyenv --version
pyenv 2.2.2-1-gf2925393
$ pyenv install -l | grep 3.9.
(省略)
3.9.9
(省略)
$ pyenv install 3.9.9
Downloading Python-3.9.9.tar.xz...
-> https://www.python.org/ftp/python/3.9.9/Python-3.9.9.tar.xz
Installing Python-3.9.9...
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
Installed Python-3.9.9 to /home/ec2-user/.pyenv/versions/3.9.9
#(警告が出ているので追加で導入)
$ sudo yum -y install bzip2
$ pyenv versions
* system (set by /home/ec2-user/.pyenv/version)
3.9.9
$ pyenv global 3.9.9
$ python -V
Python 3.7.10
Pythonのインストールは、5分くらいかかりますかね。そして、まだ、設定は反映されていません。原因は、
which python
alias python=python3
/usr/bin/python3
ですね。Alias 設定がされており、どうやら /etc/profile.d/python3_default.sh
で指定されているようなのです。
とりあえず、以下の一行を ~/.bash_profile
をに追加し変更を適用
export PATH="$HOME/.pyenv/shims:$PATH"
$ source ~/.bash_profile
$ python -V
Python 3.9.9
ということで、ここまでだいぶ長くなりましたが、環境設定ができたので、ここからようやく本題ですね。
構築するアプリケーション
シンプルにAmazon API GatewayとAWS Lambdaを連携させてみたいと思います。
SAMでLambda 関数を構築するとEvent属性にAPI Gatewayを指定することで簡単に連携ができますが、今回は個別に作りたいと思います。
SAMを利用して構築
初期化
まずは、sam init
。今回はhello-worldを指定しています。生成されるTemplateは後でごっそり書き換えます。
sam init
$ sam init --name sam-accelerate-demo --app-template hello-world --runtime python3.9 --architecture x86_64 -p Zip
SAM CLI now collects telemetry to better understand customer needs.
You can OPT OUT and disable telemetry collection by setting the
environment variable SAM_CLI_TELEMETRY=0 in your shell.
Thanks for your help!
Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html
Cloning from https://github.com/aws/aws-sam-cli-app-templates
-----------------------
Generating application:
-----------------------
Name: sam-accelerate-demo
Runtime: python3.9
Architectures: x86_64
Dependency Manager: pip
Application Template: hello-world
Output Directory: .
Next application steps can be found in the README file at ./sam-accelerate-demo/README.md
Commands you can use next
=========================
[*] Create pipeline: cd sam-accelerate-demo && sam pipeline init --bootstrap
[*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
初期化完了しました。treeコマンドで現在の環境をお見せします。ただ、その前に、treeをインストール
tree
sudo yum -y install tree
初期状態から、ダウンロードしたものも含めて色々ありますね。
その中で、 sam-accelerate-demo
ディレクトリができています。
$ tree
.
├── aws
│ ├── dist
│ ├── install
│ ├── README.md
│ └── THIRD_PARTY_LICENSES
├── awscliv2.zip
├── aws-sam-cli-linux-x86_64.zip
├── README.md
├── resize.sh
├── sam-accelerate-demo
│ ├── events
│ ├── hello_world
│ ├── __init__.py
│ ├── README.md
│ ├── template.yaml
│ └── tests
└── sam-installation
├── aws-sam-cli-src
├── dist
├── install
└── THIRD-PARTY-LICENSES
ということで、ここから最初の状態を目指して仮に作ってみます。
アプリ構築開始
- HTTP APIを定義。パス(Route/Integration)は別ファイルで定義。(OpenAPIで定義)
- API GatewayがLambdaを呼び出す際の権限をIAM Roleで指定(Lambdaのリソースベースポリシーでも設定可能)
- Lambda 関数は分散トレーシング(X-Ray)を有効化
- OutputsでAPIアクセスするためのURLを表示
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-accelerate-demo
Sample SAM Template for sam-accelerate-demo
Globals:
Function:
Timeout: 3
Tracing: Active
Resources:
HttpAPI:
DependsOn: APIIAMRole
Type: AWS::Serverless::HttpApi
Properties:
DefinitionBody:
Fn::Transform:
Name: AWS::Include
Parameters:
Location:
openapi.yaml
FailOnWarnings: true
#API Gateway Invoke Lambda Role
APIIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
-
Effect: Allow
Principal:
Service:
- apigateway.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Description: "Role for API Gateway to invoke Lambda Functions"
Policies:
- PolicyName: AllowAllActions
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: lambda:InvokeFunction
Resource: !GetAtt ProducerFunction.Arn
ProducerFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub ${AWS::StackName}-ProducerFunction
CodeUri: ProducerFunction/
Handler: app.lambda_handler
Runtime: python3.9
Architectures:
- x86_64
Outputs:
HttpApiUrl:
Description: URL of your API endpoint
Value:
Fn::Sub: 'https://${HttpAPI}.execute-api.${AWS::Region}.${AWS::URLSuffix}/'
Open API定義はこんな感じです。Any で{proxy+}で受け取る定義にしています。特に深い意味はありません。
openapi: "3.0.1"
servers:
- url: ""
x-amazon-apigateway-endpoint-configuration:
disableExecuteApiEndpoint: false
info:
title:
Fn::Sub:
${AWS::StackName}-api
version: "1.0"
components:
x-amazon-apigateway-integrations:
lambda-sample:
credentials:
Fn::GetAtt:
APIIAMRole.Arn
payloadFormatVersion: "2.0"
type : aws_proxy
connectionType: INTERNET
httpMethod : POST
uri:
Fn::Sub:
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${ProducerFunction}/invocations
paths:
/{proxy+}:
x-amazon-apigateway-any-method:
parameters:
- name: "proxy+"
in: "path"
description: "Generated path parameter for proxy+"
required: true
schema:
type: "string"
x-amazon-apigateway-integration:
$ref : "#/components/x-amazon-apigateway-integrations/lambda-sample"
ビルド・デプロイ
さて、テンプレートを書いたら、いつも使うコマンドは、sam build
これ、毎回時間がかかるんですよね。今回は関数が1つなのでよいのですが、複数あるとさらに時間がかかる。結構ストレスな彼。
今回は、sam build
に -cオプションをつけて実行してみますね。
ビルドをキャッシュで高速化
以下のコマンドで時間計測をしながらビルドをします。初回はキャッシュがない状態、その後、template.yamlを修正してキャッシュがある状態でビルドします。
time sam build --use-container -c
2回目以降の結果は以下の通りです。今回は関数が1つだけなので、大した影響はないように見えるかもしれませんが、関数が更けてくると影響が大きくなりますね。
$ time sam build --use-container -c
Starting Build use cache
Starting Build inside a container
Valid cache found, copying previously built resources from function build definition of fa140cb2-3521-449f-981a-51fb482a48d0
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
[*] Deploy: sam deploy --guided
real 0m1.138s
user 0m0.645s
sys 0m0.044s
たったの1秒で終わってます。ということで、依存関係等の変更がなければ、この**-cオプション**とても開発のストレスを軽減する優れもの。
でも、今日は、これはメインディッシュではありません。
buildコマンド
の最後に、sam sync --stack-name {stack-name} --watch
が表示(紹介)されています。これが今日の目玉なのです。
ただ、その目玉に行く前にsam sync --stack-name {stack-name}
を実行したいと思います。以下のムービーは、短縮版で作成しているため実際には、120秒程度かかっています。
作られたスタックを見てみます。
$ aws cloudformation list-stacks
{
"StackSummaries": [
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:012345678901:stack/sam-accelerate-demo-AwsSamAutoDependencyLayerNestedStack-I0U4XRI8KM5M/2d561a90-54ee-11ec-bbdb-06a7faf1c72f",
"StackName": "sam-accelerate-demo-AwsSamAutoDependencyLayerNestedStack-I0U4XRI8KM5M",
"TemplateDescription": "AWS SAM CLI Nested Stack for Auto Dependency Layer Creation",
"CreationTime": "2021-12-04T10:37:28.234000+00:00",
"StackStatus": "CREATE_COMPLETE",
"ParentId": "arn:aws:cloudformation:ap-northeast-1:012345678901:stack/sam-accelerate-demo/275eda00-54ee-11ec-ab89-0ab26497c855",
"RootId": "arn:aws:cloudformation:ap-northeast-1:012345678901:stack/sam-accelerate-demo/275eda00-54ee-11ec-ab89-0ab26497c855",
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
}
},
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:012345678901:stack/sam-accelerate-demo/275eda00-54ee-11ec-ab89-0ab26497c855",
"StackName": "sam-accelerate-demo",
"TemplateDescription": "sam-accelerate-demo\nSample SAM Template for sam-accelerate-demo\n",
"CreationTime": "2021-12-04T10:37:18.221000+00:00",
"StackStatus": "CREATE_COMPLETE",
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
}
]
}
どうやら、Lambda 関数が依存するライブラリ等をLaterで実装しているようです。この影響もあるのかもしれませんが、sam syncを最初に実行するときは、時間が長く感じます。
これは、--watch
をつけても同じです。ただ、--watch
をつけるとその後のデプロイが高速に行われ、特にLambda関数の開発がしやすくなります。
それでは、今度は、最初からsam sync
に--watch
つけてスタックを作成したいと思います。
実行後、最後に Infra sync completed.
が表示されると、そこから待機してディレクトリ内の変更を監視するようになるのです。
なお、スタック作成後にsam sync
に`--watchを実行するとローカルの環境とスタックを同期するための更新で時間が少しがかかりますが、その後は同じ動きとなります。
動画で紹介している手順はこちらです。
- sam syncを実行しスタックを作成
- スタック作成後、OutputsでHTTP APIのURLを表示
- Curlでアクセスしメッセージを受け取る。
- sam logでLambdaやAPI Gatewayのログを受け取る
- Lambdaのソースコードを修正し反映
- Curlでアクセスし更新されたメッセージを受け取る。
- Lambdaのコードの反映や、Stackが更新されていないことを確認する。
終わりに
CICDパイプラインでUnit Testをローカル実行して動作確認するのが通常のプロセスかとは思いますが、Lambdaのコード変更をローカルで行い、いち早くクラウドに反映させて動作検証する場合には非常に高速ですし、sam logもなかなか便利なツールだと思います。複数のAWSサービスのログを一元的に確認でき、自身でポーリングしてチェックする必要がないところがお気に入りポイントですね。
さて、今回は、一からCloud9を立ち上げてSAM Accelerateを試したのですが、自身の環境の問題(IAM Roleを利用してアクセスしたものの、設定をしていない)等もあり、エラーがでることや、自動検知されない変更等がありました。また別途記事にしたいと思います。