Amazon Redshift: AWS CLIでスナップショット取得&リストアを効率化するPythonスクリプト

2016.10.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

小ネタです。

Amazon Redshiftはクラスタの"停止"が行えないため、一旦クラスタのスナップショットを取得しておき、取得後に削除、そして復旧の際には取得したスナップショットからのリストア作業を行って起動し直す、という手順が必要となります。ある程度環境が整って来た段階であればそこまで頻度多く削除(with スナップショット取得)・起動(リストア)の機会は無いかなとは思いますが(データ量が増えてクラスタ規模も大きくなるとそもそもリストアに時間が掛かるため運用的には立ち上げっぱなしというケースが大半です)、動作検証時や開発作業用に一時的にクラスタを立ち上げて終わったら落とす、というケースは割と良くあるケースかと思います。

当エントリではその際に使えそうな『スナップショットを取得の後、クラスタの削除』及び『直近最新の手動スナップショットからのリストア』をコマンド一発で行えるスクリプトを作ってみたので、そのご紹介をしたいと思います。

利用に際してのルール

当エントリでご紹介するスクリプトは、簡単ではありますが以下のルールで想定したものとします。

  • スナップショットの名前は『任意の名前』+『実行時のタイムスタンプ情報』とする
  • クラスタリストアに用いるスナップショットは上記ルールで取得した手動スナップショットの作成日時が最新のものを用いる事とする

また、実行に際してはPython及びAWS CLIが実行可能となっている必要があります。

$ python --version
Python 2.7.10
$ aws --version
aws-cli/1.10.50 Python/2.7.10 Darwin/14.5.0 botocore/1.4.40

スナップショットを取得の後、クラスタを削除するPythonスクリプト

1つ目のスクリプトが『スナップショットを取得の後、クラスタを削除するPythonスクリプト』となります。事前に設定しておくのは『クラスタ名(CLUSTER_NAME)』と『スナップショット名『SNAPSHOT_TIMESTAMP』の2つとなります。

delete-redshift-cluster-with-final-snapshot.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from datetime import datetime
import commands

CLUSTER_NAME = "cm-redshift"
SNAPSHOT_PREFIX = "cm-redshift-snapshot"
SNAPSHOT_TIMESTAMP = datetime.now().strftime('%Y%m%d-%H%M%S')

print "# Snapshot Prefix: " + SNAPSHOT_PREFIX
print "# Snapshot Created Timestamp: " + SNAPSHOT_TIMESTAMP

# 実行時タイムスタンプと所定の名称でファイナルスナップショットを取得し、クラスタを削除
command_str = "aws redshift delete-cluster --cluster-identifier " + CLUSTER_NAME + " --final-cluster-snapshot-identifier " + SNAPSHOT_PREFIX + "-" + SNAPSHOT_TIMESTAMP
print "# Final Snapshot Command: " + command_str

check = commands.getoutput(command_str)
print check

実行イメージが以下となります。今回実行した内容だと、スナップショットの名前は『cm-redshift-snapshot-20161012-151447』という名前で生成される形となります。

$ python delete-redshift-cluster-with-final-snapshot.py 
# Snapshot Prefix: cm-redshift-snapshot
# Snapshot Created Timestamp: 20161012-151447
# Final Snapshot Command: aws redshift delete-cluster --cluster-identifier cm-redshift --final-cluster-snapshot-identifier cm-redshift-snapshot-20161012-151447
{
    "Cluster": {
        "PubliclyAccessible": true, 
        "MasterUsername": "root", 
        "VpcSecurityGroups": [
       :
       :
        "AllowVersionUpgrade": true, 
        "ClusterCreateTime": "2016-05-08T14:45:40.784Z", 
        :
        "ClusterIdentifier": "cm-redshift", 
        :
        "ClusterStatus": "final-snapshot"
    }
}
$

処理完了後のスナップショットの一覧です。処理前にも同じ命名ルールで幾つか取得していたものも併せて並んでいます。

redshift-snapshot-lists_01

直近最新の手動スナップショットからのリストアを行うPythonスクリプト

2つ目のスクリプトが『直近最新の手動スナップショットからのリストアを行うPythonスクリプト』となります。AWS CLIを使って以下のコマンドを実行すると、手動(manual)スナップショットで得られる最新日時(判定に使ったのはClusterCreateTime)のスナップショットの名称を得る事が出来ます。このAWS CLIコマンドを使って情報を連携します。

$ aws redshift describe-cluster-snapshots | \
  jq '.Snapshots[]' | \
  jq '{ClusterCreateTime,SnapshotIdentifier,SnapshotType}' | \
  jq '. | select(.SnapshotType == "manual")' | \
  jq '.' --slurp | \
  jq 'sort_by(.ClusterCreateTime)' | \
  jq 'reverse' | \
  jq '.[0].SnapshotIdentifier'
"cm-redshift-snapshot-20161012-151447"

上記内容を踏まえたリストア用Pythonスクリプトの内容が以下となります。14〜27行目の設定項目については適宜必要な値を事前に埋め込んで置いてください。基本、任意のクラスタの設定値を固定で埋め込んでおいて削除〜起動を繰り返すイメージで当スクリプトを作っているのでこのような形にしています。IAM Rolesの箇所については、対象ロールのARN記法の値で記載する必要があります。(スペース区切りで複数設定する事が可能です)

restore-redshift-latest-snapshot.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from datetime import datetime
import commands

# 現行最新の手動スナップショットの名称を取得
command_latest_snapshot_name = "aws redshift describe-cluster-snapshots | jq '.Snapshots[]' | jq '{ClusterCreateTime,SnapshotIdentifier,SnapshotType}' | jq '. | select(.SnapshotType == \"manual\")' | jq '.' --slurp | jq 'sort_by(.ClusterCreateTime)' | jq 'reverse' | jq '.[0].SnapshotIdentifier'"

LATEST_SNAPSHOT_NAME = commands.getoutput(command_latest_snapshot_name)
print "# Latest Snapshot Name: " + LATEST_SNAPSHOT_NAME

# スナップショットリストアに必要なパラメータを用意
CLUSTER_IDENTIFIER = "cm-redshift"
SNAPSHOT_IDENTIFIER = LATEST_SNAPSHOT_NAME
PORT = "5439"
AVAILAVILITY_ZONE = "us-east-1a"
ALLOW_VERSION_UPGRADE = "--allow-version-upgrade"
CLUSTER_SUBNET_GROUP_NAME = "xxxxxxxx-subnet-group"
PUBLICLY_ACCESSIBLE = "--publicly-accessible"
ELASTIC_IP = 'xx.xxx.xxx.xx'
CLUSTER_PARAMETER_GROUP_NAME = "cluster-parametergroup-xxxxxxxxxxxxx"
VPC_SECURITY_GROUP_IDS = "sg-xxxxxxxxxxxx"
PREFERRED_MAINTENANCE_WINDOW = "thu:11:00-thu:12:00"
AUTOMATED_SNAPSHOT_RETENTION_PERIOD = '14'
NODE_TYPE = "dc1.large"
IAM_ROLES = "arn:aws:iam::999999999999:role/xxxx arn:aws:iam::999999999999:role/yyyyyyyyyy arn:aws:iam::999999999999:role/zzzzzzz"

# コマンド構築
command_restore = "aws redshift restore-from-cluster-snapshot " + \
  " --cluster-identifier " + CLUSTER_IDENTIFIER + \
  " --snapshot-identifier " + SNAPSHOT_IDENTIFIER + \
  " --port " + PORT + \
  " --availability-zone " + AVAILAVILITY_ZONE + \
  " " + ALLOW_VERSION_UPGRADE + \
  " --cluster-subnet-group-name " + CLUSTER_SUBNET_GROUP_NAME + \
  " " + PUBLICLY_ACCESSIBLE + \
  " --elastic-ip " + ELASTIC_IP + " --cluster-parameter-group-name " + CLUSTER_PARAMETER_GROUP_NAME + \
  " --vpc-security-group-ids " + VPC_SECURITY_GROUP_IDS + \
  " --preferred-maintenance-window " + PREFERRED_MAINTENANCE_WINDOW + \
  " --iam-roles " + IAM_ROLES + \
  " --automated-snapshot-retention-period " + AUTOMATED_SNAPSHOT_RETENTION_PERIOD + " --node-type " + NODE_TYPE

print "# Snapshot Restore Command: " + command_restore

# コマンド実行
status = commands.getoutput(command_restore)
print status

以下の形で実行する事でAWS CLIコマンドでリストア実行した際の出力結果が表示され、クラスタのリストア作業が始まります。クラスタのリストアについては規模にも拠るかと思いますので適宜ご確認ください。

$ python restore-redshift-latest-snapshot.py

ちなみに付随する設定情報として、イベント通知の情報は『status:no-permission』となってしまっていました。

redshift-snapshot-lists_02

ですので一旦Redshiftに紐付くイベント通知を削除の後、再作成して復旧。

$ aws redshift delete-event-subscription --subscription-name cm-redshift-event-subscription
$ aws redshift create-event-subscription \
  --subscription-name cm-redshift-event-subscription \
  --sns-topic-arn arn:aws:sns:us-east-1:999999999999:topic-xxxxxxxxxxx

また、監査ログ設定についてもリストアの段階で設定が解除されてしまってましたので、

redshift-snapshot-lists_03

こちらもAWS CLIで設定連携を行う処理を実施しました。

$ aws redshift enable-logging \
  --cluster-identifier cm-redshift \
  --bucket-name cm-redshift-auditlog-xxxxx \
  --s3-key-prefix cm-auditlog-yyyyy
{
    "LoggingEnabled": true, 
    "S3KeyPrefix": "cm-auditlog-yyyyy/", 
    "BucketName": "cm-redshift-auditlog-xxxxx"
}

まとめ

Redshiftのスナップショット取得&リストアをプログラム一発で効率良く行うスクリプトに関するご紹介でした。冒頭述べた様に、利用ケースはそこまで広くは無いかと思いますが、何やかんやで手間となるこの手の作業、このスクリプトで少しでも効率化が実現出来るのであれば幸いです。こちらからは以上です。