AWS CLIを利用したRDSの起動停止スクリプト(検証環境用2017年1月版)
西澤です。検証環境のRDSの利用料金を節約する為に、みんな大好きAWS CLIを利用した停止/再開相当のスクリプトを用意した話を以前に紹介しました。
こちらを最新化する必要があったので、2017年1月時点での更新版を記録しておこうと思います。ちなみに今回はRedshiftについては触れません。
前提
執筆時点のRDSにおいて、検証環境等の常時起動が不要なRDS環境を、少しでも安く利用する為に用意したスクリプトをご紹介し、同じような仕組みを準備したいと考えている方の参考にしていただければと公開しているものになります。また、スケジュール設定により自動実行とするものではなく、手動でのスクリプト実行を想定したものですので、停止(削除)時には、確認プロンプトが返されるようにしました。当然ですが、本番環境での動作を保証するような類のものではありませんのでご了承ください。
RDS Oracleの起動停止スクリプト
前回の記事を執筆した時点では、RDSスナップショットからのリストア時にSecurity Groupの指定ができていたのですが、botocore1.2.7になったタイミングから指定不可となっていました。下記記事でもご指摘をいただいていましたが、記載の修正が遅れましたことをお詫びいたします(前回の記事内に注釈を加えました)。
今回はこちらを踏まえて修正版となります。下記はRDS Oracleを利用して試したものとなる為、他のDBエンジンではオプションの修正が必要となるかもしれません。
#!/bin/bash set -e ### 環境に合わせて変数を指定 export AWS_DEFAULT_REGION=ap-northeast-1 RDS_IDENTIFIER=myrdsinstance RDS_INSTANCE_CLASS=db.t2.micro AZ=ap-northeast-1 DB_PARAMTER_GROUP=mydbparamgroup DB_SUBNET_GROUP=mydbsubnetgroup DB_OPTION_GROUP_NAME=mydboptiongroup STORAGE_TYPE=gp2 VPC_SECURITY_GROUP="sg-xxxxxxxx" ### RDSインスタンスのステータスを表示 function rds_status() { aws rds describe-db-instances \ --db-instance-identifier ${RDS_IDENTIFIER} \ --query "DBInstances[].{DBInstanceIdentifier:DBInstanceIdentifier,DBInstanceStatus:DBInstanceStatus}" \ --output table } ### RDSインスタンスがavailableになるまでひらすら待つ(タイムアウト指定はないので要注意) function rds_wait_available() { while : do RDS_STATUS=$(aws rds describe-db-instances \ --db-instance-identifier ${RDS_IDENTIFIER} \ --query "DBInstances[].DBInstanceStatus" \ --output text) if [ "${RDS_STATUS}" != "available" ]; then echo "$(date +'[%Y/%m/%d %H:%M:%S]') Waiting for RDS Instance=${RDS_IDENTIFIER} is to be in available state..." sleep 10 else break fi done } ### 引数指定で分岐 case $1 in start) ### 最新のRDS手動スナップショットを取得 LAST_RDS_SNAPSHOT=$(aws rds describe-db-snapshots \ --snapshot-type manual \ --query "reverse(sort_by(DBSnapshots,&SnapshotCreateTime))[?DBInstanceIdentifier==\`${RDS_IDENTIFIER}\`]|[0].[DBSnapshotIdentifier]" \ --output text) ### 取得したRDSスナップショットからリストア、--no-multi-az、--no-publicly-accessibleは静的に指定 aws rds restore-db-instance-from-db-snapshot \ --db-instance-identifier ${RDS_IDENTIFIER} \ --db-snapshot-identifier ${LAST_RDS_SNAPSHOT} \ --db-instance-class ${RDS_INSTANCE_CLASS} \ --availability-zone ${AZ} \ --db-subnet-group-name ${DB_SUBNET_GROUP} \ --no-multi-az \ --no-publicly-accessible \ --option-group-name ${DB_OPTION_GROUP_NAME} \ --storage-type ${STORAGE_TYPE} ### リストア完了まで待つ、10分程度かかることがある rds_wait_available ### DBパラメータグループ、VPC Security Groupを修正 aws rds modify-db-instance \ --db-instance-identifier ${RDS_IDENTIFIER} \ --db-parameter-group-name ${DB_PARAMTER_GROUP} \ --vpc-security-group-ids ${VPC_SECURITY_GROUP} \ --apply-immediately ### 設定変更反映の為、RDSインスタンスをリブート aws rds reboot-db-instance \ --db-instance-identifier ${RDS_IDENTIFIER} ### RDSインスタンスのステータスを表示 rds_status ;; stop) ### 停止(削除)確認プロンプトを返す echo -n "Are you sure you are going to stop RDS Instance: ${RDS_IDENTIFIER}? [y/n]: " read ANS case $ANS in "Y" | "y" | "yes" | "Yes" | "YES" ) echo "RDS Instnace: ${RDS_IDENTIFIER} is going to stop." ;; * ) echo "Operation is cancelled." exit 1 ;; esac ### 取得するRDSスナップショット名を指定 RDS_SNAPSHOT_NAME=${RDS_IDENTIFIER}-$(date +'%Y%m%d-%H%M%S') ### 最終スナップショットを取得しつつ、RDSインスタンスを停止(削除) aws rds delete-db-instance \ --db-instance-identifier ${RDS_IDENTIFIER} \ --no-skip-final-snapshot \ --final-db-snapshot-identifier ${RDS_SNAPSHOT_NAME} ### RDSインスタンスのステータスを表示 rds_status ;; status) ### RDSインスタンスのステータスを表示 rds_status ;; *) ### 引数誤り echo "Usage: $0 {start|stop|status}" ;; esac
静的に指定しているオプションやスキップしているオプションがありますので、ご利用の際には必ず公式ドキュメントをご確認ください。
RDS Auroraの起動停止スクリプト
Auroraの場合には、インスタンス1台の構成であってもDBクラスタとしての操作が必要となる為、必要な処理がかなり複雑になりました。RDSインスタンスはクラスタのコンピューティングリソースとしてを用意した上で、そのクラスタ内で操作するインスタンスを操作するということがよく理解でき、個人的には結果的にとても勉強になりました。PostgreSQL互換のAuroraが正式に利用できるようになると、EngineやEngineVersion指定が必要となる可能性があります。
#!/bin/bash set -e ### 環境に合わせて変数を指定 export AWS_DEFAULT_REGION=ap-northeast-1 RDS_IDENTIFIER=myaurora DB_CLUSTER_IDENTIFIER=myauroracluster RDS_INSTANCE_CLASS=db.t2.medium AZ=ap-northeast-1a DB_PARAMTER_GROUP=mydbparamgroup DB_CLUSTER_PARAMETER_GROUP=mydbclusterparamgroup DB_SUBNET_GROUP=mydbsubnetgroup DB_OPTION_GROUP_NAME=mydboptiongroup VPC_SECURITY_GROUP="sg-xxxxxxxx" ### Auroraクラスタのステータスを表示 function aurora_status() { aws rds describe-db-clusters \ --db-cluster-identifier ${DB_CLUSTER_IDENTIFIER} \ --query "DBClusters[].{DBClusterIdentifier:DBClusterIdentifier,Status:Status}" \ --output table aws rds describe-db-instances \ --db-instance-identifier ${RDS_IDENTIFIER} \ --query "DBInstances[].{DBInstanceIdentifier:DBInstanceIdentifier,DBInstanceStatus:DBInstanceStatus}" \ --output table } ### Auroraクラスタがavailableになるまでひたすら待つ(タイムアウト指定はないので要注意) function aurora_cluster_wait_available() { while : do AURORA_CLUSTER_STATUS=$(aws rds describe-db-clusters \ --db-cluster-identifier ${DB_CLUSTER_IDENTIFIER} \ --query "DBClusters[].Status" \ --output text) if [ "${AURORA_CLUSTER_STATUS}" != "available" ]; then echo "$(date +'[%Y/%m/%d %H:%M:%S]') Waiting for Aurora Cluster=${DB_CLUSTER_IDENTIFIER} to be in available state..." sleep 10 else break fi done } ### Auroraクラスタメンバーとして起動したRDSインスタンスがavailableになるまでひたすら待つ(タイムアウト指定はないので要注意) function rds_wait_available() { while : do RDS_STATUS=$(aws rds describe-db-instances \ --db-instance-identifier ${RDS_IDENTIFIER} \ --query "DBInstances[].DBInstanceStatus" \ --output text) if [ "${RDS_STATUS}" != "available" ]; then echo "$(date +'[%Y/%m/%d %H:%M:%S]') Waiting for RDS Instance=${RDS_IDENTIFIER} to be in available state..." sleep 10 else break fi done } ### Auroraクラスタ内のメンバーが0になるまでひたすら待つ(タイムアウト指定はないので要注意) function aurora_cluster_members_null() { while : do AURORA_CLUSTER_MEMBERS=$(aws rds describe-db-clusters \ --db-cluster-identifier ${DB_CLUSTER_IDENTIFIER} \ --query "Clusters[].DBClusterMembers[]") if [ "${AURORA_CLUSTER_MEMBERS}" != "null" ]; then echo "$(date +'[%Y/%m/%d %H:%M:%S]') Waiting for Members fo Aurora Cluster=${DB_CLUSTER_IDENTIFIER} to be null..." sleep 10 else break fi done } ### 引数指定で分岐 case $1 in start) ### 最新のAuroraクラスタ手動スナップショットを取得 LAST_AURORA_CLUSTER_SNAPSHOT=$(aws rds describe-db-cluster-snapshots \ --snapshot-type manual \ --query "reverse(sort_by(DBClusterSnapshots,&SnapshotCreateTime))[?DBClusterIdentifier==\`${DB_CLUSTER_IDENTIFIER}\`]|[0].[DBClusterSnapshotIdentifier]" \ --output text) ### 取得したAuroraクラスタスナップショットからリストア、--engineは静的に指定 aws rds restore-db-cluster-from-snapshot \ --db-cluster-identifier ${DB_CLUSTER_IDENTIFIER} \ --snapshot-identifier ${LAST_AURORA_CLUSTER_SNAPSHOT} \ --engine "aurora" \ --db-subnet-group-name ${DB_SUBNET_GROUP} \ --vpc-security-group-ids "${VPC_SECURITY_GROUP}" ### リストア完了まで待つ、30分以上かかるケースもありました aurora_cluster_wait_available ### DBクラスタパラメータグループを修正 aws rds modify-db-cluster \ --db-cluster-identifier ${DB_CLUSTER_IDENTIFIER} \ --db-cluster-parameter-group-name ${DB_CLUSTER_PARAMETER_GROUP} ### クラスタメンバーとしてRDSインスタンスを起動、--engine、--no-multi-az、--no-publicly-accessibleは静的に指定 aws rds create-db-instance \ --db-instance-identifier ${RDS_IDENTIFIER} \ --db-instance-class ${RDS_INSTANCE_CLASS} \ --engine aurora \ --availability-zone ${AZ} \ --db-parameter-group-name ${DB_PARAMTER_GROUP} \ --no-multi-az \ --no-publicly-accessible \ --option-group-name ${DB_OPTION_GROUP_NAME} \ --db-cluster-identifier ${DB_CLUSTER_IDENTIFIER} ### メンバーサーバがavailableになるまで待つ rds_wait_available ### Auroraクラスタのステータスを表示 aurora_status ;; stop) ### 停止(削除)確認プロンプトを返す echo -n "Are you sure you are going to stop Aurora Cluster: ${DB_CLUSTER_IDENTIFIER}? [y/n]: " read ANS case $ANS in "Y" | "y" | "yes" | "Yes" | "YES" ) echo "Aurora Cluster: ${DB_CLUSTER_IDENTIFIER} is going to stop." ;; * ) echo "Operation is cancelled." exit 1 ;; esac ### クラスタメンバーであるRDSインスタンスを削除 aws rds delete-db-instance \ --db-instance-identifier ${RDS_IDENTIFIER} \ --skip-final-snapshot ### クラスタメンバーが0になるまで待つ aurora_cluster_members_null ### 取得するクラスタスナップショット名を指定 AURORA_CLUSTER_SNAPSHOT_NAME=${DB_CLUSTER_IDENTIFIER}-$(date +'%Y%m%d-%H%M%S') ### 最終スナップショットを取得しつつ、Auroraクラスタを停止(削除) aws rds delete-db-cluster \ --db-cluster-identifier ${DB_CLUSTER_IDENTIFIER} \ --no-skip-final-snapshot \ --final-db-snapshot-identifier ${AURORA_CLUSTER_SNAPSHOT_NAME} ### Auroraクラスタのステータスを表示 aurora_status ;; status) ### Auroraクラスタのステータスを表示 aurora_status ;; *) ### 引数誤り echo "Usage: $0 {start|stop|status}" ;; esac
同様に、静的に指定しているオプションやスキップしているオプションがありますので、ご利用の際には必ず公式ドキュメントをご確認ください。
まとめ
これまでAuroraの操作をAPIから行ったことが無かったのですが、クラスタメンバーの削除は--skip-final-snapshot
で行って、クラスタ削除のところで--no-skip-final-snapshot
を指定するところから、データの管理はクラスタメンバーで行われていないことが納得できました。特にAuroraの操作が少々複雑になってしまったのですが、AWS CLIでAWSを操作することで、実体の理解につながる場合がよくありますので、色々と触って試してみていただければと思います。
どこかの誰かのお役に立てば嬉しいです。