ディスクフルになって接続できなくなった場合の対処方法

# はじめに
先日、EC2インスタンスのディスクがいっぱいになり、`SSH`でも`Session Manager`でも接続できなくなってしまったため、今後同じようなことが起きたときにすぐに対応できるよう、手順をまとめておこうと思います。

:::note info
2023/02/11 EBSボリュームの拡張方法も投稿しました。
:::
- 【次】[EBSボリュームの拡張方法](https://qiita.com/sakai00kou/items/b7828b6b38036c7f838e)

# ディスクフルになった場合に起こる問題
EC2インスタンスに限らず、一般的な`Linux`マシンでも同様ですが、ディスクフルになったマシンにログインしようとした場合、一時ファイルやログを出力できるディスク容量が無いことで以下のように接続に失敗してしまいます。
※以下はディスクフルのEC2インスタンスに`Session Manager`で接続しようとして失敗したときの例

![Monosnap_20230205_105840.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/fac38d72-9c04-7527-1182-4084b4a8993b.png)

# ディスクフルになって接続できなくなった場合の対処方法
対処方法は色々とありますが、思いつく限りだと以下のような方法が考えられます。

- [再起動](#再起動)
- [他のEC2インスタンスでEBSをマウント](#他のec2インスタンスでebsをマウント)
- [バックアップからの復元](#バックアップからの復元)
- [ルートボリュームの置き換えによる復旧](#ルートボリュームの置き換えによる復旧)

それぞれの手順について以下で紹介していきます。

## 再起動
EC2インスタンスを再起動することで一時ファイルが削除されるため、一時的に`SSH`、`Session Manager`で接続できる可能性があります。

ディスクフルでEC2インスタンスに接続できなくなった場合はひとまず再起動して接続できるようになるか確認してみましょう。
※ちなみに私は再起動したら`Session Manager`で接続できるようになったため、後述の作業は行わずに済みました。

## 他のEC2インスタンスでEBSをマウント
再起動しても接続できない場合は復旧作業用EC2インスタンスを準備して、復旧用EC2インスタンスで元のEC2インスタンスにアタッチされていたEBSボリュームをマウントすることで不要ファイルの削除等を行うことができます。

手順としては以下のような流れで進めていきます。

- [ディスクフルEBSボリュームのデタッチ](#ディスクフルebsボリュームのデタッチ)
- [ディスクフルEBSボリュームのアタッチ](#ディスクフルebsボリュームのアタッチ)
- [ディスクフルEBSボリュームのデバイス名確認](#ディスクフルebsボリュームのデバイス名確認)
- [ディスクフルEBSボリュームのマウント](#ディスクフルebsボリュームのマウント)
- [不要ファイルの削除](#不要ファイルの削除)
- [ディスクフルEBSボリュームのアンマウント](#ディスクフルebsボリュームのアンマウント)
- [元のEC2インスタンスへのアタッチ](#元のec2インスタンスへのアタッチ)
- [元のEC2インスタンスの起動](#元のec2インスタンスの起動)

この方法はディスクフルで接続できなくなった場合だけではなく、例えば`fstab`の修正を誤って接続できなくなった場合などにも応用できるので、覚えておくと良いと思います。

### ディスクフルEBSボリュームのデタッチ
ディスクフルとなっているEC2インスタンスを停止してEBSボリュームをデタッチします。

ログインできない状態だとコマンド操作での停止はできないので、EC2のダッシュボードより「**インスタンスの状態**」→「**インスタンスの停止**」を行って停止させます。

停止後、「**Elastic Block Store**」→「**ボリューム**」で該当のEBSボリュームを選択→「**アクション**」から「**ボリュームのデタッチ**」でEC2インスタンスから取り外します。

![Monosnap_20230205_111556.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/2b31e044-3010-84d4-abe2-347d5cfbce73.png)

また、再度EBSボリュームをアタッチする際に必要となるため、以下EBSボリュームの詳細タブの「**アタッチされたインスタンス**」からデバイス名を確認しておきます。

![Monosnap_20230205_150633.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/2ff5ca3b-cba1-2a19-d9cc-340ec39916d1.png)

### ディスクフルEBSボリュームのアタッチ
先程デタッチしたEBSボリュームを復旧用EC2インスタンスにアタッチします。

アタッチして操作ができれば良いので、他のEC2インスタンスが存在するのであれば、復旧用EC2インスタンスは新たに準備しなくても問題ありません。

また、アタッチする際には復旧用EC2インスタンスは起動したままでもEBSボリュームをアタッチできるため、停止する必要もありません。

デタッチした方法と同様、「**Elastic Block Store**」→「**ボリューム**」で該当のEBSボリュームを選択→「**アクション**」から「**ボリュームのアタッチ**」で復旧用EC2インスタンスに取り付けます。

![Monosnap_20230205_111855.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/77480ae5-7855-fb37-5e13-fceaf69383d5.png)

アタッチする際の画面で以下のように表示されますが、今回は復旧用EC2インスタンスにデータボリュームとしてアタッチするため、デバイス名はデフォルトのまま`/dev/sdf`でアタッチします。

![Monosnap_20230205_111940.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/8c08c380-edd5-75a6-7fd8-c9af9f9475bb.png)

### ディスクフルEBSボリュームのデバイス名確認
`Linux`の仕様としてボリュームをアタッチしただけではディスクフルとなっているEBSボリュームの操作ができないため、復旧用EC2インスタンスにログインし、領域をマウントして不要ファイルの削除等を行えるようにします。

事前作業として、先程アタッチしたEBSボリュームのデバイス名を確認するため、`blkid`コマンドでデバイス名を確認します。

```bash:bulidコマンドでのデバイス確認
$ sudo blkid
/dev/xvda1: LABEL="/" UUID="5d259081-e60a-4c60-8f74-78ad0ee25652" TYPE="xfs" PARTLABEL="Linux" PARTUUID="f257d0ed-ac68-4b9b-8ee1-1f8cbe74e9e6"
/dev/xvdf1: LABEL="/" UUID="5d259081-e60a-4c60-8f74-78ad0ee25652" TYPE="xfs" PARTLABEL="Linux" PARTUUID="f257d0ed-ac68-4b9b-8ee1-1f8cbe74e9e6"
```

操作を行っているEC2インスタンスに元々アタッチされているルートボリュームは`df`コマンドなどを実行して確認します。

```bash:dfコマンドでルートボリュームのデバイスを確認
$ df
ファイルシス   1K-ブロック    使用  使用可 使用% マウント位置
devtmpfs            485168       0  485168    0% /dev
tmpfs               493960       0  493960    0% /dev/shm
tmpfs               493960     516  493444    1% /run
tmpfs               493960       0  493960    0% /sys/fs/cgroup
/dev/xvda1         8376300 1652180 6724120   20% /
tmpfs                98796       0   98796    0% /run/user/1000
tmpfs                98796       0   98796    0% /run/user/0
```

今回の場合は`/dev/xvda1`が復旧用EC2インスタンスのルートボリューム、`/dev/xvdf1`がディスクフルとなっているボリュームとなります。

### ディスクフルEBSボリュームのマウント
先程確認したデバイス名を指定して、復旧用EC2インスタンスにディスクフルEBSボリュームをマウントしていきます。

注意点として、復旧用EC2インスタンスもディスクフルとなったEC2インスタンスと同一のイメージ（`AMI`）を使用している場合、復旧用EC2インスタンスのルートボリュームの`UUID`と同じIDとなり、以下のようにマウントに失敗してしまいます。
※今回テストで準備したEC2インスタンスも同じAMIから作成したため、`blkid`で確認した`UUID`が同一であることが確認できます。

```bash:UUIDが同じボリュームをマウントしようとした場合のエラー
$ sudo mount -t xfs /dev/xvdf1 /mnt
mount: /mnt: wrong fs type, bad option, bad superblock on /dev/xvdf1, missing codepage or helper program, or other error.
```

その場合、`mount`コマンドにオプションを付与することで`UUID`を無視することができるので、今回は以下のコマンドで`/mnt`にマウントを行います。

```bash:ディスクフルEBSボリュームのマウント
$ sudo mount -t xfs -o nouuid /dev/xvdf1 /mnt
```

### 不要ファイルの削除
`/mnt`にディスクフルとなっているEBSボリュームをマウントしたことでディスクフルとなっているEBSボリュームの中身が確認できるようになります。

不要ファイル削除を行う際、パス指定を間違えると復旧用EC2インスタンス自体のファイルが削除されることになるため、気をつけましょう。

```bash:不要ファイルの削除例
$ sudo rm /mnt/root/diskfulltest
```

### ディスクフルEBSボリュームのアンマウント
不要ファイルを削除したらデバイス指定でアンマウントして元のEC2インスタンスにアタッチする準備を行います。

```bash:デバイスのアンマウント
$ sudo umount -d /dev/xvdf1
```

### 元のEC2インスタンスへのアタッチ
「**Elastic Block Store**」→「**ボリューム**」で該当のEBSボリュームを選択→「**アクション**」から「**ボリュームのデタッチ**」で復旧用EC2インスタンスから取り外します。

復旧用EC2インスタンスは今回の手順に従えば特に停止しなくてもデタッチできるはずですが、デタッチできず、`device busy`となるようであれば、停止するか強制デタッチを行ってください。

復旧用EC2インスタンスからデタッチ後、「**Elastic Block Store**」→「**ボリューム**」で該当のEBSボリュームを選択→「**アクション**」から「**ボリュームのアタッチ**」で元のEC2インスタンスにアタッチしますが、復旧用EC2インスタンスにアタッチした場合と異なり、今回はルートボリュームとしてアタッチする必要があるため、以下のようにデバイス名を元のデバイス名に書き換え（今回の場合は`/dev/xvda`）「**ボリュームのアタッチ**」を選択します。

![Monosnap_20230205_145725.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/2b22b225-698d-901f-09e8-ddd497fe79cc.png)

### 元のEC2インスタンスの起動
EBSボリュームアタッチ後は通常と同じくEC2インスタンスを起動してログインできるか確認してみます。

問題なく接続できれば完了です。

## バックアップからの復元
`AMI`またはEBSボリュームのスナップショットを定期的にバックアップしている場合は、バックアップから復元して新たにEC2インスタンスを作成することで、問題が発生する以前の状態に戻すこともできます。

ただし、復元を行う場合は当然ながらバックアップを取得したときの状態に戻るため、バックアップ取得後に行った操作やファイルは無くなってしまうことに注意しましょう。
※今回は`AMI`、スナップショットからの復元手順は省略します。

## ルートボリュームの置き換えによる復旧
ディスクフルとなっているEC2インスタンスをどうしても停止させたくないような場合は、以下のような手順でルートボリュームの置き換えを行うことで無停止で復旧させることも可能です。

- [ルートボリュームの置き換え](#ルートボリュームの置き換え)
- [ルートボリューム置き換え後の接続](#ルートボリューム置き換え後の接続)

ただし、置き換えの名の通り、ルートボリュームをそのまま別のボリュームに置き換えることになるため、仕組みとしては`AMI`やスナップショットからのリストアと同等の対処となります。

また、無停止で復旧することは可能ですが、ボリュームを置き換えるタイミングで1分程度応答が無くなるため、サービス提供を行っているEC2インスタンスに対して実施する場合は注意が必要です。

ルートボリューム交換時の無応答検証は以前の記事でまとめているため、興味がある方は以下も参照してください。

- [EC2のルートボリューム交換を試す。](https://qiita.com/sakai00kou/items/ddaf9efaa1c02ee536b9)

### ルートボリュームの置き換え
ルートボリュームを置き換えするには、EC2ダッシュボードの「**インスタンス**」で該当のインスタンスを選択→「**アクション**」から「**モニタリングとトラブルシューティング**」→「**ルートボリュームを置き換える**」を選択します。

![Monosnap_20230205_175520.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/afb81b52-7986-5b64-cd6c-b874493dfe26.png)

ルートボリュームを置き換える際、以下3つの復元方法を選択できます。

`AMI`やスナップショットを指定することもできるため、バックアップを取得している場合は、`AMI`やスナップショットを指定しても良いです。

|復元|内容|
|:--|:--|
|起動状態|現在起動中のルートボリュームの初期状態に戻す|
|スナップショット|指定したスナップショットに置き換える|
|イメージ|指定したAMIイメージに置き換える|

![Monosnap_20230205_172252.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/be7088ff-3719-de76-493c-8e421be6cba8.png)

「**置き換えられたルートボリュームを削除**」にチェックをすることで、置き換え時にボリュームを削除できますが、削除すると古いルートボリュームに入っているファイルが救出できないため、確実に削除しても問題ないとわかっている場合以外はチェックを行わず、問題ないと判断できた時点で削除するのが良いでしょう。

### ルートボリューム置き換え後の接続
置き換え後、1分ほど経過すると再接続できるようになるため、 `SSH`や`Session Manager`で接続を行います。

`SSH`で接続を行う場合はフィンガープリントが変わるため、以下のようなワーニングで接続できません。

そのため操作端末の`known_hosts`から該当の定義を削除して再度接続するようにします。

```bash:ルートボリューム置き換え後のSSH接続
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Please contact your system administrator.
Add correct host key in /Users/user01/.ssh/known_hosts to get rid of this message.
Offending ED25519 key in /Users/user01/.ssh/known_hosts:51
Host key for X.X.X.X has changed and you have requested strict checking.
Host key verification failed.
```

削除方法はどのような方法でも問題ありませんが、以下`sed`で削除する場合の例。

```bash:該当フィンガープリントの削除（接続IPアドレスが192.0.2.1の場合）
sed -i -e '/192.0.2.1/d' ~/.ssh/known_hosts
```

## おわりに
ディスクフルになって接続できなくなった場合の対処方法をいくつか紹介しましたが、改めて整理するとオンプレミスのサーバで問題が発生した場合よりも対応方法があると感じました。

とはいえ、今回の手順は最終手段なので、実際にはディスク容量監視を行い、ディスクフルになる前に対処できるようにしましょう。