AWS EC2の「No space left on device」エラーの解決方法

## はじめに
株式会社じげんのrkinseiです。
:airplane: 留学エージェント比較サービス 留学くらベーるの開発を担当しています。

今回はAWS EC2の「No space left on device」エラーの解決方法を紹介します！

苦戦しながら修正したものの、完璧な対応はまだできていないと思いますが、今回実際に試してみた対処法をまとめてみました。
これから同じエラーを解決したい方の参考になれば幸いです。:relaxed:

## エラーの概要
RailsアプリケーションをAWSのEC2インスタンスにデプロイした際に、「no space left on device」とエラーメッセージが表示されます:triumph:

```
error An unexpected error occurred: "ENOSPC: no space left on device, copyfile '/home/ec2-user/.cache/yarn/XXXXXXXXX'".
rake aborted!
```

インスタンスにログインすると、以下のようにエラーメッセージが表示されました。:flushed:

```
/home/user/.rbenv/libexec/rbenv-init: 行 131: ヒアドキュメント用一時ファイルを作成できません: デバイスに空き領域がありません
```

## エラーの原因調査 :muscle:
エラーメッセージを読むと「このデバイスにもうスペースが無い」と言われています。
容量不足が発生する原因として、次の２つのパターンがあります。
   :one: ディスク容量が不足している
   :two: 「inode」の容量が不足している

## ディスク/inodeの容量を確認する:muscle:
###:one: ディスクの容量を確認する
[「df」コマンド](https://atmarkit.itmedia.co.jp/ait/articles/1610/24/news017.html#sample1)を使ってディスクの空き容量を調べます。**基本的には「df -h」だけで十分です。**

> 「df」を実行すると、ディスクの空き領域が表示されます。デフォルトでは、1K（1024バイト）のブロックサイズの表示となります。GBなど、読みやすい単位で表示したい場合は、「-h」オプションを使用します。
空き領域は、マウントしているファイルシステムごと、つまり、パーティションごとに表示されます。空き領域の合計を表示したい場合は、「--total」オプションを使用します。

https://atmarkit.itmedia.co.jp/ait/articles/1610/24/news017.html

```
## 実行例
[ec2-user@ip-XXXXXXXX/]$ df  ## ディスクの空き容量を表示する
ファイルシス    1K-ブロック      使用      使用可   使用%   マウント位置
devtmpfs      2009420       60    2009360      1%     /dev
tmpfs         2020068        0    2020068      0%     /dev/shm
/dev/xvda1    1225231  8220416    3931652     68%     /
[ec2-user@ip-XXXXXXXX/]$ df -h  ## 読みやすいサイズ表記で表示する
ファイルシス   サイズ   使用    残り   使用%  マウント位置
devtmpfs     2.0G   60K   2.0G    1%   /dev
tmpfs        2.0G     0   2.0G    0%   /dev/shm
/dev/xvda1    12G   7.9G  3.8G   68%   /
[ec2-user@ip-XXXXXXXX /]$ df -h --total ##空き領域の合計も併せて表示する
ファイルシス   サイズ  使用  残り    使用%  マウント位置
devtmpfs    2.0G   60K  2.0G    1%   /dev
tmpfs       2.0G     0  2.0G    0%   /dev/shm
/dev/xvda1   12G  7.9G  3.8G   68%   /
total        16G  7.9G  7.6G   51%   -
```
まだ3.8Gも残っているので、ディスクに十分な空き容量がある状態です。:expressionless:

:point_right: ディスクの空き容量がない場合があれば、使用量の大きい不要なファイルを削除する必要があります。
[「du」コマンド](https://eng-entrance.com/linux-command-du "ディスクの空き容量を調べる")を実行して削減できる場所を探ってみます :fist:

```
## 実行例
[ec2-user@ip-XXXXXXXx ~]$ sudo du -sh /var/* | sort -rh
4.3G	/var/www
294M	/var/log
185M	/var/cache
168M	/var/lib
1.3M	/var/spool
148K	/var/run
16K	    /var/lock
16K	    /var/db
12K	    /var/kerberos
8.0K	/var/empty
4.0K	/var/yp
4.0K	/var/tmp
4.0K	/var/preserve
4.0K	/var/opt
4.0K	/var/nis
4.0K	/var/local
4.0K	/var/games
4.0K	/var/account
0	/var/mail
```

###　:two: inodeの容量を確認する
:point_up: ディスクの空き容量がある場合は、続いてinodeの容量を確認します。

-  [inode](https://e-words.jp/w/inode.html)とは：

> UNIX系OSの一部のファイルシステムで用いられる、ファイルやディレクトリについての情報を記録した管理データのこと。

https://e-words.jp/w/inode.html


inodeの残りは`df`コマンドに`「-i」`オプションをつければ確認できます。

```
[ec2-user@ip-XXXXXXXX /]$ df -i
ファイルシス   Iノード    I使用   I残り   I使用%  マウント位置
devtmpfs    502355    441 501914      1%  /dev
tmpfs       505017      1 505016      1%  /dev/shm
/dev/xvda1  786432 786431      1     100%  /

```
:point_up: `I使用%`が`100%`だったため、今回のエラーの原因はinodeの容量不足だということがわかりました:clap: :clap: :clap:

## 解決法 :muscle:
### 対処1: 不要なファイルを手動で削除する
① ファイル数が多いディレクトリがどこにあるのかを探す
 `sudo find / -xdev -type f | cut -d "/" -f 2 | sort | uniq -c | sort -nr `を実行すると、ルートディレクトリ直下にあるディレクトリのファイル数が表示されます。
 コマンドの説明は下記:point_down:の通りです。
  
:::note info
「findコマンド 」: find - ディレクトリ階層下のファイルを検索する
「-xdev」 :  マウント先のファイルシステムを検索しないようにしてくれる
「-type f」 ：ディレクトリではなく、ファイルのみを対象とし検索する
「cut -d "/" -f 2」 : ファイル「/」の文字で区切り、その２項目目を表示する
「sort | uniq -c」: 重複行を並べ替えてからカウントする (sort省略可)
「sort -nr」: 文字列を数字として認識した上で、降順で表示してくれる
:::

```
### 実行例
$ sudo find / -xdev -type f | cut -d "/" -f 2 | sort | uniq -c | sort -nr 
 357021 var
 137808 home
  65042 usr
   8846 opt
   3443 lib
    618 etc
    281 lib64
    176 sbin
     99 bin
     34 root
     30 boot
      2 tmp
      1 .autorelabel
      1 .autofsck
```
:point_up: `/var`配下のどこに、多数のファイルが存在しているのかがわかりました:clap:

② ファイル数が多いディレクトリが見つかったら、そのディレクトリに対して同じコマンドを実行する

```
$ sudo find /var -xdev -type f | cut -d "/" -f 3 | sort | uniq -c | sort -nr
 352693 www
   3986 lib
    177 log
    106 cache
     25 run
     24 lock
      8 spool
      1 db
      1 account
```

- ③ 上記の操作を何度か繰り返し、不要なファイルが多数存在しているディレクトリを探す
- ④ 不要なファイルを` sudo rm -rf ディレクトリパス`コマンドで削除する
- ⑤ ⏬再びdfコマンドを実行してinodeの容量を確認する ==>「I使用%」の数値が下がっていれば、inodeの容量が確保できています。


```
[ec2-user@ip-XXXXXXXXX ~]$ df -i
ファイルシス   Iノード     I使用   I残り  I使用% マウント位置
devtmpfs    253915    431  253484     1% /dev
tmpfs       256156      1  256155     1% /dev/shm
/dev/xvda1  786432 313277  473155    40% /
```

:::note alert
本番環境の場合、ファイルが不要なのかよく確認してください！
:::

### 対処2: inode のサイズ拡張:point_right::point_right::point_right:EBSボリュームを増やす
ディスク容量が小さすぎる場合は、デプロイするたびに手動でファイルを削除して容量を確保する必要があるため、面倒な場合はEBSのボリュームを増やしましょう。

::: note warn 
1度ボリュームサイズやタイプを変更すると6時間は変更できなくなるので注意が必要です。
:::

基本的には、下記公式ガイドと参考記事に沿って作業を行えば OK なので、ご参考にしてください。

- 公式ガイド
  - [EBS ボリュームへの変更のリクエスト](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/requesting-ebs-volume-modifications.html)
 - [ボリュームサイズ変更後の Linux ファイルシステムの拡張](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/recognize-expanded-volume-linux.html)
- 参考記事：　[[No space left on device] EC2 インスタンスEBSボリュームが枯渇したときの対処方法](https://dev.classmethod.jp/articles/how-to-expand-ec2-storage/)