AWSコスト、見直していますか? 第2弾 〜夜は止めよう!自動停止・起動でムダな出費にサヨウナラ〜
こんにちは。株式会社ペライチのインフラエンジニア西野です。
先日、弊社テックブログで
AWS コスト、見直していますか? 〜ムダな出費を抑える 3 つの視点〜を公開しました。
今回はその第 2 弾として、**弊社でも実践している「休日・夜間の ECS・RDS 自動停止・起動」**によるコスト最適化について紹介します。
この記事は、AWS の基本操作に慣れ、 ECS や RDS を少し触ったことがある方向けです。
「本番環境は常に稼働させる必要があるけれど、検証環境や一部の業務系リソースは本当に 24 時間動いている必要があるのか?」
そう考えたことがある方は、ご覧いただければ幸いです。
🗂️ 目次
- なぜ夜間や休日にとめるのか?
- 構成概要
- IAM ロールの作成
- Lambda で ECS サービスを停止・起動
- Lambda で RDS クラスタを停止・起動
- EventBridge でスケジュール設定
- 注意点・補足
- まとめ
- 最後に
1. なぜ夜間や休日にとめるのか?
開発・検証環境は、平日の日中のみ使用されることが多いです。
常に稼働していると、使われていない時間帯にもインスタンスや DB に対するコストが
発生します。
特に Aurora などの RDS や、Fargate ベースの ECS は時間課金のためムダなコストが積み重なります。そこで「使わない時間帯はとめる」ことで、コスト削減につなげていきます。
2. 構成概要
最初に構成の説明をしていきます。
構成自体はいたってシンプルです。EventBridge でスケジュール管理、Lambda か各サービスの API に対して処理を実行します。
- EventBridge スケジューラー
曜日・時間ベースで停止・起動をスケジュール
https://aws.amazon.com/jp/eventbridge/scheduler/ - Lambda
RDS の停止/起動
ECS サービスの desiredCount 更新(停止 =0/起動 =1)
https://aws.amazon.com/jp/lambda/
- 一連の流れ
- EventBridge が定時に Lambda を起動
- Lambda が ECS と RDS に対して停止・起動処理を実行
3. IAMロールの作成
まず最初に ECS や RDS、CloudWatchLogs の操作に許可を与えた IAM ロールを作成します。
最低限必要な権限は以下の通りです。
各操作毎のロール若しくは、サービス毎にロールを作成します。
※ Resource などは必要に応じて適切な権限を付与してください。
ECS
| アクション | 説明 |
|---|---|
| ecs:UpdateService | desiredCount の変更(= 停止・起動)に必須 |
| ecs:DescribeServices | 状態確認などに必要(任意) |
RDS
| アクション | 説明 |
|---|---|
| rds:StartDBCluster | Auroraクラスタを起動 |
| rds:StopDBCluster | Auroraクラスタを停止 |
| rds:DescribeDBClusters | 起動後の状態確認やログ出力用(任意) |
CloudWatchLogs
| アクション | 説明 |
|---|---|
| logs:CreateLogGroup | 指定された名前のロググループを作成します。 |
| logs:CreateLogStream | ロググループの中に、ログストリーム(時間単位のログの束)を作成 |
| logs:PutLogEvents | 作成されたログストリームに対して、実際のログイベントを送信 |
例)Resource_Auto_Start_Stop_Role。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rds:StartDBCluster",
"rds:StopDBCluster",
"rds:DescribeDBClusters"
],
"Resource": [
"arn:aws:rds:ap-northeast-1:123456789012:cluster:dev-*"
]
},
{
"Effect": "Allow",
"Action": [
"ecs:UpdateService",
"ecs:DescribeServices"
],
"Resource": [
"arn:aws:ecs:ap-northeast-1:123456789012:service/dev-*/dev-*",
"arn:aws:ecs:ap-northeast-1:123456789012:cluster/dev-*"
]
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/lambda/dev-*:*"
]
}
]
}
4. LambdaでECS サービスを停止・起動
続いて、Lambda を使って ECS サービスの停止・起動をする処理を作成していきます。
今回は Python 3.12 を使用しています。
ここでは作成手順の詳細は割愛し、コードベースで処理の流れを中心に解説していきます。
以下の Boto3 ドキュメントも併せて参照ください。
import boto3
from botocore.exceptions import ClientError
def lambda_handler(event, context):
client = boto3.client('ecs')
# 操作対象のECSクラスター名とサービス名
services = [
('hoge-cluster', 'hoge-service')
]
for cluster_name, service_name in services:
try:
# desiredCount=0 で停止、1以上で起動
desired_count = 1
client.update_service(
cluster=cluster_name,
service=service_name,
desiredCount=desired_count
)
# 成功時は最小限のログ
print(f"{service_name} を desiredCount={desired_count} に更新しました")
except ClientError as e:
# 具体的なエラーだけ出す(機密情報は含まれない)
print(f"ClientError on {service_name}: {e.response['Error']['Message']}")
except Exception as e:
# 想定外エラーも簡潔に
print(f"Unexpected Error on {service_name}: {str(e)}")
return 'Done'
Point
| アクション | 説明 |
|---|---|
| boto3.client('ecs') | ECS操作用のクライアントを作成 |
| services = [(cluster名,service名)] | ターゲットとなるClusterとサービス名 |
| desiredCount | 起動するタスク数を指定します。1 以上 → サービス起動、0 → サービス停止 |
5.Lambda でRDSクラスタを停止・起動
次に、Lambda を使って Aurora RDS クラスタの停止・起動 を行う処理を作成していきます。
このコードは Aurora RDS を前提とした構成になっており、先ほどの ECS 編と同様に Python 3.12 を使用しています。
以下の Boto3 ドキュメントも併せて参照ください。
import boto3
from botocore.exceptions import ClientError
def lambda_handler(event, context):
rds_client = boto3.client('rds')
# 操作対象のAurora DBクラスタ名
db_clusters = ['hoge-aurora-cluster']
# 操作種別: "start" または "stop"
operation = "start"
for db_cluster in db_clusters:
try:
if operation == "start":
rds_client.start_db_cluster(DBClusterIdentifier=db_cluster)
print(f"[INFO] {db_cluster} を起動しました")
else:
rds_client.stop_db_cluster(DBClusterIdentifier=db_cluster)
print(f"[INFO] {db_cluster} を停止しました")
except ClientError as e:
# 例: すでに起動済み/停止済みの場合
print(f"[WARN] {db_cluster}: {e.response['Error']['Message']}")
except Exception as e:
# 想定外のエラー
print(f"[ERROR] {db_cluster}: {str(e)}")
return {"status": "done", "operation": operation}
Point
| アクション | 説明 |
|---|---|
| boto3.client('rds') | RDS操作用のクライアントを作成 |
| db_clusters = ['hoge-aurora-cluster'] | ターゲットとなるAurora Cluster名 |
| rds_client.start_db_cluster | Clusterを起動 |
| rds_client.stop_db_cluster | Clusterを停止 |
6. EventBridgeでスケジュール設定
Lambda 関数を自動実行するために、EventBridge ルールを使ってスケジュールを設定します。
ここでは「平日の朝 7 時(JST)に起動処理を実行し、夜 22 時(JST)に停止処理を実行する」例を示します。
EventBridge の cron 式は UTC 基準で記述する必要があります。
そのため、JST の時間を −9 時間して UTC に変換します。
cron式の書き方
| JST (日本時間) | UTC (世界標準時) | cron式例 | 説明 |
|---|---|---|---|
| 07:00 JST(平日朝) | 22:00 (前日 UTC) | cron(0 22 ? * Sun-THU *) | 毎週月曜〜金曜の朝7時(JST)に実行 |
| 22:00 JST(平日夜) | 13:00 (同日 UTC) | cron(0 13 ? * MON-FRI *) | 毎週月曜〜金曜の夜10時(JST)に実行 |
ルールの作成時のポイント
- ターゲットに先ほど作成した Lambda 関数を指定する
-
IAMロールは EventBridge から Lambda を実行する権限が必要になります。
自動で新規作成もしてくれるので、それを利用する形でも問題ないです。
7. 注意点・補足
- Aurora RDS は停止後 7 日で自動起動されます(停止のしっぱなしは不可)
- ECS Fargate は、サービスの desiredCount=0 でもタスク定義は保持されるため、再起動もスムーズです。
- 起動時にクラスタやサービスの状態確認を加えるとより堅牢です。
- Terraform でこのしくみを構築できれば、より IaC に準拠しますが、まずはマネジメントコンソールで簡単に試すのもお勧めです。
8. まとめ
-
開発や検証環境において、夜間・休日に使わないリソースを自動停止することで、環境規模に応じて数千円〜数万円のコスト削減が可能です。
例: t4g.medium の RDS インスタンスを 9 時間/日 × 22 日/月停止した場合、月あたり約 1,500 〜 2,000 円前後の削減が期待できます(AWS 料金はリージョンや契約プランにより異なります)。 -
本記事では、Lambda + EventBridge による RDS と ECS の自動制御の構成とコードを紹介しました。
9. 最後に
今回は、AWS リソースの自動停止・起動を実現する構成と、その実装コードについて紹介しました。
第 3 弾では、「とめるもの・とめないものを自動で見極める」「複数リソースを効率よく制御する」など、より柔軟で実践的なリソース管理のテクニックを取り上げる予定です。
最後までお読みいただき、ありがとうございました!
Discussion