[OCI] 無料50GBインスタンスの空き容量をなるべく確保する

OCIの無料インスタンス `VM.Standard.A1.Flex (Always Free)` を一生こすり続けている皆さんこんにちは。50GBのBootボリュームが一瞬でなくなってしまったりしてお困りではありませんか? 個人的にストレージ確保に非常に苦労しているので、この記事ではその知見をまとめます。

## 対象環境

| Key | Value |
|:----------:|:------------:|
| OS       | Ubuntu 20.04.6 LTS (GNU/Linux 5.15.0-1048-oracle aarch64)        |
| インスタンス     | VM.Standard.A1.Flex |
| Bootボリューム | 50GB (99%消費) |
| Blockボリューム | 150GB (100%消費 保管用のため消せない) |
| 備考 | DockerとPortainerを使用 |

## 消せるものの調査方法
まず現状99%消費しているので、一体何が原因なのかを調べます。

### ストレージ使用量の確認
- `sudo du -hs * | sort -hr`
  - カレントディレクトリにあるフォルダそれぞれのサイズを表示します
- `sudo ncdu -x -q`
  - カレントディレクトリ配下のフォルダそれぞれのサイズをグラフィカルにCUI表示します
    - 要 `sudo apt install ncdu`
    - [duコマンドを使うよりとても簡単に確認できます](https://softantenna.com/blog/ncdu/)
    - (実行時のユーザーがアクセス権限を持つフォルダのサイズしか計算されません
- `sudo docker system df -v`
  - Docker関連データ(コンテナ/イメージ/ボリューム)のサイズを一括表示します
- `journalctl --disk-usage`
  - Journal(systemdで動くサービス系のログ)保存量を表示します

### インスタンス情報の確認
- `uname -r`
  - 現在のカーネルバージョンを確認します
- `cat /etc/os-release`
  - 現在のOSバージョンを確認します
- `df -h --total`
  - ファイルシステム毎(ボリューム毎)の使用率を表示します

## 消せるもの一覧
大体どのフォルダが容量を取っているのかわかったので消せそうなものを調べました。

### 使っていないDocker関連データ

#### 一般データ削除
![スクリーンショット 2024-01-20 180344.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/20badf96-9939-a27f-0bdd-c0b123940c01.png)
- 不要なイメージ削除
  - `docker image prune -a`
    - コンテナから参照されていない未使用イメージとdangling image(タグを持っていないかつ参照されないイメージ)を削除します
- 不要なネットワーク削除
  - `docker network prune`
    - コンテナからも参照されていないネットワークを削除します
- 不要なボリューム削除
  - `docker volume prune`
    - コンテナからも参照されていないボリュームを削除します
- 不要なコンテナ削除
  - `docker container prune`
    - "停止中のコンテナ"を削除します
- 参考
  - https://docs.docker.jp/config/pruning.html
  - Portainerを利用している場合 ログ以外はWebUIからポチポチで削除できます

#### ログデータの削除
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/5df44e5f-9ca4-2024-e0bc-2c27d4271eb0.png)

ncduで歩き回ると /var/lib/docker/containersにやけにでかいファイルがありました。ログをコンテナ内で吐いている場合、デフォルトだとここにログが出力され、しかもサイズ制限がないため、すごく巨大化します。

- 削除方法
  - `cat /dev/null > /var/lib/docker/containers/(ハッシュ)/(ハッシュ)-json.log`
    - ログをnullで上書きする
- 参考
  - https://qiita.com/Hi-king/items/fe5ac34170c7cdf12cc0

### journalctl(var/logフォルダ)の不要なログ

OSデーモンやnginxのアクセスログなどが場合によっては貯まる可能性があります。

- 削除方法
  - `sudo journalctl --vacuum-size=1024M`
    - (大雑把に削除で問題ない場合) 1024MB残して残りを消します
- 参考
  - https://linux.just4fun.biz/?Linux%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A/%E3%82%B8%E3%83%A3%E3%83%BC%E3%83%8A%E3%83%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%89%8A%E9%99%A4%E3%81%97%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88%E3%83%BBjournalctl

### 適用済みのカーネルアップデートファイル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/beba4135-4a60-d452-a71f-c0aff125d831.png)

Oracleは、非情に親切なことに最新カーネルを勝手にダウンロードしてきます。通常、再起動したら最新版が反映され、古いものが削除されるのですが、なぜか残っていることがあります。この場合1カーネルバージョンに付き494MBと結構な量を消費してしまいます。

- 削除方法
  - `uname -r`で 現在のカーネルバージョン確認
  -  `sudo rm /usr/lib/modules/(現在のカーネルバージョンより古いもの)-oracle`
    - **※今利用しているカーネルを消さないようにバージョンは十分確認してください**
    - **※安全な削除方法ではない可能性があります**
    -  (aptから安全に削除できるという話もあったように思うのですが詳細を失念しました...

- 参考
  - https://askubuntu.com/questions/1406581/why-does-ubuntu-not-clean-out-old-kernel-module-files-in-lib-modules-when-old
  - https://serverfault.com/questions/1098556/how-to-cleanup-usr-lib-modules-and-usr-lib-x86-64-linux-gnu


## 最大ファイルサイズを制限する対策
削除して容量を確保した後は、そもそも削除操作をしなくても済むようにする方法を取っておきましょう。

### var/logのログファイルサイズ制限
全体的なjournalログサイズの最大保存量を制限することができます。

- 手順
  - `sudo nano /etc/systemd/journald.conf`
  - `SystemMaxFileSize=1024M` と記載して保存
  - `sudo systemctl restart systemd-journald`で再起動して反映
- 参考
  - https://b.fugenjikko.com/archlinux/archlinux-journal-maxsize#:~:text=jounal%E3%83%AD%E3%82%B0%E3%81%AE%E6%9C%80%E5%A4%A7%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%97%E3%81%A6%E3%81%8A%E3%81%8F

### Dockerのログファイルサイズ制限
dockerdの設定を行い、最大ログサイズを制限することができます。

- 手順
  - `sudo nano /etc/docker/daemon.json` (daemon.jsonを作った覚えがない場合は新規ファイル)
  - 下記のような内容を貼り付けて保存し `sudo systemctl restart docker`を実行
```json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "1024m",
    "max-file": "10"
  }
}
```
- 参考
  - 公式ドキュメント
    - https://docs.docker.com/config/containers/logging/json-file/#usage
    - https://docs.docker.jp/config/daemon/daemon.html#id14
    - https://docs.docker.jp/engine/admin/systemd.html
  - DockerComposeのログドライバ設定でも同様の対応が可能
    - https://qiita.com/qualitia_cdev/items/23206b3aacb291b5ded2

### (MySQLを動かしている場合) DELETEクエリの調査
**DELETEで行を削除してもストレージは開放されません。** 実装が悪い場合、ゴミデータが溜まり大変なことになります。

- 対応方法
  - DB内から見たファイルサイズと、実体のファイルサイズを確認する
    - 大きく異なる場合は mysqldumpして作り直したり、実装の改善を検討する
- 参考
  - MySQLのDBから見たサイズを確認する方法
    - https://www.wakuwakubank.com/posts/323-mysql-capacity/
  - Dockerから見たボリュームサイズを確認する方法
    - https://docs.docker.com/engine/reference/commandline/system_df/
  - 失敗談
    - https://qiita.com/Domao/items/68c70cc88978e6297c6d#%E5%95%8F%E9%A1%8C%E3%81%AE%E7%99%BA%E7%94%9F