EC2インスタンス(EBS)のリストア手順をAMI ID指定で作成・出力する内製スクリプトのご紹介

まずはこちらをご覧下さい。

よく見慣れた AWS CLI のコマンドラインがずらずらと並んでいますが、こちらはとある作業の手順書になります。今回この、EBS を差し替えることで EC2 をバックアップスナップショットからリストアする手順の手順書を作成してくれるスクリプト をご紹介したいと思います。

背景

一度起動した EC2 をメンテナンスしながら長く使用するような運用を行う場合、作業前に EC2 (EBS) のバックアップ(スナップショット)を取得しておいて、万一の時にはそこからリストアする、という運用はよく行われています。スナップショットを取得する際には、ある EC2 に関連する EBS に対してまるごと実施するために、AMI 作成を使用することも多いです。

そしてその「万が一」が起こった場合はそのバックアップから戻すわけですが、長く使い続けているということは、EC2 インスタンス ID やプライベート IP アドレスが変わることも出来れば避けたい場合があるはず。そういう時には下記のブログで紹介されているような、「スナップショットから作成した EBS ボリュームと差し替える」手順が有効です。

EBSスナップショットからのレストア

ただ、その手順はそこまで単純ではありません。ざっくりと下記のような手順が必要になります。

  • 作成した AMI から、取得された EBS スナップショットの ID を取得する
  • 該当のスナップショットからボリュームを作成する
  • 作成された EBS ボリュームに必要なタグを付与する
  • EC2インスタンスを停止、EBS を全て差し替え、起動

もちろんそれぞれの手順ごとに、確認作業が発生します。マネジメントコンソールにて作業する場合には EC2、AMI、ボリューム、スナップショットと複数のコンソールを行き来しないとなりませんし、ひとつの EC2 に複数のボリュームがアタッチされていた場合は混乱しがちです。

しかも、この手順が必要になるのは「万が一」の場合です。すばやく、かつミスがないように行わなければなりませんが、一方でバックアップの AMI は 作業の開始 時点で作成されるため、そのときにならないと AMI ID やスナップショット ID も確定しません。事前に手順書化したりスクリプトとして作り込んでおくことは困難ですし、動的に取得するようにするとコマンドが長く複雑になって見通しが悪くなります。

とはいえ職業柄、この手の作業は繰り返し備えることが多いので、EC2 インスタンス ID と AMI ID から、作業で必要な AWS CLI のコマンドライン列を出力するシェルスクリプトを作って個人的に使っていました。部内で同僚に話したところ「欲しい」という声があったので、ブログで公開します。

なお「そこまでやるならリストア作業を自動化するスクリプトとして作り込んでおけよ」という話は当然あると思うのですが、「万が一のときのリストア作業」という何より確実性が求められる作業で使うものなので、いろいろ勘案してあえてこのような仕様にしました。

理由としては、弊社のオペレーションチームのメンバーであれば全員 AWS CLI には習熟してますから、コマンドラインの妥当性含めて実行時にダブルチェックを頼める、というのが大きいです。

出力 = 手順書

EC2 インスタンス ID と AMI ID を引数として指定すると、一連の AWS CLI コマンドラインがだらだらと出力されます。そのコマンドラインを順に実行していくと、その AMI に含まれるスナップショットを EC2 インスタンスに付け替えて起動されることになります。

(再掲)

出力例の全体は こちら に貼りましたので、併せてご参照下さい。

こちらの例は、EBS が二つ(/dev/xvda/dev/xvdf)アタッチされている EC2 について実行したものです。アタッチされている EBS の数や付与されているタグを自動的に認識して手順書化するようになっています。

また、実行する行とコメントが見分け付きやすいよう、ターミナルに出力する時に色分けもしています。

それから AMI ID が指定されない場合は、AMI IDならびにスナップショット ID をプレースホルダ(「***」)にした状態で出力します。事前の手順はこちらで作っておき、必要が生じたらその場で入力する、というやり方も出来るようにしてあります。

注意

公開したスクリプト、およびそのスクリプトが生成する手順については、一切の保証ができません。また、このスクリプトが提示したコマンドラインを実行した際に生じた結果についても責任をもてるものではありません。あくまでサンプルとして、予めご了承の上ダウンロードしてお使い下さい。

このスクリプト自体は AWS に対して何か変更が伴うようなコマンドを発行したりはしませんが、その性格上、出力されたコマンドラインには stop-instancesdetach-volume など、既存の環境に影響を与えるものが含まれますし、create-volume などコストが発生するこのもあります。

それらの行をコピペし実行する前に、必ず そのコマンドが妥当か、慎重にチェックした上で実行下さい。

使い方

中身の説明の前に、使い方を紹介します。スクリプトは下記のようにして実行します。

usage: show-manual_restore-from-ami.sh <EC2 Instance ID> [<AMI ID>]

先にお話ししたとおり、引数にはインスタンスIDと AMI ID を指定します( AMI ID はオプション)。このとき、EC2 にアタッチされているボリュームの情報と AMI に含まれるボリューム情報を比較して、差異があれば先に進まないようになっています。誤った AMI からリストアしないような簡易的なチェックとなっています。また当然、存在しない ID を指定した場合も終了します。

あとは、表示(出力)されたコマンド列を順に(コメントを除いて概ね空行ごとに)コピペして実行していくだけです。あるいはリダイレクトなどの方法でファイルに保存し活用してください。

ただし当然ながら、入力された ID の妥当性のスクリプトでのチェックは限度があります。このスクリプトならびに出力結果が必要になるのは、緊急時など慌ただしい時が多いと思うので、出力されたコマンドラインが妥当かどうか、要は 間違ったインスタンス ID や AMI ID を指定していないか、逐次確認しながら実行するようにしてください。

スクリプトについて

このスクリプト「show-manual_restore-from-ami.sh」のコードは Gist で公開しました。前述したように出力例(手順書)と、その手順を順番に実行した際の出力も載せているので参考にして下さい。

スクリプトは内部で aws コマンド(AWS CLI)と jq コマンドを使用しています。また出力の色分けのために ruby のワンライナを使っていますので、これらが利用できる環境で実行して下さい。

またスクリプトからは、EC2 インスタンスや AMI、EBS の情報を取得するために describe 系のコマンドを発行しています。管理ポリシーで言えば AmazonEC2ReadOnlyAccess、最低でも ec2:Describe* の権限がある状態で実行して下さい。

もちろん前述したとおり、出力された手順を実行するためにはそれ相応の権限が必要です。

スクリプト自体にはあまり工夫らしい工夫はありませんが、下記のところには気をつけたつもりです。

  • AMI ID が無指定でも手順書を出力する
  • EBS を作成する AZ やボリュームタイプは、意識しなくて済むよう自動で取得(127行目、128行目)
  • ターミナル上で見た際にわかりやすく色分けする(222行目〜228行目、233行目)
  • とはいえリダイレクトなどでファイルに保存するときには、余計なエスケープシーケンスは付けない(223行目)
  • スクリプト上でも手順の流れが認識しやすくなる・見通しが良くなるよう、ビュー(230行目〜)とロジック(103行目〜230行目)を分ける
  • AWS CLI コマンドを発行する量をへらすため、各種 describe系コマンドの実行結果は JSON で保存し(49行目〜101行目)、jq で必要な情報を切り出して使用する
  • EBS に付与するタグは、Name タグが最初にくるように(174行目〜184行目)
  • コードは shfmt でフォーマット(インデントは 2)
  • 特定の環境によらず汎用的に使えるものにする

また出力される手順についても、下記の点を工夫しました。

  • 確認などで出力される内容は、なるべく見やすく jqxargs で整形する
  • コマンドラインが長くなりすぎないようにバランスを取る
  • コマンド列が小文字になるので、変数名は大文字を使い判別しやすくする

とはいえ、自分以外が使うことをあまり考慮していなかったので、今後下記のようなところは検討していきたいと考えてます。

  • 出力される内容で jq を使わない(前提にしない)手順にする
  • もとの EBS と作成した EBS の比較をもっと分かりやすく表示する

さいごに

例えばこれが自社運用の環境で使うものであれば、実行までするスクリプトなり自動化なりを作り込むのも普通にありなのですが、お客様の環境を扱う以上は何より確実性が必要と言うことで、こういうスクリプトを整備していたりします。

実際にコマンドを発行しないので、作る側もそこまでエラーチェックに気を遣わずに済み、実作業の効率を上げる手段として効果が見込めるかなと思ってます。もしよければお使い下さい(ただし、事前の検証をお忘れ無く)。