Azure Container Apps Job で sys.dm_database_backups の最新履歴を定期確認し、想定期間内にバックアップ履歴がない場合に Slack Incoming Webhook へ通知する監視ツールです。コンテナは Node.js 24 系で動作する前提です。
Azure SQL Database の自動バックアップは、成功したバックアップ履歴として DMV に現れます。このツールは「最新の Full / Differential / Transaction log バックアップが設定した猶予時間内に存在するか」で失敗や遅延を検知します。DMV のクエリ自体が失敗した場合もアラート扱いです。
既定値は Azure SQL Database の標準バックアップ頻度に余裕を持たせています。
| 種別 | DMV 値 | 既定の許容期間 |
|---|---|---|
| Full | D |
8 日 |
| Differential | I |
30 時間 |
| Transaction log | L |
60 分 |
BACKUP_CHECK_WINDOWS で変更できます。
BACKUP_CHECK_WINDOWS=D=11520,I=1800,L=60src/backupMonitor.js は CLI entry point と互換 export だけを持ち、実装は責務ごとに分割しています。
| ファイル | 責務 |
|---|---|
config.js |
環境変数の読み込みと検証 |
backupHistoryQuery.js / sqlBackupHistoryRepository.js |
DMV クエリ生成と SQL Server 接続 |
backupHistoryEvaluator.js / simulatedBackupHistory.js |
監視結果の判定と疑似アラート生成 |
slackNotifier.js / consoleReporter.js |
Slack payload 生成、送信、コンソール出力 |
backupMonitorService.js / cli.js |
ユースケースの orchestration と CLI 引数処理 |
監視ユーザーは対象データベースで sys.dm_database_backups を参照できる必要があります。多くのサービスレベルでは VIEW DATABASE STATE で足ります。
CREATE USER backup_monitor WITH PASSWORD = '<strong-password>';
GRANT VIEW DATABASE STATE TO backup_monitor;Basic / S0 / S1、または Elastic Pool では、サーバー管理者、Microsoft Entra ID 管理者、または ##MS_ServerStateReader## サーバーロールが必要です。
Hyperscale はスナップショット方式のため、この DMV は結果を返しません。Hyperscale ではこの DMV ベースの監視は使用しないでください。
Node.js 24 以上を使います。
npm install
cp .env.example .env.env を編集してから環境変数として読み込んで実行します。
set -a
. ./.env
set +a
npm run checkJSON で確認する場合:
npm run check:jsonSlack 送信なしで動作確認する場合:
node src/backupMonitor.js --dry-run --jsonSlack Incoming Webhook や Azure SQL Database に接続できない検証環境では、SIMULATE_ALERT=true と SLACK_PRINT_PAYLOAD=true を使うと、DB へ接続せずに意図的なアラート状態を生成し、Slack に送る payload をコンソールへ表示できます。
set -a
. ./.env.simulated.example
set +a
npm run checkこのモードでは終了コードは 1 になり、スケジューラーや GitHub Actions 上でも失敗アラート相当の挙動を確認できます。実際の Slack 送信は SLACK_WEBHOOK_URL を設定した場合だけ行われます。
SIMULATE_ALERT=true の場合は SQL 接続情報が未設定でも simulated-server.database.windows.net / simulated-database として動作します。
Container Apps Job の Schedule trigger で 15 分ごとに単発実行します。Cron は UTC で評価されます。
まず ACR にイメージをビルドします。
export RESOURCE_GROUP=rg-sql-backup-alert
export LOCATION=japaneast
export ACR_NAME=<globally-unique-acr-name>
export ACA_ENVIRONMENT=cae-sql-backup-alert
export JOB_NAME=sql-backup-alert
export IMAGE_NAME=sql-database-backup-alert
export IMAGE_TAG=$(date +%Y%m%d%H%M%S)
export ACR_LOGIN_SERVER="$ACR_NAME.azurecr.io"
export IMAGE="$ACR_LOGIN_SERVER/$IMAGE_NAME:$IMAGE_TAG"
az group create \
--name "$RESOURCE_GROUP" \
--location "$LOCATION"
az acr create \
--resource-group "$RESOURCE_GROUP" \
--name "$ACR_NAME" \
--sku Basic
az acr build \
--registry "$ACR_NAME" \
--image "$IMAGE_NAME:$IMAGE_TAG" \
.
az containerapp env create \
--name "$ACA_ENVIRONMENT" \
--resource-group "$RESOURCE_GROUP" \
--location "$LOCATION"Slack / SQL Database なしで疑似アラートだけ確認する Job:
az containerapp job create \
--name "$JOB_NAME" \
--resource-group "$RESOURCE_GROUP" \
--environment "$ACA_ENVIRONMENT" \
--trigger-type Schedule \
--cron-expression "*/15 * * * *" \
--replica-timeout 300 \
--replica-retry-limit 0 \
--parallelism 1 \
--replica-completion-count 1 \
--image "$IMAGE" \
--cpu 0.25 \
--memory 0.5Gi \
--mi-system-assigned \
--registry-server "$ACR_LOGIN_SERVER" \
--registry-identity system \
--env-vars \
SIMULATE_ALERT=true \
SLACK_PRINT_PAYLOAD=true \
SLACK_MENTION="<!here>" \
BACKUP_CHECK_WINDOWS=D=11520,I=1800,L=60実際に Azure SQL Database と Slack に接続する Job:
export SQL_SERVER=your-server.database.windows.net
export SQL_DATABASE=your-database
export SQL_USERNAME=backup_monitor
export SQL_PASSWORD='<password>'
export SLACK_WEBHOOK_URL='https://hooks.slack.com/services/...'
az containerapp job create \
--name "$JOB_NAME" \
--resource-group "$RESOURCE_GROUP" \
--environment "$ACA_ENVIRONMENT" \
--trigger-type Schedule \
--cron-expression "*/15 * * * *" \
--replica-timeout 300 \
--replica-retry-limit 0 \
--parallelism 1 \
--replica-completion-count 1 \
--image "$IMAGE" \
--cpu 0.25 \
--memory 0.5Gi \
--mi-system-assigned \
--registry-server "$ACR_LOGIN_SERVER" \
--registry-identity system \
--secrets \
sql-password="$SQL_PASSWORD" \
slack-webhook-url="$SLACK_WEBHOOK_URL" \
--env-vars \
SQL_SERVER="$SQL_SERVER" \
SQL_DATABASE="$SQL_DATABASE" \
SQL_AUTH_MODE=sql \
SQL_USERNAME="$SQL_USERNAME" \
SQL_PASSWORD=secretref:sql-password \
SLACK_WEBHOOK_URL=secretref:slack-webhook-url \
BACKUP_CHECK_WINDOWS=D=11520,I=1800,L=60 \
SLACK_NOTIFY_ON_SUCCESS=false手動で即時実行する場合:
az containerapp job start \
--name "$JOB_NAME" \
--resource-group "$RESOURCE_GROUP"疑似アラートまたはバックアップ異常時はコンテナの終了コードが 1 になるため、Container Apps Job の実行結果は失敗として記録されます。アラートがない場合は 0、設定不備は 2 です。
.github/workflows/backup-alert.yml は Node.js 24 でテストを実行します。手動実行時に simulate_alert=true を指定すると、DB に接続せず疑似アラートを発生させ、Slack payload を Actions log に表示します。定期実行は GitHub Actions ではなく Azure Container Apps Job が担当します。
任意の Repository variables:
| Variable | 用途 |
|---|---|
BACKUP_CHECK_WINDOWS |
例: D=11520,I=1800,L=60 |
SLACK_MENTION |
例: <!here> |
docker build --build-arg NODE_VERSION=24 -t sql-database-backup-alert .
docker run --rm --env-file .env sql-database-backup-alert終了コードは正常時 0、バックアップ履歴異常またはクエリ失敗時 1、設定エラー時 2 です。