- 1. 概要
- 目的
- Serverless Framework (sls)
- Lambda Function
- EventBridge Rule (旧 CloudWatch Events Rule)
- リソース一覧
- 命名規則
- 公式URL
- 2. 解説手順
- 3. Serverless Frameworkで使うファイル
- ディレクトリ構成
- handler.py
- serverless.yml
- 4. serverlessコマンドのまとめ
- 5. 宿題
Serververless Frameworkで作るLambda Function・EventBridge (旧 CloudWatch Events) について学んでいきましょう!
1. 概要
目的
RDSは定期的なメンテナンスのため、停止して7日後に自動的に起動します。なるべく課金を避けるため、毎日深夜03:15と03:30にDBクラスターを自動停止させてみましょう。もし停止したタイミングが昼間だと7日後の昼間に自動起動してしまうので、毎週日曜のみ深夜03:00にDBクラスターの自動起動も追加しておきましょう。
同時に、現場でも良く使われているServerless FrameworkやLambda Functionによってサーバーレスの仕組みを体感して頂けます。
実は【SSM・Lambda不要】Amazon EventBridge SchedulerでAuroraの自動停止を実装してみた | DevelopersIOを使うともっと簡単に実装できますが、今回はLambda Functionを体験いただくということで、ご参考まで。
Serverless Framework (sls)
「サーバーレス」の仕組みを簡単に作成できる、オープンソースのフレームワークです。AWS Lambdaだけでなく、Azure Functions、Google Cloud Functionsにも対応しています。サーバーレス(=EC2などのサーバーが不要)で、コードを書くだけで実行できるLambda関数を作成できます。ついでにIAM Role、API Gateway、DynamoDB、EventBridge (旧 CloudWatch Events)など関連するリソースも一緒に作成できます。
ちなみにCFnでもLambda関数を作れますが、Serverless Frameworkの方が断然便利です。
Lambda Function
Lambda=ラムダと読みます。つまり日本語にするとLambda Function=ラムダ関数ですね。
AWSにおける「サーバレス」のサービスの代表格であり、EC2などのサーバー不要で簡単なコード(プログラム)を実行できます。Python, Ruby, Node.jsなど Lambda ランタイム - AWS Lambda に書かれた言語に対応しています。100行程度の簡単なコードを1つ実行するイメージですね。そのようなコードをインフラの世界では「スクリプト」と呼んだりもします。
API Gateway, S3, DynamoDBなどとの相性はいいですが、RDSとの相性は悪いです(RDS Proxyの登場によって多少緩和されましたが)
Webサービスの本体をLambda関数で作ることは基本ないですが、そのサポート(バッチ実行のキックなど)をしたり、AWSのリソースを定期的に操作したり、IoTの機器で使われたり、応用範囲は幅広いです。実行された時間のみ課金されるサーバレスなので、ランニングコストを極限まで下げてコードを実行できます。
EventBridge Rule (旧 CloudWatch Events Rule)
イベントルールを作成することで、イベントが発生(=設定したトリガーが発動)すると、ターゲット(=AWS上の処理)を複数実行できます。
例えばCron式で曜日や日時を指定すれば、定期的なトリガーになります。EC2インスタンスの状態変化やS3バケットのファイル操作などの不定期なイベントをトリガーにもできます。
- AWS サービスからのイベント - Amazon EventBridge
- サポートされている各サービスからの CloudWatch イベント イベントの例 - Amazon CloudWatch Events
も参考まで。
実行できる処理も多岐に渡ります。Lambda関数を実行したり、EC2インスタンスを起動/停止したり、AWS Batchでバッチをキックしたり、様々な使い方ができます。
リソース一覧
Serverless Frameworkでデプロイすると裏側ではCFn Stackを作成し、必要なリソースを自動的に作成してくれます。下記は serverless.yml
で明示したリソースだけで、実際は他にもS3 Bucket, CloudWatch LogGroupなど多数のリソースが作成されます。
リソース | 目的 | 備考 |
---|---|---|
IAM: Role | Lambdaへ権限付与するためのIAM「ロール」 | InlinePolicyを使ったロールが作成される。Lambda関数で必要な権限の中身だけを |
Lambda: Function | Python, Ruby, Node.jsなどのコードだけを実行することができるLambda「関数」 |
|
Events: Rule | イベントでトリガーして何かの操作を実行できる EventBridge (旧 CloudWatch Event)「ルール」 | DBクラスター停止の方は |
命名規則
Serverlessならではの命名規則として、CFnスタック名がデフォルトで サービス名-ステージ名
になります。従って今回の場合は awsmaster-sls-stop-rds-prod
となります。
それ以外Lambda関数名やEventBridge (旧 CloudWatch Events) ルール名など明示しない場合は自動的に命名されます。
公式URL
Serverless Framework
- Top: The Serverless Application Framework | Serverless.com
- Docs: Serverless Framework Documentation
- Examples (AWSに✅ ): Serverless Examples Directory (90+ Examples w/ Filters)
2. 解説手順
流れとして、Serverless Frameworkをインストールし、Lambda Functionをデプロイします。そのLambda Functionを試しに実行してみます。
- Serverless Frameworkのインストール(Mac or EC2=Windowsの場合)
(Macの場合 →)
brew install serverless
※インストールコマンド (↓ EC2にSession Managerで接続の場合)bash
cd
curl -o- -k -L https://slss.io/install | bash
※インストールコマンドexit
bash
cd
- Serverless Frameworkの初期設定
cd
※Projectディレクトリを作ります。他にお好きな場所があれば、そちらに移動してくださいserverless
What do you want to make?
(↓ キーで) AWS - Python - Scheduled Task を選択What do you want to call this project?
awsmaster-sls-stop-rds を入力Do you want to login/register to Serverless Dashboard? (Y/n)
n を入力 (Serverless Frameworkの公式サイトにログインして表示させたい場合は Y でもOK) (↓ EC2でAWSアクセスキーを未登録の場合)No AWS credentials found, what credentials do you want to use?
Local AWS Access Keys を入力Do you have an AWS account? (Y/n)
Y を入力 (↓ ブラウザが勝手に開くが、無視して)Press Enter to continue after creating an AWS user with access keys
EnterAWS Access Key Id:
IAMユーザーのアクセスキーを入力AWS Secret Access Key:
IAMユーザーのシークレットアクセスキーを入力Do you want to deploy now? (Y/n)
n を入力 (Y を入力するとヴァージニア北部リージョン(us-east-1)にデプロイされるので注意) - Serverless FrameworkのProjectディレクトリ作成
(↓Serverless Frameworkの初期設定時にProjectディレクトリを作らなかった場合のみ)
cd
※この下にProjectディレクトリを作ります。他にお好きな場所があれば、そちらに移動してくださいmkdir awsmaster-sls-stop-rds
cd awsmaster-sls-stop-rds
serverless create -t aws-python3 -n awsmaster-sls-stop-rds
※2つ目以降のProjectは毎回このコマンド - Serverless Frameworkのデプロイ準備
cd awsmaster-sls-stop-rds
※Projectディレクトリのパスが違う場合は読み替えてください 後述の通りhandler.py
とserverless.yml
を上書きしてくださいserverless print
※エラーが表示されないことを確認 - Serverless Frameworkのデプロイ
serverless deploy
※コードを変更した後に更新する場合も同じコマンド - CFnの画面で
awsmaster-sls-stop-rds-prod
という名前のStackが作られたことを確認 ResourcesタブからリンクをたどってLambda Function, IAM Role, EventBridge (旧 CloudWatch Events) Rule, CloudWatch Logs LogGroup などが作られたことを確認する - Lambda Functionを試しに実行
serverless invoke --function stop-db-cluster --log
(↓ のように表示されたら成功)null
-----------------------------------------------------------------—
START
2021-04-18 22:56:42.460 [INFO] Found credentials in environment variables.
awsmaster-prod-rds: available
※現在のDBクラスターの状態を表示。available
だと稼働中{'DBCluster': {'AllocatedStorage': 1,
※停止しようとした場合は表示される。以下割愛END RequestId: 8e03edb2-8915-49ef-af90-3d965c9a15ab
END Duration: 1606.13 ms (init: 308.44 ms) Memory Used: 64 MB
※1.6秒で動作終了。課金対象も同様 - Lambda Functionを再度実行
serverless invoke --function stop-db-cluster --log
(↓ のように表示されたら成功。一部のみ抜粋)awsmaster-prod-rds: stopping
※現在のDBクラスターの状態を表示。stopping
だと停止中。stopped
だと停止済。 - CloudWatch Logs LogGroupのログ確認
/aws/lambda/awsmaster-sls-stop-rds-prod-start-db-cluster
と/aws/lambda/awsmaster-sls-stop-rds-prod-stop-db-cluster
を開いてみると実行ログが都度出力されているのを確認できる - (もし余裕があれば) 後日、上記のログを確認 ログから日曜日03:00にDBクラスターの起動、毎日03:15と03:30にDBクラスターの停止が実行されたことを確認する
- (もし将来不要になったら) Lambda Functionなど全部削除
serverless remove
3. Serverless Frameworkで使うファイル
ディレクトリ構成
~/awsmaster-sls-stop-rds/ 配下(パスはどこでもOK)
.gitignore -> Gitリポジトリにアップロードしたくないファイルを明示
handler.py -> Lambda関数で動かしたいコード(今回はPythonで書いてある)
serverless.yml -> Serverless Frameworkで作るリソースなどの設計・設定
handler.py
import boto3
import logging
# import os
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# DB_CLUSTER_IDENTIFIER = os.environ['DB_CLUSTER_IDENTIFIER']
client = boto3.client('rds')
response = client.describe_db_clusters() # client.describe_db_clusters(DBClusterIdentifier = DB_CLUSTER_IDENTIFIER)
def start_db_cluster(event, context):
for DBCluster in response['DBClusters']:
print(DBCluster['DBClusterIdentifier'] + ': ' + DBCluster['Status'])
if DBCluster['Status'] == "stopped":
print(str(client.start_db_cluster(DBClusterIdentifier = DBCluster['DBClusterIdentifier'])))
def stop_db_cluster(event, context):
for DBCluster in response['DBClusters']:
print(DBCluster['DBClusterIdentifier'] + ': ' + DBCluster['Status'])
if DBCluster['Status'] == "available":
print(str(client.stop_db_cluster(DBClusterIdentifier = DBCluster['DBClusterIdentifier'])))
serverless.yml
serverless --version
の結果が Framework Core: 3.*.*
の場合
---
service: awsmaster-sls-stop-rds
frameworkVersion: '3'
provider:
name: aws
runtime: python3.11
stage: prod
region: ${opt:region, 'ap-northeast-1'}
deploymentBucket:
blockPublicAccess: true
memorySize: 128
logRetentionInDays: 14
iam:
role:
statements:
- Effect: Allow
Action:
- rds:DescribeDBClusters
- rds:StartDBCluster
- rds:StopDBCluster
Resource: '*'
functions:
start-db-cluster:
handler: handler.start_db_cluster
# environment:
# DB_CLUSTER_IDENTIFIER: awsmaster-prod-rds
events:
- schedule:
description: Start all DB Clusters at 03:00(JST) on Sunday.
rate: 'cron(0 18 ? * 7 *)'
stop-db-cluster:
handler: handler.stop_db_cluster
# environment:
# DB_CLUSTER_IDENTIFIER: awsmaster-prod-rds
events:
- schedule:
description: Stop all DB Clusters at 03:15,30(JST).
rate: 'cron(15,30 18 * * ? *)'
【変更履歴】
- 2022-05-03:最新のServerless Framework Version 3に対応したテンプレートを追加
- 2024-01-20:実行タイミングを03:00〜03:45から02:00〜04:45に変更
- 2024-05-23:DBクラスターの自動起動を追加し、自動停止のタイミングを変更
4. serverlessコマンドのまとめ
- Serverless FrameworkのProjectディレクトリ作成
serverless create -t aws-python3 -n [ProjectName]
cd [ProjectName]
↓以下 2.以降はProjectディレクトリ内で実行すること - Serverless Frameworkでデプロイされるものの確認
serverless print
- Serverless Frameworkのデプロイ(新規作成 or 更新)
serverless deploy
- Serverless Frameworkでデプロイされたものの確認
serverless info
- Lambda Functionを試しに実行してみる
serverless invoke --function [FunctionName] --log
- Lambda Functionなど全部削除
serverless remove
5. 宿題
宿題は特にありません。
下記の内容は応用課題です。挑戦してみると勉強になると思います。
- Lambaの料金体系を調べてみてください。1ヶ月30日、毎日2回ずつ(合計60回)メモリ128MBの関数を1512ミリ秒動かしたらいくらになるでしょう?
handler.py
とserverless.yml
の両方にある#
のコメントを外して修正すると、特定のDBクラスターのみ停止させることもできます。試してみてください- Serverlessのサンプルを見ながら他にもサーバレスアプリケーションを作ってみると、勉強になると思います。特にAPI Gatewayまで作れるとカッコイイですね。 → Examples (awsに✅ ): Serverless Examples Directory (90+ Examples w/ Filters)
以上、お疲れさまでした!