AWS EC2 のスナップショットからインスタンスのボリュームを復元する

# はじめに
AWS EC2 のスナップショットからインスタンスのボリューム (volume) を復元して起動させるまでの手順の覚書です。

これは、インスタンスのボリューム (volume) が1つのみのものなのでご注意ください。

昔のラックに収められていたサーバの HDD を差し替えをした人なら、なんとなく感覚がわかるんじゃないか(笑
と思います。

このスクリプトを実行するときは事前に、「インスタンスID」と「スナップショットID」を取得しておく必要があるのでご注意ください。


簡単な手順は以下になります。

1. インスタンスを停止
1. インスタンスに割り当たっている root デバイス名を取得
1. 上記の root デバイス名のボリューム (volume) IDを取得
1. インスタンスの root デバイスをデタッチ
1. スナップショットからボリューム (volume) を復元
1. 復元したボリューム (volume) の ID を取得
1. インスタンスの root デバイスにボリューム (volume) をアタッチ
1. インスタンスを開始


# 実際の実行

# インスタンスの停止
まずは、復元するインスタンスを停止します。
```bash
aws ec2 stop-instances --instance-ids=＜＜＜インスタンスID＞＞＞
```

## インスタンスに割り当たっている root デバイス名を取得
インスタンスに割り当たっている root デバイス名を取得します
※) 物理的な HDD と思えばいいかと

```bash
aws ec2 describe-instances \
    --instance-ids=＜＜＜インスタンスID＞＞＞ \
    --query "Reservations[].Instances[].RootDeviceName"   --output text
```

おそらく以下のような値が返ってくるかと思います(違う可能性もあります)

```bash
/dev/sda1
```

## インスタンスのボリュームID を取得
root デバイスに割りあっているボリューム (volume) ID を取得します。
※) まぁ、HDD でいくとパーティションみたいなもんです。ここでは 1HDD = 1ボリューム(volume) にして簡単にしています。

```bash
`aws ec2 describe-instances \
    --instance-id ＜＜＜インスタンスID＞＞＞\
    --query "Reservations[].Instances[].BlockDeviceMappings[?DeviceName==\＜＜＜上記で出力された root デバイス名 (/dev/sda1 とか)＞＞＞\`].Ebs.VolumeId"   --output text`
```

おそらく、以下のような値が返ってくるかと思います(xxxx は半角英数字)
```bash
vol-xxxxxxxxxxxxxxxxx
```

## インスタンスの root デバイスをデタッチ
上記で出力されたボリューム (volume) をデタッチします。 ここでは root デバイスになります
※) デバイスを umount するって言ったらわかりやすいですかね。 root デバイスを umount するので、実行したらインスタンスは 2 度と起動できませんｗ (マウントすれば、動作するけど)

```bash
aws ec2 detach-volume \
    --instance-id ＜＜＜インスタンスID＞＞＞\
    --volume-id ＜＜＜上記で取得したインスタンスのボリューム (volume) ID＞＞＞
```


# スナップショットからボリューム (volume) を復元
スナップショットからボリュームを復元します。

availability-zone は、（この文章を読んでいるのは)日本だと思うので ap-northeast-1 ではないでしょうか
リージョンが合わないと復帰できないので、合わせるようにしてください。

まぁ、だいたいは ap-northeast-1a でしょうが。。。


```bash
aws ec2 create-volume \
    --availability-zone ap-northeast-1a ＜＜＜ここはリージョンをあわせてください＞＞＞
    --snapshot-id ＜＜＜スナップショットID＞＞＞
    --tag-specifications "ResourceType=volume,Tags=[{Key=Name,Value=＜＜＜ボリュームの名前をつけるので適当な文字列(あとでこの名前で復帰するボリュームを検索します)＞＞＞]"
```

# 復元したボリューム (volume) の ID を取得
上記で復元したボリューム (volume) の ID を取得します。
取得する際、ボリューム (volume) につけた名前で検索をします。

```bash
aws ec2 describe-volumes \
    --filters Name=tag:Name,Values=＜＜＜ボリュームの名前＞＞＞ \
    --query "Volumes[].VolumeId" \
    --output text
```

おそらく、以下のような値が返ってくるかと思います(xxxx は半角英数字)
これが、復元したボリューム(のID) です。
```bash
vol-xxxxxxxxxxxxxxxxx
```

# 復元したボリューム (volume) をインスタンスにアタッチ
※) サーバに HDD をはめ込んでデバイスをマウントするわけですｗ

```bash
aws ec2 attach-volume \
    --device ＜＜＜root デバイス名＞＞＞
    --instance-id ＜＜＜インスタンスID＞＞＞ \\
    --volume-id ＜＜＜復元したボリューム (volume) のID＞＞＞
```

# インスタンスの起動
最後にインスタンスを起動します

```bash
aws ec2 start-instances --instance-ids=＜＜＜インスタンスID＞＞＞
```

# 不要なボリュームを削除
もし、復元するときにデタッチしたボリュームが不要な場合は削除しちゃいましょう
※) どんどんボリュームが増えて、見た目上わけわからんくなるので。。。

```bash
aws ec2 delete-volume --volume-id ＜＜＜デタッチしたボリューム ID＞＞＞
```


# まとめ
上記を bash スクリプトにすると以下のようになります。
スクリプト内なので「`」をエスケープしないといけないとかあるので「\」が若干増えているとことがありますｗ


```bash
#!/bin/bash
DATE=`date "+%Y%m%d%H%M%S"`

INSTANCE_ID=i-xxxxxxxxxxxxxxxxx
SNAP_SHOT_ID=snap-xxxxxxxxxxxxxxxx

# インスタンスを停止
aws ec2 stop-instances --instance-ids=${INSTANCE_ID}

# インスタンスが停止するまで待機
aws ec2 wait instance-stopped --instance-ids=${INSTANCE_ID}

# root デバイス名取得
INSTANCE_ROOT_DEV=`aws ec2 describe-instances \
    --instance-ids=${INSTANCE_ID} \
    --query "Reservations[].Instances[].RootDeviceName" \
    --output text`

# root デバイスの volume 名を取得
ROOT_DEV_VOLUME=`aws ec2 describe-instances \
    --instance-id ${INSTANCE_ID} \
    --query "Reservations[].Instances[].BlockDeviceMappings[?DeviceName==\\\`${INSTANCE_ROOT_DEV}\\\`].Ebs.VolumeId"   \
    --output text`


# root デバイスの volume をデタッチ
aws ec2 detach-volume --instance-id ${INSTANCE_ID} --volume-id ${ROOT_DEV_VOLUME}

# スナップショットから volume 復元
RESTORE_VOLUME_TAG_VALUE="instance_restore_${DATE}"
aws ec2 create-volume \
    --availability-zone ap-northeast-1a \
    --snapshot-id ${SNAP_SHOT_ID} \
    --tag-specifications "ResourceType=volume,Tags=[{Key=Name,Value=$RESTORE_VOLUME_TAG_VALUE}}]"


# volume 復元まで待機
aws ec2 wait volume-available \
    --filters Name=tag:Name,Values=${RESTORE_VOLUME_TAG_VALUE}

# root デバイスに vlolume をアタッチ
aws ec2 attach-volume --device ${INSTANCE_ROOT_DEV} --instance-id ${INSTANCE_ID} --volume-id ${RESTORE_VOLUME_ID}


# インスタンスを開始
aws ec2 start-instances --instance-ids=${INSTANCE_ID}

# 不要な volume を削除
aws ec2 delete-volume --volume-id ${ROOT_DEV_VOLUME}

```

# おわりに
インテリジェンスにスナップショットやインスタンスの ID を取得して実行する方法ではないので、事前にある程度、情報をまとめておく必要がありますので、若干めんどくさいです。

そのめんどくさいのは、今後改善していきたいとは思ってます。