EC2のEBSを別のEC2に付け替えてマウントしてまた戻す

AI時代においてもなお残るじみーな仕事として、数年間放置されて誰も接続できなくなったサーバの調査が必要になった。対象サーバのOSはUbuntu 18.04である。ひさびさに見た。

もろもろの調査を経て、最終手段として、EC2のEBSをいったん別のEC2に付け替え、そちらでマウントして中身を調べてから元に戻すことにした。
誰か接続できる人いないかな〜と探したが、開発者なら自分で道を切り開くべし。ということでやっていく。

やること

接続したいができないEC2とは別に接続可能なEC2を用意し、接続できない方のEC2のEBSをデタッチした上で接続可能なEC2にそのEBSをアタッチする。で、接続可能なEC2に入ってそのEBSを適当なところにマウントしてもろもろ調整をし、再度元のEC2にアタッチする。

ただし、付け替え先のEC2は対象のEBSと同じAZに用意する必要がある。同じVPCにあるだけではだめなので注意。 はじめに言及していたのはUbuntu 18.04だが、検証用に用意したのはUbuntu 24.04、t3.microのもの。

この手のやつもAIにきけば出してくれるから助かる。とはいえそれなりにリスクのある対応ではあるのでもろもろの理解と確認は必要そう。

対象EC2のEBSについてボリュームIDを確認する

対象EC2について、以下のコマンドでルートデバイス名とそれに対応するボリュームIDを確認する。

aws ec2 describe-instances \
  --instance-ids <インスタンスID> \
  --query 'Reservations[].Instances[].{
    ID:InstanceId,
    RootDevice:RootDeviceName,
    Disks:BlockDeviceMappings
  }'

出力

[
    {
        "ID": "i-07eee7aec5844b1d4",
        "RootDevice": "/dev/sda1",
        "Disks": [
            {
                "DeviceName": "/dev/sda1",
                "Ebs": {
                    "AttachTime": "2026-10-25T14:47:56+00:00",
                    "DeleteOnTermination": false,
                    "Status": "attached",
                    "VolumeId": "vol-0adfe8bb1dab84598"
                }
            }
        ]
    }
]

"RootDevice"に記載のある文字列と一致する"DeviceName"をもつ"Disks"をみる。そこにある"Ebs"の"VolumeId"が対象となる。 RootDeviceNameはEC2作成元のAMIから引き継ぐ、起動用ディスクのAWS側の接続名。OS内で/にマウントされているデバイス名を取得しているわけではない。元に戻すときに使うので、ボリュームIDとあわせて控えておく。

対象のEC2を停止する

ルートEBSはEC2が起動したままではデタッチできないので、まず停止する。接続可能な方のEC2は起動したままでよい。

aws ec2 stop-instances --instance-ids <対象のインスタンスID>

対象のEBSのスナップショットを作成する

この手の操作はなにかやらかすとEBSを元に戻したのに起動しなくなるリスクがある。そのためスナップショットをとる。

aws ec2 create-snapshot \
  --volume-id <ボリュームID> \
  --description "EBSデタッチ前のやつ" \
  --query 'SnapshotId' \
  --output text

出力

snap-hogehogehogehoge

それなりに時間はかかる。手元では8GB程度のEBSであっても5分くらいはかかった。

対象のEBSをデタッチして接続可能なEC2にアタッチする

対象のEC2からEBSを切り離す。

aws ec2 detach-volume \
  --volume-id <ボリュームID> \
  --instance-id <対象のインスタンスID>

続いて、接続可能なEC2にアタッチする。

aws ec2 attach-volume \
  --volume-id <ボリュームID> \
  --instance-id <接続可能なEC2のインスタンスID> \
  --device /dev/sdf

--deviceで指定できるデバイス名には、接続可能なEC2ですでに使用中の接続名と重ならないものを選ぶ。今回は追加ディスクとして/dev/sdfを指定している。 EC2で使用できるデバイス名

接続可能なEC2に入りEBSをマウントする

lsblk -p -o NAME,SIZE,FSTYPE,MOUNTPOINTS,SERIAL

出力

NAME          SIZE FSTYPE   MOUNTPOINTS                  SERIAL
## 中略 ##
/dev/nvme0n1         8G                                       <元からアタッチされているボリュームのID>
├─/dev/nvme0n1p1     7G ext4     /
├─/dev/nvme0n1p14    4M
├─/dev/nvme0n1p15  106M vfat     /boot/efi
└─/dev/nvme0n1p16  913M ext4     /boot
/dev/nvme1n1         8G                                       <今回アタッチしたボリュームのID>
├─/dev/nvme1n1p1     7G ext4
├─/dev/nvme1n1p14    4M
├─/dev/nvme1n1p15  106M vfat
└─/dev/nvme1n1p16  913M ext4

さきほどアタッチしたEBSのボリュームIDが見えていればアタッチに成功している。

続いて、対象のルートファイルシステムが入っているパーティションをマウントする。今回は/dev/nvme1n1p1が対象となる。

sudo mkdir -p /mnt/rescue
sudo mount -o ro,noload /dev/nvme1n1p1 /mnt/rescue # 読み込みのみ
findmnt /mnt/rescue

findmntで以下のように出力されればOK。

TARGET      SOURCE         FSTYPE OPTIONS
/mnt/rescue /dev/nvme1n1p1 ext4   ro,relatime,norecovery

もろもろ調査をして、なにか書き込みが必要になった場合はアンマウントした上で書き込み可能なオプションを指定して再度マウントすればよい。

cd / # マウント対象の外に移動する
sudo umount /mnt/rescue
sudo mount -o rw /dev/nvme1n1p1 /mnt/rescue

作業が終わったら元のEC2に戻す

まず接続可能なEC2の中でアンマウントする。

cd /
sudo umount /mnt/rescue

ここからは手元の端末で実行する。接続可能なEC2から取り外し、完了を待つ。

aws ec2 detach-volume \
  --volume-id <ボリュームID> \
  --instance-id <接続可能なEC2のインスタンスID>

元のEC2は停止したまま、控えておいた元のルートデバイス名でアタッチする。今回は/dev/sda1。

aws ec2 attach-volume \
  --volume-id <ボリュームID> \
  --instance-id <元のインスタンスID> \
  --device /dev/sda1

あとは元のEC2を起動する。

aws ec2 start-instances --instance-ids <元のインスタンスID>

元のEC2では起動時にOSが自動でマウントするため、手動でのマウントは不要。

終わり

AIによってこういうのも楽になったのは大変うれしいが、そもそもそれほどやりたい作業ではないなあ。 ちなみに接続できない場合のトラブルシューティング集が公式から提供されている。 EC2への接続のトラブルシューティング:秘密鍵を紛失した場合

参照