目次

Amazon Data Lifecycle Manager(DLM)v2.0 完全ガイド

公式ドキュメント


1. 本質と概要

Amazon Data Lifecycle Manager(DLM)は 「EBS スナップショット・AMI・EBS-Optimized スナップショットの作成・保持・削除を自動化するポリシーベースのサービス」。タグ条件に基づいて対象ボリュームを自動検出し、cron 式でスケジュール実行・世代管理・クロスリージョンコピー・クロスアカウント共有を宣言的に管理。DLM 自体は無料(EBS ストレージ料金のみ発生)で、Lambda 運用・EC2 インスタンスの管理コストを廃止できる。

DLM が選ばれる理由

スナップショット自動化による運用負担の削減

  • Lambda + boto3 でスナップショット作成スクリプトを実装する場合、スクリプト管理・エラーハンドリング・リトライロジック・ロギングを全て自前実装する必要があるが、DLM はポリシー JSON で宣言的に定義でき、AWS が全て管理
  • スクリプト障害によるスナップショット欠落リスク(RPO 達成不可)を排除

世代管理の完全自動化

  • 古いスナップショットの手動削除を忘れた場合、ストレージコストが月 +$10,000 以上増加可能
  • DLM はポリシーで保持世代数(例:7 世代)・保持日数(例:30 日)を指定し、自動削除
  • AWS Backup との違い: DLM は EBS 特化・シンプル / AWS Backup は複数サービス横断・複雑

コンプライアンス対応の自動化

  • 金融規制(SOX / HIPAA)で要求される「7 年間のデータ保持」ポリシーを自動実装
  • CloudTrail で全スナップショット操作を監査ログ記録 → 規制機関への証跡提出
  • AWS Config Integration で「スナップショット保持ポリシー準拠状況」を自動監視

クロスリージョン DR 対応

  • メインリージョン(us-east-1)のスナップショットを DR リージョン(us-west-2)に自動複製
  • クロスリージョンコピーのタイミング・暗号化・タグ付与を自動化 → DR 検証効率化

マルチリージョン・マルチアカウント構成の一元管理

  • 複数 AWS アカウント(本番 / ステージング / 開発)のバックアップを、集中バックアップアカウントで一元管理
  • Cross-Account Sharing で権限の最小化 → セキュリティ向上

具体的なユースケース

  1. 本番 EC2 ボリューム: 日次スナップショット 7 世代保持 + 週次スナップショット 4 世代保持 + 月次スナップショット 12 世代保持(多段階ポリシー)
  2. データベース VM: 時間単位スナップショット(RPO 1 時間)で復旧ポイント最大化
  3. ステートレスアプリ: 深夜 1 回のスナップショット → AMI 自動生成 → 古い AMI 自動削除
  4. DR 対応: Primary Region スナップショット → Secondary Region 自動複製(同期レプリケーション)
  5. 開発環境クローン: 本番スナップショット → 開発環境へのクロスアカウント共有

2. DLM アーキテクチャと動作フロー

全体アーキテクチャ

┌─────────────────────────────────────────────────────────────────┐
│           AWS Account(本番)                                   │
│                                                                  │
│  EC2 Instances with EBS Volumes                                 │
│  ┌────────────────┐  ┌────────────────┐                        │
│  │ EC2 Instance 1 │  │ EC2 Instance 2 │                        │
│  │ ┌──────────┐   │  │ ┌──────────┐   │                        │
│  │ │ EBS Vol  │   │  │ │ EBS Vol  │   │                        │
│  │ │ (Backup= │   │  │ │ (Backup= │   │                        │
│  │ │  daily)  │   │  │ │  weekly) │   │                        │
│  │ └──────────┘   │  │ └──────────┘   │                        │
│  └────────────────┘  └────────────────┘                        │
│         │                    │                                   │
│         └────────┬───────────┘                                  │
│                  │ (Target by Tags)                             │
│                  ▼                                              │
│  ┌──────────────────────────────────────────┐                 │
│  │  Data Lifecycle Manager(DLM)           │                 │
│  │  ┌────────────────────────────────────┐  │                 │
│  │  │ Policy: "Daily EBS Snapshots"      │  │                 │
│  │  │ Target: Volumes with Tag:          │  │                 │
│  │  │   Backup = daily                   │  │                 │
│  │  │ Schedule 1:                        │  │                 │
│  │  │  - CreateRule: cron(0 2 * * ? *)   │  │                 │
│  │  │  - RetainRule: Count = 7           │  │                 │
│  │  │                                    │  │                 │
│  │  │ Schedule 2:                        │  │                 │
│  │  │  - CreateRule: cron(0 0 ? * SUN *) │  │                 │
│  │  │  - RetainRule: Count = 4           │  │                 │
│  │  │                                    │  │                 │
│  │  │ CrossRegionCopyRule:               │  │                 │
│  │  │  - TargetRegion: us-west-2         │  │                 │
│  │  │  - RetainRule: Days = 30           │  │                 │
│  │  │  - Encrypted: true                 │  │                 │
│  │  └────────────────────────────────────┘  │                 │
│  └────┬─────────────────────────────────────┘                 │
│       │                                                        │
├───────┴─────────────┬──────────────────┬──────────────────┐   │
│                     │                  │                  │   │
▼                     ▼                  ▼                  ▼   │
Local Region      CrossRegion        CloudTrail          SNS    │
EBS Snapshots     EBS Snapshots      Audit Logs          Alert   │
(Primary)         (us-west-2)        (Compliance)                │
│                 │                                        │     │
└─────────────────┴──────────────────────────────────────┴─────┘
      7 世代保持       30 日保持(DR)         コンプライアンス   |
      ↓               ↓                       ↓
  S3 復旧可能      災害時復旧             監査対応(SOX/HIPAA)

┌─────────────────────────────────────────────────────────────────┐
│           AWS Account(バックアップ集約)                       │
│                                                                  │
│  Cross-Account Snapshot Sharing                                 │
│  ┌──────────────────────────────────────────┐                 │
│  │ Account: 987654321098                    │                 │
│  │ (Centralized Backup Account)             │                 │
│  │                                          │                 │
│  │ Shared Snapshots from Account 123456789012:              │  │
│  │ ├─ snap-0123456789abcdef0                │                 │
│  │ ├─ snap-abcdefg0123456789                │                 │
│  │ └─ snap-xyz123456789abcdef               │                 │
│  │                                          │                 │
│  │ Retention Vault (AWS Backup)            │                 │
│  │ └─ Long-term Archive (7 years)          │                 │
│  └──────────────────────────────────────────┘                 │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

DLM ポリシーのライフサイクル

Day 1 (Mon) - Policy Create
  └─ DLM Policy: "prod-daily-backup"
     └─ Target: Volumes with "Backup=daily"

Day 1 (Mon) - Schedule 1: Daily (Cron: 2:00 AM)
  ├─ Snapshot Created: snap-prod-mon-01
  ├─ Tags Added:
  │  ├─ CreatedBy: DLM
  │  ├─ SourceVolume: vol-xxx
  │  └─ Schedule: Daily
  └─ Retention: 7 days

Day 2 (Tue) - Schedule 1: Daily (Cron: 2:00 AM)
  ├─ Snapshot Created: snap-prod-tue-01
  ├─ Metadata Tracked
  └─ Retention: 7 days

... (Days 3-6 similar)

Day 7 (Sun) - Schedule 1: Daily (Cron: 2:00 AM)
  ├─ Snapshot Created: snap-prod-sun-01
  ├─ Retention: 7 days
  └─ OLD SNAPSHOT DELETED: snap-prod-mon-01
     (created 7 days ago → auto-deleted)

Day 7 (Sun) - Schedule 2: Weekly (Cron: 0:00 AM, Sunday)
  ├─ Snapshot Created: snap-prod-weekly-w01
  ├─ Retention: 4 weeks
  └─ Tags: Schedule=Weekly

Day 8 (Mon) - CrossRegion Copy (us-west-2)
  ├─ Copy Task Initiated: snap-prod-tue-01 → us-west-2
  ├─ Target Region Snapshot: snap-prod-tue-01-dr
  ├─ Encrypted: true (CMK in us-west-2)
  ├─ Tags Copied: true
  └─ Retention in us-west-2: 30 days

Day 38 (Sun) - Monthly Archive (Optional)
  ├─ Monthly Snapshot: snap-prod-monthly-202604
  ├─ Archive to S3 Glacier Deep Archive
  ├─ Retention: 7 years
  └─ Cost: ~$0.00035/GB/month (long-term)

3. DLM ポリシーの実装

ポリシー設定の核となる 5 つの要素

{
  "PolicyType": "EBS_SNAPSHOT_MANAGEMENT" | "IMAGE_MANAGEMENT",
  "ResourceTypes": ["VOLUME"] | ["INSTANCE"],
  "TargetTags": [
    { "Key": "Environment", "Value": "production" }
  ],
  "Schedules": [
    {
      "Name": "DailySnapshot",
      "CreateRule": {
        "CronExpression": "cron(0 2 * * ? *)"
      },
      "RetainRule": {
        "Count": 7
      },
      "CrossRegionCopyRules": [
        {
          "TargetRegion": "us-west-2",
          "Encrypted": true,
          "CmkArn": "arn:aws:kms:us-west-2:123456789012:key/...",
          "RetainRule": {
            "Interval": 30,
            "IntervalUnit": "DAYS"
          }
        }
      ]
    }
  ]
}

実装例 1: 本番環境の多段階バックアップポリシー

# 複数スケジュール: 日次(7世代)+ 週次(4週)+ 月次(12ヶ月)
aws dlm create-lifecycle-policy \
  --description "Production Multi-Tier Backup - Daily + Weekly + Monthly" \
  --state ENABLED \
  --execution-role-arn arn:aws:iam::123456789012:role/AWSDataLifecycleManagerDefaultRole \
  --policy-details '{
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "ResourceTypes": ["VOLUME"],
    "TargetTags": [
      {
        "Key": "Environment",
        "Value": "production"
      },
      {
        "Key": "BackupTier",
        "Value": "multi-tier"
      }
    ],
    "Schedules": [
      {
        "Name": "DailySnapshot",
        "Description": "Daily snapshots at 2:00 AM - 7 day retention",
        "CreateRule": {
          "CronExpression": "cron(0 2 * * ? *)"
        },
        "RetainRule": {
          "Count": 7
        },
        "FastRestoreRule": {
          "Count": 1
        },
        "TagsToAdd": [
          {
            "Key": "SnapshotType",
            "Value": "daily"
          },
          {
            "Key": "BackupTier",
            "Value": "1-Daily"
          }
        ],
        "CopyTags": true,
        "CrossRegionCopyRules": [
          {
            "TargetRegion": "us-west-2",
            "Encrypted": true,
            "CmkArn": "arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012",
            "RetainRule": {
              "Interval": 7,
              "IntervalUnit": "DAYS"
            },
            "CopyTags": true
          }
        ]
      },
      {
        "Name": "WeeklySnapshot",
        "Description": "Weekly snapshots every Sunday - 4 week retention",
        "CreateRule": {
          "CronExpression": "cron(0 3 ? * SUN *)"
        },
        "RetainRule": {
          "Count": 4
        },
        "FastRestoreRule": {
          "Count": 0
        },
        "TagsToAdd": [
          {
            "Key": "SnapshotType",
            "Value": "weekly"
          },
          {
            "Key": "BackupTier",
            "Value": "2-Weekly"
          }
        ],
        "CopyTags": true,
        "CrossRegionCopyRules": [
          {
            "TargetRegion": "us-west-2",
            "Encrypted": true,
            "CmkArn": "arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012",
            "RetainRule": {
              "Interval": 30,
              "IntervalUnit": "DAYS"
            },
            "CopyTags": true
          }
        ]
      },
      {
        "Name": "MonthlySnapshot",
        "Description": "Monthly snapshots 1st of month - 12 month retention",
        "CreateRule": {
          "CronExpression": "cron(0 4 1 * ? *)"
        },
        "RetainRule": {
          "Count": 12
        },
        "TagsToAdd": [
          {
            "Key": "SnapshotType",
            "Value": "monthly"
          },
          {
            "Key": "BackupTier",
            "Value": "3-Monthly"
          },
          {
            "Key": "ArchiveCandidate",
            "Value": "true"
          }
        ],
        "CopyTags": true,
        "CrossRegionCopyRules": [
          {
            "TargetRegion": "us-west-2",
            "Encrypted": true,
            "CmkArn": "arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012",
            "RetainRule": {
              "Interval": 365,
              "IntervalUnit": "DAYS"
            },
            "CopyTags": true
          }
        ]
      }
    ]
  }'

# Output: Policy ID
# {
#   "PolicyId": "policy-0123456789abcdef0"
# }

# ポリシー確認
aws dlm get-lifecycle-policy \
  --policy-id policy-0123456789abcdef0 \
  --query 'Policy.PolicyDetails.Schedules[*].[Name,CreateRule.CronExpression,RetainRule.Count]' \
  --output table

実装例 2: データベース VM の高頻度スナップショット(RPO 1 時間)

# 1 時間単位のスナップショット(RPO = 1 hour)
# 本番 DB の最大 RTO 1 時間要件に対応

aws dlm create-lifecycle-policy \
  --description "Database VM - Hourly snapshots with 24h retention" \
  --state ENABLED \
  --execution-role-arn arn:aws:iam::123456789012:role/AWSDataLifecycleManagerDefaultRole \
  --policy-details '{
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "ResourceTypes": ["VOLUME"],
    "TargetTags": [
      {
        "Key": "Application",
        "Value": "database"
      },
      {
        "Key": "CriticalLevel",
        "Value": "tier1-database"
      }
    ],
    "Schedules": [
      {
        "Name": "HourlyDatabaseBackup",
        "Description": "Hourly database backups - 24 snapshots retained",
        "CreateRule": {
          "CronExpression": "cron(0 * * * ? *)"
        },
        "RetainRule": {
          "Count": 24
        },
        "FastRestoreRule": {
          "Count": 2
        },
        "ArchiveRule": {
          "RetainRule": {
            "RetentionArchiveTier": {
              "Interval": 0,
              "IntervalUnit": "DAYS"
            }
          }
        },
        "TagsToAdd": [
          {
            "Key": "BackupFrequency",
            "Value": "hourly"
          },
          {
            "Key": "RPO",
            "Value": "1hour"
          },
          {
            "Key": "CostCenter",
            "Value": "database-ops"
          }
        ],
        "CopyTags": true,
        "CrossRegionCopyRules": [
          {
            "TargetRegion": "us-east-2",
            "Encrypted": true,
            "CmkArn": "arn:aws:kms:us-east-2:123456789012:key/db-kms-key",
            "RetainRule": {
              "Interval": 7,
              "IntervalUnit": "DAYS"
            },
            "CopyTags": true
          }
        ]
      }
    ]
  }'

実装例 3: EC2 インスタンス全体のバックアップ(AMI 自動化)

# EC2 インスタンス → AMI 自動生成 → 古い AMI 自動削除
# 用途: ステートレスアプリの定期的な「ゴールデンイメージ」更新

aws dlm create-lifecycle-policy \
  --description "AMI Lifecycle - Weekly creation, 4 versions retained" \
  --state ENABLED \
  --execution-role-arn arn:aws:iam::123456789012:role/AWSDataLifecycleManagerDefaultRole \
  --policy-details '{
    "PolicyType": "IMAGE_MANAGEMENT",
    "ResourceTypes": ["INSTANCE"],
    "TargetTags": [
      {
        "Key": "AMI-Backup",
        "Value": "enabled"
      }
    ],
    "Schedules": [
      {
        "Name": "WeeklyAMICreation",
        "Description": "Create AMI every Sunday at 4 AM - keep 4 recent versions",
        "CreateRule": {
          "CronExpression": "cron(0 4 ? * SUN *)"
        },
        "RetainRule": {
          "Count": 4
        },
        "TagsToAdd": [
          {
            "Key": "CreatedBy",
            "Value": "DLM"
          },
          {
            "Key": "BackupType",
            "Value": "automated-ami"
          },
          {
            "Key": "Application",
            "Value": "web-server"
          }
        ],
        "CopyTags": true,
        "CrossImageCopyRules": [
          {
            "TargetRegion": "eu-west-1",
            "Encrypted": true,
            "CmkArn": "arn:aws:kms:eu-west-1:123456789012:key/ami-kms-key"
          }
        ]
      }
    ]
  }'

# 古い AMI のクリーンアップ確認
aws ec2 describe-images \
  --owners self \
  --filters "Name=tag:CreatedBy,Values=DLM" \
  --query 'Images | sort_by(@, &CreationDate)' \
  --output table

4. 高度なポリシー設定

Fast Restore(高速復旧)の有効化

{
  "Name": "CriticalDataFastRestore",
  "Description": "High-frequency snapshots with Fast Restore enabled",
  "CreateRule": {
    "CronExpression": "cron(0 */4 * * ? *)"
  },
  "RetainRule": {
    "Count": 6
  },
  "FastRestoreRule": {
    "Count": 2
  }
}

説明:
  - CreateRule: 4 時間ごとにスナップショット作成
  - RetainRule: 最新 6 個を保持(= 24 時間分)
  - FastRestoreRule: 最新 2 個を Fast Restore 対応
    ├─ Fast Restore: EBS スナップショット → EC2 Volume に数秒で復旧
    ├─ 通常スナップショット: 数分かかる
    └─ コスト: Fast Restore 対応スナップショット +$0.10/GB/月

Archive Rule(アーカイブ)の有効化

{
  "Name": "MonthlyWithArchive",
  "CreateRule": {
    "CronExpression": "cron(0 5 1 * ? *)"
  },
  "RetainRule": {
    "Count": 24
  },
  "ArchiveRule": {
    "RetainRule": {
      "RetentionArchiveTier": {
        "Interval": 7,
        "IntervalUnit": "DAYS"
      }
    }
  }
}

説明:
  - RetainRule: スタンダードストレージに 24 ヶ月保持
  - ArchiveRule: 作成後 7 日でアーカイブ層に自動移行
    ├─ Standard Tier: $0.050/GB/月(アクセス時間: 秒)
    ├─ Archive Tier: $0.010/GB/月(アクセス時間: 数時間)
    └─ TCO: 7 年保持時に 70% コスト削減

Pre & Post Script(スクリプト実行)

{
  "Name": "DatabaseWithPrePost",
  "CreateRule": {
    "CronExpression": "cron(0 2 * * ? *)"
  },
  "RetainRule": {
    "Count": 7
  },
  "CreateImageRule": {
    "CronExpression": "cron(0 3 * * ? *)"
  },
  "Scripts": [
    {
      "ExecutionPhase": "PRE",
      "ExecutionTimeout": 600,
      "ScriptLocation": "arn:aws:lambda:us-east-1:123456789012:function:pre-snapshot-backup"
    },
    {
      "ExecutionPhase": "POST",
      "ExecutionTimeout": 600,
      "ScriptLocation": "arn:aws:lambda:us-east-1:123456789012:function:post-snapshot-verify"
    }
  ]
}

説明:
  - PRE-Script: スナップショット前に実行(DB チェックポイント・ファイルシステム同期)
  - POST-Script: スナップショット後に実行(整合性検証・通知送信)

5. Python による自動化・監視・管理

import boto3
import json
from datetime import datetime, timedelta
from botocore.exceptions import ClientError

class DLMAutomationManager:
    """DLM ポリシーの自動管理・監視・分析"""
    
    def __init__(self, region='us-east-1'):
        self.dlm = boto3.client('dlm', region_name=region)
        self.ec2 = boto3.client('ec2', region_name=region)
        self.cloudwatch = boto3.client('cloudwatch', region_name=region)
        self.sns = boto3.client('sns', region_name=region)
        self.region = region
    
    def create_policy_from_template(self, template_name, **kwargs):
        """テンプレートからポリシーを自動生成"""
        
        templates = {
            'prod-daily': {
                'PolicyType': 'EBS_SNAPSHOT_MANAGEMENT',
                'ResourceTypes': ['VOLUME'],
                'TargetTags': [{'Key': 'Environment', 'Value': 'production'}],
                'Schedules': [
                    {
                        'Name': 'Daily',
                        'CreateRule': {'CronExpression': 'cron(0 2 * * ? *)'},
                        'RetainRule': {'Count': 7}
                    },
                    {
                        'Name': 'Weekly',
                        'CreateRule': {'CronExpression': 'cron(0 3 ? * SUN *)'},
                        'RetainRule': {'Count': 4}
                    },
                    {
                        'Name': 'Monthly',
                        'CreateRule': {'CronExpression': 'cron(0 4 1 * ? *)'},
                        'RetainRule': {'Count': 12}
                    }
                ]
            },
            'db-hourly': {
                'PolicyType': 'EBS_SNAPSHOT_MANAGEMENT',
                'ResourceTypes': ['VOLUME'],
                'TargetTags': [{'Key': 'Application', 'Value': 'database'}],
                'Schedules': [
                    {
                        'Name': 'Hourly',
                        'CreateRule': {'CronExpression': 'cron(0 * * * ? *)'},
                        'RetainRule': {'Count': 24},
                        'FastRestoreRule': {'Count': 2}
                    }
                ]
            }
        }
        
        if template_name not in templates:
            raise ValueError(f"Unknown template: {template_name}")
        
        policy_spec = templates[template_name].copy()
        
        # テンプレートのパラメータをオーバーライド
        for key, value in kwargs.items():
            if key in policy_spec:
                policy_spec[key] = value
        
        response = self.dlm.create_lifecycle_policy(
            ExecutionRoleArn=f'arn:aws:iam::123456789012:role/AWSDataLifecycleManagerDefaultRole',
            Description=f'Auto-generated from {template_name} template',
            State='ENABLED',
            PolicyDetails=policy_spec
        )
        
        print(f"✓ Policy created: {response['PolicyId']}")
        return response['PolicyId']
    
    def analyze_snapshot_costs(self):
        """スナップショット関連コスト分析"""
        
        snapshots = self.ec2.describe_snapshots(OwnerIds=['self'])['Snapshots']
        
        total_size_gb = sum(s['VolumeSize'] for s in snapshots)
        standard_cost = total_size_gb * 0.050  # $0.050/GB/month
        
        # Fast Restore 対象スナップショット
        fast_restore_count = sum(1 for s in snapshots if s.get('FastRestoreProgress'))
        fast_restore_cost = fast_restore_count * 0.10 * total_size_gb / len(snapshots)
        
        # Archive 対象スナップショット
        archive_count = sum(1 for s in snapshots if 'archive' in s.get('StorageTier', '').lower())
        archive_cost = (total_size_gb * archive_count / len(snapshots)) * 0.010
        
        total_monthly_cost = standard_cost + fast_restore_cost + archive_cost
        
        report = {
            'total_snapshots': len(snapshots),
            'total_size_gb': total_size_gb,
            'costs': {
                'standard_tier': round(standard_cost, 2),
                'fast_restore': round(fast_restore_cost, 2),
                'archive_tier': round(archive_cost, 2),
                'total_monthly': round(total_monthly_cost, 2)
            },
            'optimization_opportunity': self._find_cost_savings(snapshots)
        }
        
        return report
    
    def _find_cost_savings(self, snapshots):
        """コスト最適化の機会を検出"""
        
        old_snapshots = []
        duplicate_snapshots = []
        
        for snap in snapshots:
            # 作成日時が 90 日以上前 → Archive 推奨
            if snap['StartTime'].replace(tzinfo=None) < datetime.now() - timedelta(days=90):
                old_snapshots.append(snap['SnapshotId'])
            
            # 同じボリュームの重複スナップショット → 削除推奨
            volume_id = snap['VolumeId']
            volume_snaps = [s for s in snapshots if s['VolumeId'] == volume_id]
            if len(volume_snaps) > 7:  # デフォルト保持世代より多い
                duplicate_snapshots.append(volume_id)
        
        return {
            'old_snapshots_archive_candidate': len(old_snapshots),
            'volumes_with_excess_snapshots': len(set(duplicate_snapshots))
        }
    
    def monitor_policy_health(self):
        """DLM ポリシーの健全性監視"""
        
        policies = self.dlm.get_lifecycle_policies()['Policies']
        
        health_report = []
        
        for policy in policies:
            policy_details = self.dlm.get_lifecycle_policy(PolicyId=policy['PolicyId'])['Policy']
            
            # 最後の実行ステータス確認
            try:
                executions = self.dlm.get_lifecycle_policy_state(PolicyId=policy['PolicyId'])
                last_exec = executions['PolicyExecutionState']
                last_exec_time = last_exec.get('LastExecutionTime')
                last_exec_state = last_exec.get('State')  # SUCCESS / ERROR
                
            except ClientError:
                last_exec_time = None
                last_exec_state = 'UNKNOWN'
            
            health_report.append({
                'PolicyId': policy['PolicyId'],
                'Description': policy_details['Policy'].get('Description', 'N/A'),
                'State': policy['State'],
                'LastExecution': last_exec_time,
                'LastExecutionState': last_exec_state,
                'IsHealthy': last_exec_state == 'SUCCESS' and policy['State'] == 'ENABLED'
            })
        
        return health_report
    
    def setup_cost_alert(self, threshold_dollars=1000):
        """EBS スナップショットコスト超過アラート設定"""
        
        alarm_name = f'dlm-snapshot-cost-{self.region}'
        
        self.cloudwatch.put_metric_alarm(
            AlarmName=alarm_name,
            MetricName='SnapshotStorageCost',
            Namespace='AWS/EBS',
            Statistic='Sum',
            Period=3600,  # 1 時間
            EvaluationPeriods=24,  # 24 時間
            Threshold=threshold_dollars,
            ComparisonOperator='GreaterThanThreshold',
            AlarmActions=[
                'arn:aws:sns:us-east-1:123456789012:cost-alerts'
            ]
        )
        
        print(f"✓ Cost alert set: {threshold_dollars} USD/day")
    
    def cleanup_untagged_volumes(self):
        """タグ付けされていないボリュームをリスト化"""
        
        volumes = self.ec2.describe_volumes()['Volumes']
        
        untagged = []
        for vol in volumes:
            tags = {tag['Key']: tag['Value'] for tag in vol.get('Tags', [])}
            if 'Environment' not in tags or 'Backup' not in tags:
                untagged.append({
                    'VolumeId': vol['VolumeId'],
                    'Size': vol['Size'],
                    'State': vol['State'],
                    'MissingTags': [k for k in ['Environment', 'Backup'] 
                                    if k not in tags]
                })
        
        return untagged

# 使用例
manager = DLMAutomationManager(region='us-east-1')

# 1. テンプレートからポリシー作成
policy_id = manager.create_policy_from_template(
    'prod-daily',
    TargetTags=[{'Key': 'Environment', 'Value': 'staging'}]
)

# 2. コスト分析
costs = manager.analyze_snapshot_costs()
print(f"\nSnapshot Cost Analysis:")
print(json.dumps(costs, indent=2))

# 3. ポリシーの健全性監視
health = manager.monitor_policy_health()
print(f"\nPolicy Health Report:")
for h in health:
    print(f"  {h['PolicyId']}: {h['LastExecutionState']}")

# 4. コストアラート設定
manager.setup_cost_alert(threshold_dollars=500)

# 5. タグ付けされていないボリュームの検出
untagged = manager.cleanup_untagged_volumes()
print(f"\nUntagged Volumes: {len(untagged)}")
for vol in untagged:
    print(f"  {vol['VolumeId']}: Missing {vol['MissingTags']}")

6. AWS Backup との使い分け

観点 Data Lifecycle Manager(DLM) AWS Backup
対象リソース EBS Snapshot / AMI のみ EBS / EC2 / RDS / EFS / S3 / DynamoDB / FSx 等 15+ サービス
設定方法 シンプル(JSON ポリシー) 中程度(Backup Plan + Recovery Point)
ライフサイクル制御 高い(Retain / Archive / Delete) 高い(Transition / Backup Vault Lock)
コンプライアンス対応 中(ポリシー定義のみ) 高(Vault Lock / 監査ログ)
クロスリージョン ✓ 対応 ✓ 対応
クロスアカウント ✓ 対応 ✓ 対応
推奨シーン EBS スナップショット のみのシンプル管理 複数 AWS サービスの横断的バックアップ
コスト 無料(ストレージのみ) Backup Plan $0.40/month + on-demand $0.005/snapshot
使いやすさ 簡単(タグベース) 中程度(複雑な設定も可)

使い分けルール

  • EBS スナップショットのみ → DLM
  • 複数サービス横断 → AWS Backup
  • 高度なコンプライアンス(HIPAA / SOX) → AWS Backup + Vault Lock

7. CloudTrail・CloudWatch・EventBridge 連携

CloudTrail による操作監査

# DLM 関連の全操作をログ記録
aws cloudtrail put-event-selectors \
  --trail-name dlm-audit-trail \
  --event-selectors '[
    {
      "ReadWriteType": "All",
      "IncludeManagementEvents": true,
      "DataResources": [
        {
          "Type": "AWS::EC2::Snapshot",
          "Values": ["arn:aws:ec2:us-east-1:123456789012:snapshot/*"]
        }
      ]
    }
  ]'

# DLM によるスナップショット作成ログを検索
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=CreateSnapshot \
  --lookup-attributes AttributeKey=Username,AttributeValue=dlm.amazonaws.com \
  --query 'Events[*].[EventTime,EventName,Username,CloudTrailEvent]' \
  --output text

CloudWatch Alarms

# Snapshot creation failure
aws cloudwatch put-metric-alarm \
  --alarm-name dlm-snapshot-failure-alert \
  --alarm-description "Alert when DLM snapshot creation fails" \
  --metric-name SnapshotCreationFailures \
  --namespace AWS/DLM \
  --statistic Sum \
  --period 300 \
  --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:dlm-alerts

EventBridge Integration

# Snapshot completed → Lambda トリガー
aws events put-rule \
  --name dlm-snapshot-complete \
  --event-pattern '{
    "source": ["aws.ec2"],
    "detail-type": ["EBS Snapshot State-change Notification"],
    "detail": {
      "state": ["completed"],
      "SnapshotId": ["snap-*"]
    }
  }'

aws events put-targets \
  --rule dlm-snapshot-complete \
  --targets "Id=1,Arn=arn:aws:lambda:us-east-1:123456789012:function:post-snapshot-actions"

8. 設計チェックリスト

ポリシー設計

  • [ ] ポリシータイプ: EBS_SNAPSHOT_MANAGEMENT vs IMAGE_MANAGEMENT の選択
  • [ ] Target Tags: 対象リソースの識別タグを明確化(Environment / Backup / CostCenter)
  • [ ] 複数スケジュール: 日次 / 週次 / 月次の必要に応じた組み合わせ
  • [ ] 保持世代数 / 日数: 業務要件(RTO / RPO)に合わせて設定
  • [ ] Fast Restore: 高速復旧が必要なボリュームのみ有効化

クロスリージョン・クロスアカウント

  • [ ] CrossRegionCopyRule: DR リージョン指定・暗号化キー準備
  • [ ] クロスアカウント共有: 集中バックアップアカウント IAM ロール権限確認
  • [ ] KMS キー権限: 他リージョン・他アカウントでの復号権限付与

コンプライアンス・監査

  • [ ] CloudTrail 有効化: 全スナップショット操作のログ記録
  • [ ] Tagging Strategy: CreatedBy / Schedule / BackupTier タグを自動付与
  • [ ] Retention 明確化: コンプライアンス要件(SOX 7 年等)をポリシーに反映
  • [ ] 通知: SNS で管理者・監査チームに定期報告

コスト最適化

  • [ ] Archive Rule: 90 日以上保持スナップショットは Archive 層に移行
  • [ ] Cost Anomaly Detection: CloudWatch でコスト異常検知設定
  • [ ] Snapshot Cleanup: DLM でカバーされていない古いスナップショット手動削除
  • [ ] Fast Restore 精査: 必要なボリュームのみ Fast Restore 有効化

9. まとめ

Amazon Data Lifecycle Manager(DLM)は 「EBS スナップショット・AMI のライフサイクルをポリシーベースで自動管理するサービス」。タグを使った対象リソース自動検出・複数スケジュール(日次・週次・月次)による多段階バックアップ・クロスリージョン DR 対応・クロスアカウント集約管理を実現。Lambda スクリプト管理・運用負担を廃止し、DLM 自体は無料(EBS ストレージのみ課金)で、シンプルで信頼性高いバックアップ基盤を構築。EBS 特化のシンプルなニーズなら DLM、複数 AWS サービス横断なら AWS Backup を選択。


参考資料