kakakakakku blog

Weekly Tech Blog: Keep Learning!

Terraform で CloudWatch Alarm「ミュートルール」を設定する

2026年4月15日にリリースされた Terraform AWS Provider v6.41.0 で Amazon CloudWatch Alarm の「ミュートルール (Mute Rules)」を管理するリソース aws_cloudwatch_alarm_mute_rule がサポートされた💡

github.com

最近までは Terraform で「ミュートルール」を設定するためには AWS Cloud Control Provider (awscc) を使う必要があった.awscc の awscc_cloudwatch_alarm_mute_rule に関しては以下の記事にまとめてある.

kakakakakku.hatenablog.com

さっそく試す \( 'ω')/

今回は「1回限り」を試す.他には「定期的なスケジュール」という設定もある🕐️

Amazon CloudWatch Alarm をデプロイする

まずは検証用の Amazon CloudWatch Alarm と Amazon SNS トピックをデプロイする.Amazon CloudWatch Alarm のメトリクスは適当に設定しておく😀

resource "aws_sns_topic" "alarms" {
  name = "sandbox-alarms"
}

resource "aws_sns_topic_subscription" "mail" {
  topic_arn = aws_sns_topic.alarms.arn
  protocol  = "email"
  endpoint  = "y.yoshida22@gmail.com"
}

resource "aws_cloudwatch_metric_alarm" "sandbox" {
  alarm_name          = "sandbox-for-mute"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  namespace           = "Sandbox"
  metric_name         = "DummyMetric"
  period              = 300
  statistic           = "Sum"
  threshold           = 1
  treat_missing_data  = "notBreaching"
  alarm_actions       = [aws_sns_topic.alarms.arn]
  ok_actions          = [aws_sns_topic.alarms.arn]
}

Amazon CloudWatch Alarm を発火させる

デプロイした Amazon CloudWatch Alarm の動作確認をするために aws cloudwatch set-alarm-state コマンドを使って一時的に ALARM に変更してアラートを発火する🔥

docs.aws.amazon.com

$ aws cloudwatch set-alarm-state \
  --alarm-name sandbox-for-mute \
  --state-value ALARM \
  --state-reason 'Testing alarm action without mute'

すると ALARM: "sandbox-for-mute" in Asia Pacific (Tokyo) というメールが届いた📩

Terraform AWS Provider でミュートルールをデプロイする

Terraform AWS Provider の aws_cloudwatch_alarm_mute_rule リソースを使ってミュートルールをデプロイする.schedule で開始時刻と期間を指定できる.今回は検証として 9:15 - 9:30 の時間帯でアラートを抑制する🕐️ 実装イメージとしては AWS Cloud Control Provider (awscc) の awscc_cloudwatch_alarm_mute_rule とほとんど同じかなという印象 \( 'ω')/

resource "aws_cloudwatch_alarm_mute_rule" "maintenance" {
  name        = "maintenance"
  description = "Maintenance schedule for mute"

  rule {
    schedule {
      expression = "at(2026-04-17T09:15)"
      duration   = "PT15M"
      timezone   = "Asia/Tokyo"
    }
  }

  mute_targets {
    alarm_names = [aws_cloudwatch_metric_alarm.sandbox.alarm_name]
  }
}

期待通りにミュートルールをデプロイできた👌

もう一度 Amazon CloudWatch Alarm を発火させる

今度は設定した時間帯でアラートを発火する🔥

$ aws cloudwatch set-alarm-state \
  --alarm-name sandbox-for-mute \
  --state-value ALARM \
  --state-reason 'Testing alarm action with mute'

すると今度はメールは届かず,マネジメントコンソールでも「アラーム状態」「ミュート時間帯」が重なるようになっていた.

ちなみに「アクション履歴」を見たら以下のようなメッセージが出ていた💡

Successfully muted the alarm action arn:aws:sns:ap-northeast-1:000000000000:sandbox-alarms with the one-time alarm mute arn:aws:cloudwatch:ap-northeast-1:000000000000:alarm-mute-rule:maintenance.

X ポスト

関連記事

kakakakakku.hatenablog.com

AWS エミュレーター「Floci」を試す

2026年3月23日から LocalStack のプラン変更があって,以下のような選択肢を検討しているチームが多いと思う.

  • LocalStack Base プラン以上を契約して使う
  • LocalStack の過去バージョンに固定して無料で使う
  • LocalStack 以外のエミュレーターに移行する
  • Vibe Coding でチームで必要なエミュレーターのみを独自実装する
  • エミュレーター依存をやめる

LocalStack 以外のエミュレーター (LocalStack alternatives) として多くのツールも登場していて,今後覇権争いになるようなフェーズに入るような気がしている🤔

その中でも特に最近注目されている(あくまで僕の個人的な観測範囲だけど)Floci を試してみようと思う💪現時点では Floci 1.5.2 が最新になる.

github.com

今回は以前に公開した「LocalStack 実践入門 | AWS アプリケーション開発ワークショップ」の内容を参考にする.

zenn.dev

セットアップ

Floci の GitHub リポジトリにある README.mddocker-compose.yml を参考に compose.yml を作った.AWS Lambda 関数を動かすために Docker ソケット /var/run/docker.sock をマウントする必要がある.デフォルトのポートは 4566 になっていて,LocalStack から移行しやすくなっていると思う👌

services:
  floci:
    image: hectorvent/floci:latest
    ports:
      - 4566:4566
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/app/data
    environment:
      FLOCI_SERVICES_DOCKER_NETWORK: floci_default
    networks:
      floci_default:
        aliases:
          - localhost.floci.cloud

networks:
  floci_default:
    name: floci_default

そして Floci を Docker Compose で起動する.

$ docker compose up -d
 ✔ Network floci_default            Created
 ✔ Container sandbox-floci-floci-1  Started

あとは README.md を参考に環境変数を設定する.アクセスキーはダミー値で OK👌

$ export AWS_ENDPOINT_URL=http://localhost:4566
$ export AWS_DEFAULT_REGION=ap-northeast-1
$ export AWS_ACCESS_KEY_ID=DUMMY
$ export AWS_SECRET_ACCESS_KEY=DUMMY

1. Amazon SQS + Amazon S3 + Python (boto3)

以下のように Python (boto3) スクリプトで Amazon SQS キューから取得したメッセージを使って Amazon S3 バケットにオブジェクトを作るアーキテクチャを Floci で試す.

まずは AWS CLI で Floci に Amazon SQS キューと Amazon S3 バケットを作成する.

$ aws sqs create-queue --queue-name sandbox-queue
{
    "QueueUrl": "http://localhost:4566/000000000000/sandbox-queue"
}

$ aws s3api create-bucket --bucket sandbox-bucket --create-bucket-configuration LocationConstraint=ap-northeast-1
{
    "Location": "/sandbox-bucket"
}

そして Amazon SQS キューにメッセージを2つ送信する.

$ aws sqs send-message \
    --queue-url http://localhost:4566/000000000000/sandbox-queue \
    --message-body '{ "id": "id0001", "body": "This is message 0001." }'
{
    "MD5OfMessageBody": "724a181067bbde5b905d391a475a82ec",
    "MessageId": "1e8b2701-cba0-4bf8-b24f-6098213fa0ff"
}

$ aws sqs send-message \
    --queue-url http://localhost:4566/000000000000/sandbox-queue \
    --message-body '{ "id": "id0002", "body": "This is message 0002." }'
{
    "MD5OfMessageBody": "b796b47a6c737f200e34c2676dc40a2a",
    "MessageId": "1b717759-578a-4405-b436-2dfd3dca6565"
}

今回実行する app.py はこんな感じ❗️

import json

import boto3

sqs = boto3.client("sqs", endpoint_url="http://localhost:4566")

queue_url = "http://localhost:4566/000000000000/sandbox-queue"

response = sqs.receive_message(
    QueueUrl=queue_url,
    MaxNumberOfMessages=10,
)

s3 = boto3.client("s3", endpoint_url="http://localhost:4566")

for message in response.get("Messages", []):
    body = json.loads(message["Body"])
    s3.put_object(
        Bucket="sandbox-bucket",
        Key=f"{body['id']}.json",
        Body=message["Body"],
    )
    sqs.delete_message(
        QueueUrl=queue_url,
        ReceiptHandle=message["ReceiptHandle"],
    )

最後に app.py を実行すると,期待通りに Amazon S3 バケットにオブジェクトが作られていた👌

$ uv run app.py

$ aws s3api list-objects --bucket sandbox-bucket
{
    "Contents": [
        {
            "Key": "id0001.json",
            "LastModified": "2026-04-11T08:30:24+00:00",
            "ETag": "\"724a181067bbde5b905d391a475a82ec\"",
            "Size": 51,
            "StorageClass": "STANDARD"
        },
        {
            "Key": "id0002.json",
            "LastModified": "2026-04-11T08:30:24+00:00",
            "ETag": "\"b796b47a6c737f200e34c2676dc40a2a\"",
            "Size": 51,
            "StorageClass": "STANDARD"
        }
    ],
    "RequestCharged": null,
    "Prefix": ""
}

2. AWS CloudFormation

Floci は AWS CloudFormation もサポートしている.次は AWS CloudFormation で Amazon SQS キューと Amazon S3 バケットをデプロイする.

template.yaml は以下のような感じ.

AWSTemplateFormatVersion: '2010-09-09'

Resources:
  Queue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: sandbox-cfn-queue
      ReceiveMessageWaitTimeSeconds: 20
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: sandbox-cfn-bucket

まず aws cloudformation deploy コマンドを実行するとエラーになってしまった.aws cloudformation deploy コマンドは内部的に Chage Set を使っていて,Floci のドキュメントを読むと AWS CloudFormation の Change Set をサポートしていると記載されているけど,完全にサポートできていない可能性がありそう🙅‍♂️

$ aws cloudformation deploy \
    --stack-name 02-cfn \
    --template-file template.yaml
Waiting for changeset to be created..

aws: [ERROR]: 'Status'

代わりに aws cloudformation create-stack コマンドを実行すると問題なくデプロイできた.

$ aws cloudformation create-stack \
    --stack-name 02-cfn \
    --template-body file://template.yaml
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/02-cfn/19d6508f-e771-4d0c-95ea-9805d70a738e"
}

aws cloudformation describe-stacks コマンドを実行すると AWS CloudFormation スタックを確認できた.

$ aws cloudformation describe-stacks --stack-name 02-cfn
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/02-cfn/19d6508f-e771-4d0c-95ea-9805d70a738e",
            "StackName": "02-cfn",
            "CreationTime": "2026-04-11T08:31:26.265839+00:00",
            "LastUpdatedTime": "2026-04-11T08:33:06.673563+00:00",
            "StackStatus": "CREATE_COMPLETE",
            "Capabilities": [],
            "Outputs": [],
            "Tags": []
        }
    ]
}

Amazon SQS キューと Amazon S3 バケットも期待通りにデプロイされていた👌

$ aws sqs get-queue-url --queue-name sandbox-cfn-queue
{
    "QueueUrl": "http://localhost:4566/000000000000/sandbox-cfn-queue"
}

$ aws s3api head-bucket --bucket sandbox-cfn-bucket
{
    "BucketRegion": "ap-northeast-1"
}

3. AWS SAM

AWS CloudFormation がサポートされているなら AWS SAM も使えるかも!? と思って試してみた.AWS SAM で Amazon SQS キュー・AWS Lambda 関数・Amazon S3 バケットを連携するアーキテクチャを試す.

template.yaml は以下のような感じ.

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  Queue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: sandbox-sam-queue
      ReceiveMessageWaitTimeSeconds: 20
  Function:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: sandbox-sam-function
      CodeUri: ./src
      Handler: app.lambda_handler
      Runtime: python3.13
      Architectures:
        - x86_64
      Events:
        SqsEvent:
          Type: SQS
          Properties:
            Queue: !GetAtt Queue.Arn
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: sandbox-sam-bucket

AWS SAM CLI でデプロイしようと思ったけど ChangeSetNotFoundException というエラーが出てしまった🚨あくまで推測だけど,先ほどと同じく AWS CloudFormation の Change Set まわりのサポートが不足している可能性がありそう.

$ sam build
$ sam deploy --guided
(中略)
Error: Waiter ChangeSetCreateComplete failed: An error occurred (ChangeSetNotFoundException): ChangeSet [arn:aws:cloudformation:ap-northeast-1:000000000000:changeSet/samcli-deploy1775896655/037e073d-7741-4b12-bc47-255ca867a82f] does not exist

4. AWS Lambda

AWS SAM は使えなかったため,最後は AWS Lambda 関数を単体でデプロイする.

まずは以下のようなシンプルな app.py を実装する.

import json


def lambda_handler(event, context):
    for record in event['Records']:
        print(record)
        body = json.loads(record['body'])
        print(f"id: {body['id']}, body: {body['body']}")
    return {"statusCode": 200}

そして aws lambda create-function コマンドで ZIP ファイルをアップロードして AWS Lambda 関数をデプロイする.

$ zip function.zip app.py

$ aws lambda create-function \
    --function-name sandbox-lambda-function \
    --runtime python3.13 \
    --handler app.lambda_handler \
    --role arn:aws:iam::000000000000:role/dummy \
    --timeout 30 \
    --zip-file fileb://function.zip
{
    "FunctionName": "sandbox-lambda-function",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:000000000000:function:sandbox-lambda-function",
    "Runtime": "python3.13",
    "Role": "arn:aws:iam::000000000000:role/dummy",
    "Handler": "app.lambda_handler",
    "CodeSize": 320,
    "Timeout": 30,
    "MemorySize": 128,
    "LastModified": "1775897052317",
    "Version": "$LATEST",
    "RevisionId": "ce9c7f4f-7650-4378-ad75-89481bbc7af3",
    "State": "Active",
    "PackageType": "Zip"
}

aws lambda invoke コマンドで AWS Lambda 関数を実行すると成功した❗️

$ aws lambda invoke \
    --function-name sandbox-lambda-function \
    --cli-binary-format raw-in-base64-out \
    --payload '{ "Records": [{ "body": "{ \"id\": \"id0003\", \"body\": \"This is message 0003.\" }" }] }' \
    /dev/stdout
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

aws logs filter-log-events コマンドで Amazon CloudWatch Logs を確認するとちゃんとログが出力されていた👌

$ aws logs filter-log-events --log-group-name /aws/lambda/sandbox-lambda-function
{
    "events": [
        {
            "timestamp": 1775897074549,
            "message": "{'body': '{ \"id\": \"id0003\", \"body\": \"This is message 0003.\" }'}",
            "ingestionTime": 1775897074549,
            "eventId": "bdd2d9bc-22c1-4b44-b9a4-51d5c045235e"
        },
        {
            "timestamp": 1775897074549,
            "message": "id: id0003, body: This is message 0003.",
            "ingestionTime": 1775897074549,
            "eventId": "c18ae150-26d8-4ce5-a556-fff9b43b01c7"
        }
    ]
}

まとめ

LocalStack 以外のエミュレーター (LocalStack alternatives) として最近よく聞く Floci を試してみた.まだまだ発展途上でリリース頻度も高いけど,現時点の Floci 1.5.2 でも十分 LocalStack の代替として選択肢に入ると思う.特に LocalStack では無料で使えなかった Amazon Cognito や Amazon ECS が Floci ではサポートされているし,free forever というポリシーに惹かれる人も多いと思う.さらに起動時間が速いのも実体験として嬉しいポイントだと感じた👌

今後も Floci のアップデートを追いかけていこうと思う❗️

Terraform で Athena の「パラメータ化されたクエリ」を「保存したクエリ」に登録する

Amazon Athena にはよく使うクエリを保存できる「保存したクエリ (saved queries)」という機能がある.

たとえば「WHERE でパーティションを指定する」「タイムスタンプを JST に変換する」など,プロジェクトで標準的なクエリを共有できるメリットがある👌

docs.aws.amazon.com

さらに Amazon Athena にはクエリの一部を実行時に入力できる「パラメータ化されたクエリ (parameterized queries)」という機能もある.たとえば「日付部分」? にしておくなど.

docs.aws.amazon.com

Terraform だと aws_athena_named_query リソースを使って保存したクエリ (saved queries) をデプロイできる.

aws_athena_workgroupaws_glue_catalog_database は必須になっていて,Terraform で作るのも良し!既存リソースを data source で参照するのも良し👌

今回は検証環境として ALB アクセスログを Amazon Athena でクエリするテーブルを作ってある.

docs.aws.amazon.com

resource "aws_athena_workgroup" "sandbox" {
  name = "sandbox"

  configuration {
    managed_query_results_configuration {
      enabled = true
    }
  }
}

resource "aws_glue_catalog_database" "default" {
  name = "default"
}

resource "aws_athena_named_query" "access_log_by_time_range" {
  name      = "alb-access-log-by-time-range"
  workgroup = aws_athena_workgroup.sandbox.name
  database  = aws_glue_catalog_database.default.name
  query     = <<-EOT
    SELECT
        at_timezone(parse_datetime(time, 'yyyy-MM-dd''T''HH:mm:ss.SSSSSS''Z'), 'Asia/Tokyo') AS time,
        request_verb,
        request_url,
        elb_status_code
    FROM sandbox_access_logs
    WHERE
        day = ? -- '2026/03/27' のようにシングルクォートを付けるのを忘れずに!
        AND parse_datetime(time, 'yyyy-MM-dd''T''HH:mm:ss.SSSSSS''Z')
            BETWEEN CAST(? || ' Asia/Tokyo' AS timestamp WITH TIME ZONE) -- '2026-03-27 12:00:00' のように YYYY-MM-DD HH:mm:ss 形式で入力すること!
                AND CAST(? || ' Asia/Tokyo' AS timestamp WITH TIME ZONE) -- '2026-03-27 15:00:00' のように YYYY-MM-DD HH:mm:ss 形式で入力すること!
  EOT
}

デプロイしてクエリを実行すると「パラメータ1」「パラメータ2」「パラメータ3」を入力できるようになった👌

関連記事

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

Terraform でマネジメントコンソールのアカウントカラーを設定する

2026年4月1日にリリースされた Terraform AWS Provider v6.39.0「AWS User Experience Customization (UXC)」を管理するリソース aws_uxc_account_customizations がサポートされた💡

ということは Terraform で「アカウントカラー」を管理できるぞー \( 'ω')/

github.com

「アカウントカラー」を設定しようと思ったら,最近まではマネジメントコンソールで設定する必要があって,2026年3月25日頃から AWS CloudFormation でも管理できるようになった.詳しくはブログにまとめてある.同じタイミングで AWS SDK for Go v2 でも AWS User Experience Customization (UXC) がサポートされて Terraform AWS Provider でも使えるようになったという背景がある.

kakakakakku.hatenablog.com

👾 uxc.tf

実装は簡単❗️今回は yellow にした.

resource "aws_uxc_account_customizations" "main" {
  account_color = "yellow"
}

デプロイ確認

イイ感じ❗️

2026年(1-3月)のプルリクエストを振り返る

2016年から毎年送ったプルリクエストを振り返る記事を書いている📅

2026年(1-3月)は「計12件」だった❗️

プルリクエストを振り返るための検索

プルリクエストを振り返るために GitHub の検索条件を使う.

今回は「2026年(1-3月)」に限定するため created:2026-01-01..2026-03-31 とする.

is:pr is:public author:kakakakakku -user:kakakakakku created:2026-01-01..2026-03-31

2026/01

aws-samples/serverless-patterns

2025年から Serverless Land にある AWS Serverless Patterns Collection にコントリビュート(パターンのメンテナンス)するという活動をしていて,コツコツとプルリクエストを送った.GitHub リポジトリの Contributors で気付いたら9番目になっていた😀

github.com github.com github.com github.com github.com github.com github.com

2026/02

aws-samples/serverless-patterns

github.com github.com

terraform-linters/tflint-ruleset-aws

普段よく使ってる TFLint Ruleset for terraform-provider-aws にあるルールを改めて見直してるときに README に更新漏れを見つけて修正した.

github.com

2026/03

Redocly/website

Redocly Respect を試してるときにドキュメントのコマンドが間違っていることに気付いて修正した.

github.com

awslabs/mcp

Amazon Aurora Postgres MCP Server を試してるときに Amazon RDS Data API と組み合わせるとエラーが出てしまってコードを読みながら修正した.

github.com

過去の振り返り記事