Amazon Data Lifecycle Managerのプレスクリプトとポストスクリプトを試してみる

2023年11月にAmazon Data Lifecycle Managerにプレスクリプト、ポストスクリプトの機能が追加されましたので試してみました。

https://aws.amazon.com/jp/about-aws/whats-new/2023/11/amazon-data-lifecycle-manager-pre-post-script-automation-ebs-snapshots/


# Amazon Data Lifecycle Managerとは
AMIやEBSスナップショットの取得を自動化及び管理してくれる機能です。(以下DLMと記載)

https://docs.aws.amazon.com/ebs/latest/userguide/snapshot-lifecycle.html

DLMでのEBSスナップショット取得前後に任意の処理を実行したい場合にプレスクリプト、ポストスクリプトの機能を使用して実現できます。
**DLMによるAMI取得ではプレスクリプト、ポストスクリプトの機能は使用できないので御注意下さい。**


# 今回の検証の処理の流れ
検証では以下の処理が実行されるように実装します。
①DLMのプレスクリプトでOS内のアプリケーション(apache)を停止
②DLMによってEBSスナップショットを取得
③DLMのポストスクリプトでOS内のアプリケーション(apache)を起動


# 設定
設定手順を記載します。

## EC2の起動とapacheのインストール
EC2のOSにはAmazonLinux2023を選択しました。
EC2起動後にOSにログインして以下のコマンドでapacheをインストールします。
```
yum -y install httpd
```

インストール後、apacheを起動させます。
```
systemctl start httpd
```

httpdのプロセスが起動していることを確認します。
```
[root@http-server ~]# ps -ef | grep httpd | grep -v grep
root        1467       1  0 14:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache      1477    1467  0 14:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache      1478    1467  0 14:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache      1490    1467  0 14:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache      1507    1467  0 14:24 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
```

## SSM AgentのインストールとEC2へのIAMロールの設定
DLMのプレスクリプト、ポストスクリプト機能を使用するにはSSM Agentが必要となります。
今回OSに選択したAmazonLinux2023では最初からSSM Agentが導入されていますが、SSM Agentが未導入のOSの場合は新規にインストールをして下さい。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-manual-agent-install.html

また、AWS Systems Managerのエンドポイントへアクセスするためにインターネット経由又はVPCエンドポイントでの接続経路を確保する必要があることと、エンドポイントへのアクセス権限を付与するためIAMロールをEC2に設定します。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/setup-instance-permissions.html

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/setup-create-vpc.html


## SSMドキュメントの作成
apacheを起動停止するためのSSMドキュメントを作成します。

AWSコンソールでSystems Managerを選択して左メニューの「ドキュメント」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/888b64fc-8cd6-86ca-49e2-dbc8bab2cb21.png)

右側の「ドキュメントの作成」で「コマンドまたはセッション」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/a79926ab-1b35-b5bd-d386-ffb59ece7a0d.png)

ドキュメントの詳細で、以下を設定します。
　名前：任意の名前を設定
　ターゲットタイプ：/AWS::EC2::Instance を選択
　ドキュメントタイプ：Command を設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/58656619-4d05-6ca0-3630-c6884635d880.png)

コンテンツで「YAML」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/4e17df8a-c3fa-3e69-b6e7-14af98c440f1.png)

以下のコードを設定します。
```
---
schemaVersion: '2.2'
description: SSM Document Template for Amazon Data Lifecycle Manager Pre/Post script feature
parameters:
  executionId:
    type: String
    default: None
    description: (Required) Specifies the unique identifier associated with a pre and/or post execution
    allowedPattern: ^(None|[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$
  command:
  # Data Lifecycle Manager will trigger the pre-script and post-script actions during policy execution. 
  # 'dry-run' option is intended for validating the document execution without triggering any commands
  # on the instance. The following allowedValues will allow Data Lifecycle Manager to successfully 
  # trigger pre and post script actions.
    type: String
    default: 'dry-run'
    description: (Required) Specifies whether pre-script and/or post-script should be executed.
    allowedValues:
    - pre-script
    - post-script
    - dry-run

mainSteps:
- action: aws:runShellScript
  description: Run Database freeze/thaw commands
  name: run_pre_post_scripts
  precondition:
    StringEquals:
    - platformType
    - Linux
  inputs:
    runCommand:
    - |
      #!/bin/bash

      ###===============================================================================###
      ### Global variables
      ###===============================================================================###
      START=$(date +%s)
      # For testing this script locally, replace the below with OPERATION=$1.
      OPERATION={{ command }}

      # Add all pre-script actions to be performed within the function below
      execute_pre_script() {
          echo "INFO: Start execution of pre-script. httpd stop."
          # httpd stop
          systemctl stop httpd
          # httpd stop check
          HTTPD_COUNT=`ps -ef | grep httpd | grep -v grep | wc -l`
          if [ ${HTTPD_COUNT} != 0 ]; then
           echo "ERROR: httpd is not stopped."
           exit 201
          fi
      }

      # Add all post-script actions to be performed within the function below
      execute_post_script() {
          echo "INFO: Start execution of post-script. httpd start"
          # httpd start
          systemctl start httpd
          # httpd start check
          HTTPD_COUNT=`ps -ef | grep httpd | grep -v grep | wc -l`
          if [ ${HTTPD_COUNT} = 0 ]; then
           echo "ERROR: httpd is not started."
           exit 202
          fi
      }

      # Debug logging for parameters passed to the SSM document
      echo "INFO: ${OPERATION} starting at $(date) with executionId: ${EXECUTION_ID}"

      # Based on the command parameter value execute the function that supports 
      # pre-script/post-script operation
      case ${OPERATION} in
          pre-script)
              execute_pre_script
              ;;
          post-script)
              execute_post_script
              ;;
          dry-run)
              echo "INFO: dry-run option invoked - taking no action"
              ;;
          *)
              echo "ERROR: Invalid command parameter passed. Please use either pre-script, post-script, dry-run."
              exit 1 # return failure
              ;;
      esac

      END=$(date +%s)
      # Debug Log for profiling the script time
      echo "INFO: ${OPERATION} completed at $(date). Total runtime: $((${END} - ${START})) seconds."
```

ドキュメントのサンプルコードはAWS公式マニュアルにも記載があります。

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/automate-app-consistent-backups.html


## DLMの設定
AWSコンソールでEC2を選択して左メニューの「ライフサイクルマネージャー」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/76a119e4-cdf3-4d79-9af3-f2495290d659.png)

右上の「ライフサイクルポリシーを作成」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/fbb0f303-757d-3e46-4165-eca47e289210.png)

「カスタムポリシー」及び「EBSスナップショットポリシー」を選択します。**ここで「EBS-backed AMIポリシー」を選択すると後続でプレスクリプト、ポストスクリプトが設定できません。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/0df180f9-897c-9fc1-d81d-f61ec9a99b6c.png)

ターゲットリソースタイプで「インスタンス」を選択します。**ここで「ボリューム」を選択すると後続でプレスクリプト、ポストスクリプトが設定できません。**
説明で任意のポリシー名を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/354db832-84b9-d100-bcff-e1809ea4b8ca.png)

IAMロールと必要に応じてタグを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/306df786-814f-5d9e-0d18-9cc315be4bd3.png)

DLMに設定するIAMロールは公式サイトを御確認下さい。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/dlm-prerequisites.html

ポリシーのステータスで設定完了後にこのDLMのポリシーをすぐに有効にするか無効にしておくかを選択できます。
ボリュームを除外でEBSスナップショットの対象から除外するボリュームを選択することもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/0d747670-d451-b433-576c-ca14d8be2fe8.png)

スケジュールの詳細でEBSスナップショットの取得頻度や実行時間、世代管理を設定します。
**初回の実行は設定した開始時刻から1時間以内に実行される仕様なので御注意下さい。また、ここで設定する開始時刻はUTCである点にも注意が必要です。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/c585679e-c352-feae-e452-978901c7fcf4.png)

EBSスナップショットに設定するタグを必要に応じて設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/829cc142-f36e-3952-65f2-7be1f71ca258.png)

ここでようやくプレスクリプト、ポストスクリプトの設定が出てきました。
この画面のように先ほど作成したSSMドキュメントを指定してスクリプトのタイムアウト値やスクリプト失敗時の再試行などを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/0b7aaac8-4bca-c853-fc55-1e3e0c644921.png)

その他のオプションで、EBSスナップショットに対して[高速スナップショット](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-fast-snapshot-restore.html)を有効化したり別リージョンへのコピー、別AWSアカウントへの共有を自動化するかも選択できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/4add9fac-7f42-4073-0858-bf6bbe2cc8ac.png)


# DLM実行結果の確認
DLMで取得されたEBSスナップショットのタグを確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268065/d1c6c318-2247-d2e1-23f7-6b47e2990c2c.png)

aws:dlm:pre-scriptとaws:dlm:post-scriptのValueがSUCCESSになっています。
これはプレスクリプトとポストスクリプトが正常に実行されたことを示す結果です。

OS内のログでもapacheが停止起動されたことを確認しました。
```
[Sun Dec 10 16:51:06.180966 2023] [mpm_event:notice] [pid 1467:tid 1467] AH00492: caught SIGWINCH, shutting down gracefully　※apacheが停止したログ
[Sun Dec 10 16:51:09.212254 2023] [suexec:notice] [pid 8228:tid 8228] AH01232: suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
[Sun Dec 10 16:51:09.230848 2023] [lbmethod_heartbeat:notice] [pid 8228:tid 8228] AH02282: No slotmem from mod_heartmonitor
[Sun Dec 10 16:51:09.236298 2023] [mpm_event:notice] [pid 8228:tid 8228] AH00489: Apache/2.4.58 (Amazon Linux) configured -- resuming normal operations
[Sun Dec 10 16:51:09.236354 2023] [core:notice] [pid 8228:tid 8228] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND'　※apacheが起動したログ
```


# まとめ
以上がDLMのプレスクリプト、ポストスクリプト実装の流れとなります。
EBSスナップショット取得前にEC2上のアプリケーションやデータベースに対して静止点を設ける場合、これまではOSのタスクスケジューラやcronでスクリプトを実行したりすることもありましたが、この機能を使用することによってDLM単体で静止点確保とスナップショット取得が完結できるようになりました。
DLMの進化に今後も期待したいと思います。