[re:Invent 2019] EBS direct APIs でEBSスナップショットのデータの中身を比較してみた #reinvent

まいど、大阪の市田です。
re:Invent2019にて、「EBS direct APIs」なる新機能がリリースされました。

[速報] EBSスナップショット間の直接比較が可能に!EBS direct APIsがリリースされました #reinvent | Developers.IO

実際にどのように使うのか、どんなデータが取れるのかということを試してみたので紹介したいと思います。

AWS CLIでやってみた

下記公式ドキュメントに沿って試してみます。なお、試す前にAWS CLIを最新バージョンにアップデートしておきましょう。

Accessing the Contents of an EBS Snapshot - Amazon Elastic Compute Cloud

IAMの許可設定

最初に、EBSのDirect APIを使用するためにスナップショットブロックへのアクセス許可を設定します。今回は簡単にテストするため一時的に下記のポリシー内容としました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ebs:*"
            ],
            "Resource": "arn:aws:ec2:*::snapshot/*"
        }
    ]
}

先程のドキュメントには、特定のタグに限定したい場合などユースケースに応じたポリシー例が掲載されていますので、ご参考にしていただければと思います。

スナップショットのブロックインデックスとブロックトークンを取得する

EBSのスナップショットは複数のブロックから構成されており、その識別にブロックインデックスが使用されています。また各ブロック内のデータを参照するためには 「ブロックインデックス」「ブロックトークン」が必要となります。
このブロックトークンには有効期限があり、ブロックをリスト表示した際にUnixtimeで返されます。

各用語の詳しい説明については先程のドキュメントを参照いただければと思います。

まずは、適当なEBSのスナップショットに対してブロックインデックスを取得してみます。コマンドはlist-snapshot-blocksというものになります。
下記コマンド例は、ブロックインデックスが1番目から100個のインデックスとトークンを取得するオプション指定です。(今回はTokyoリージョンで試しています。)

aws ebs list-snapshot-blocks \
--region ap-northeast-1 \
--snapshot-id snap-xxxxxxxxxxxxxx \
--starting-block-index 1 \
--max-results 100

すると、次のような応答が返ってきます。ここでブロックトークンも一緒に取得することができます。(下記のトークンはダミーです)
「ExpiryTime」としてトークンの有効期限が「1576049555.267(2019/12/11 16:32:35)」であることも分かります。

{
    "Blocks": [
        {
            "BlockIndex": 2,
            "BlockToken": "AAABATgWZC0XcFwUKvTJbUXMiSPg59KVxJGL+BWBClkw6spzCxJVqDVaTskJ"
        },
        {
            "BlockIndex": 4,
            "BlockToken": "AAABAaYvPax6mv+iGWLdTUjQtFWouQ7Dqz6nSD9L+CbXnvpkswA6iDID523d"
        },
        {

(中略)

        },
        {
            "BlockIndex": 101,
            "BlockToken": "AAABATgWZC0XcFwUKvTJbUXMiSPg59KVxJGL+BWBClkw6spzCxJVqDVaTskJ"
        },
        {
            "BlockIndex": 102,
            "BlockToken": "AAABAV3/PNhXOynVdMYHUpPsetaSvjLB1dtIGfbJv5OJ0sX855EzGTWos4a4"
        }
    ],
    "ExpiryTime": 1576049555.267,
    "VolumeSize": 8,
    "BlockSize": 524288,
    "NextToken": "AAABATgWZC0XcFwUKvTJbUXMiSPg59KVxJGL+BWBClkw6spzCxJVqDVaTskJ"
}

スナップショット間で異なるブロックの情報を取得する

次にスナップショットの差分を確認してみたいと思いますが、明らかなデータ比較ができるように、2度目のスナップショットを取る前に対象インスタンス上で/var/log/messagesにログをを出力させておきます。

実行コマンドは下記のとおりです。

$ logger -t SnapshotTest mymessage

これで/var/log/messagesに下記のログが出力されます。

Dec  4 06:15:23 ip-10-0-0-165 SnapshotTest: mymessage

この後に改めて対象ボリュームでスナップショットを取得しておきます。この状態でスナップショットの中身の差異を確認していきたいと思います。コマンドはlist-changed-blocksです。

確認する際に、比較したい2つのスナップショットIDとブロックインデックスの範囲を指定します。

aws ebs list-changed-blocks \
--region ap-northeast-1 \
--first-snapshot-id snap-xxxxxxxxxxxxxxx \
--second-snapshot-id snap-yyyyyyyyyyyyyyy \
--starting-block-index 0 \
--max-results 500

実行結果として次のような応答が得られます。(トークンはダミーです)
この結果から「ブロックインデックス4」と「ブロックインデックス26」・・・で差異があることが分かりました。
同時に差分のあるインデックスにアクセスする為のトークンも取得する事ができます。

{
    "ChangedBlocks": [
        {
            "BlockIndex": 4,
            "FirstBlockToken": "AAABAVahm9SO60Dyi0ORySzn2ZjGjW/KN3uygGlS0QOYWesbzBbDnX2dGpmC",
            "SecondBlockToken": "AAABAQdzxhw0rVV6PNmsfo/YRIxo9JPR85XxPf1BLjg0Hec6pygYr6laE1p0"
        },
        {
            "BlockIndex": 26,
            "FirstBlockToken": "AAABAbYSiZvJ0/R9tz8suI8dSzecLjN4kkazK8inFXVintPkdaVFLfCMQsKe",
            "SecondBlockToken": "AAABAaYvPax6mv+iGWLdTUjQtFWouQ7Dqz6nSD9L+CbXnvpkswA6iDID523d"
        },

(中略)

        },
        {
            "BlockIndex": 49,
            "FirstBlockToken": "AAABAZ9CTuQtUvp/dXqRWw4d07eOgTZ3jvn6hiW30W9duM8MiMw6yQayzF2cx",
            "SecondBlockToken": "AAABATgWZC0XcFwUKvTJbUXMiSPg59KVxJGL+BWBClkw6spzCxJVqDVaTskJ"
        }
    ],
    "ExpiryTime": 1576053203.905,
    "VolumeSize": 8,
    "BlockSize": 524288,
    "NextToken": "AAADARqElNng/sV98CYk/bJDCXeLJmLJHnNSkHvLzVaO0zsPH/QM3Bi3zF//O6Mdi/BbJarBnp8h"
}       

スナップショットのデータの中身を取得する

それでは、実際にデータの中身を見てみたいと思います。コマンドはget-snapshot-blockです。
取得したい対象のスナップショットとそのインデックス番号、トークンを指定します。
また、出力先に指定したパスのファイルに取得データが保存されます。今回は/tmp/outputというファイルになります。

aws ebs get-snapshot-block --region ap-northeast-1 \
--snapshot-id snap-yyyyyyyyyyyyyyy \
--block-index 43 \
--block-token AAABAaYvPax6mv+iGWLdTUjQtFWouQ7Dqz6nSD9L+CbXnvpkswA6iDID523d /tmp/ouput

このファイルはバイナリファイルなので、stringsコマンドで中身を見てみると、たしかにログの出力をスナップショット内のデータとして確認することができました。

いくつか見ていくと、今回は「ブロックインデックス43」に「/var/log/messagesへ意図的に出力した内容」を確認することができました。

$ string /tmp/output

下記は該当箇所の抜粋になります。
試したインスタンスは「Amazon Linux 2」だったので、下記はjournaldのメタデータのようです。

_TRANSPORT=syslog
_TRANSPORT
PRIORITY=5
PRIORITY
SYSLOG_FACILITY=1
zyTp
SYSLOG_FACILITY
SYSLOG_IDENTIFIER=SnapshotTest
SYSLOG_IDENTIFIER
)J@l
_PID=3071
_PID
_COMM=logger
_SOURCE_REALTIME_TIMESTAMP=1575440086276968
_SOURCE_REALTIME_TIMESTAMP
_HOSTNAME=ip-10-0-0-165.ap-northeast-1.compute.internal
MESSAGE=mymessage

異なるスナップショットのデータ差分を確認する

最後に同じブロックインデックスでこのデータの有無を比較してみたいと思います。

対象のインデックスは先程の「43」のブロックを使いたいと思います。比較対象の2つのスナップショットから"BlockIndex": 43FirstBlockTokenSecondBlockTokenをそれぞれ指定して変更前後のデータを取得します。

データ変更前のスナップショット「snap-xxxxxxxxxxxxxxx」から「インデックス43」のデータを取得

aws ebs get-snapshot-block --region ap-northeast-1 \
--snapshot-id snap-xxxxxxxxxxxxxxx \
--block-index 43 \
--block-token AAABAZ9CTuQtUvp/dXqRWw4d07eOgTZ3jvn6hiW30W9duM8MiMw6yQayzF2cx /tmp/
first_block_data

データ変更後のスナップショット「snap-yyyyyyyyyyyyyyy」から「インデックス43」のデータを取得

aws ebs get-snapshot-block --region ap-northeast-1 \
--snapshot-id snap-yyyyyyyyyyyyyyy \
--block-index 43 \
--block-token AAABAQdzxhw0rVV6PNmsfo/YRIxo9JPR85XxPf1BLjg0Hec6pygYr6laE1p0 /tmp/
second_block_data

それぞれのデータを比較しやすいようにテキストデータに変換してdiffコマンドで比較してみました。
たしかに変更後のスナップショットに追記したデータ内容が入っていることを確認できました。

--- first_block_data.txt        2019-12-04 16:41:03.000000000 +0900
+++ second_block_data.txt       2019-12-04 16:38:47.000000000 +0900
@@ -1,2032 +1,49 @@
-[nCv
-5`KS
-:,x)
->%-C
-w0w2

(中略)

+SYSLOG_FACILITY
+SYSLOG_IDENTIFIER=SnapshotTest
+)J@l
+MESSAGE
+_PID=3071
+_PID
+_UID=1000
+_UID
+_GID=1000
+_GID
+|n[$
+_COMM=logger
+_COMM
+_AUDIT_LOGINUID=1000
+_AUDIT_LOGINUID
+_SYSTEMD_CGROUP=/
+_SYSTEMD_CGROUP
+_SOURCE_REALTIME_TIMESTAMP=1575440086276968
+_SOURCE_REALTIME_TIMESTAMP
+_HOSTNAME=ip-10-0-0-165.ap-northeast-1.compute.internal
+_HOSTNAME
+)J@l
+|n[$h
+MESSAGE=mymessage

最後に

これまでのようにEC2とEBSを別途用意することなく、簡単にスナップショットの中身を直接比較できるようになったことが分かりました。
自分なりに確認できる内容をまとめてみましたが、更に活用できる方法などがないか検討していきたいと思います。

参考リンク

以上です。