はじめに
さくらVPSの最小プランでインフラを構築する際に、メモリ不足で色々と不具合が起こった際にスワップファイルを利用することで無理矢理解決したので、メモとして残します!
VPSの性能
- OS: Debian 12
- アーキテクチャ: amd64(64ビット版)
- リージョン: 東京第2(データセンターの場所)
- メモリ: 512MB
インフラ構成
すごくざっくりですが、こんなイメージです。
さくらVPS
┌───────────────┐
│ │
│ ┌───────┐ │
│ │ MySQL │ │
│ └───────┘ │
│ │
│ Docker │
│ ┌───────────┐ │
│ │ │ │
│ │ Rails │ │
│ │ (API │ │
│ │ Server) │ │
│ └───────────┘ │
└───────────────┘
接続:Rails (Docker) ⇔ MySQL (VPS上)
MySQLのインストール、起動時に問題発生
上記のインフラを構築するため
VPSを借りて、MySQLをaptでインストールし、起動する際に下記のエラーが発生しました。
sudo apt install mysql-server
dpkg: error processing package mysql-community-server (--configure): installed mysql-community-server package post-installation script subprocess returned error exit status 137
137のexit statusコードが吐き出されているので、まずこれが何か調べてみます。
137 exit statusコードとは?
Exit code 137 typically indicates that a process inside a container was killed by the system due to an out-of-memory (OOM) condition. When the operating system detects that it's running out of memory, it invokes the OOM killer, which terminates processes to free up memory. In the context of containers, this often results in the following error messages:
終了コード137は通常、コンテナ内のプロセスがメモリ不足(OOM)状態のためにシステムによって強制終了されたことを示す。
どうやらメモリ不足により、終了を表すコードのようです。
topコマンドで確認してみる
実行中のメモリの使用量をtopコマンドで見てみました
top
MiB Mem : 457.6 total, 6.2 free, 444.9 used, 16.6 buff/cache
6.2MBしか余裕がないですね笑
この後、137 exit codeが吐き出されるので、メモリ不足には間違いなさそうです。
解決方法
一番簡単な解決方法はスケールアップすることです。
ただ、当然料金が嵩みます。
利用者の限られるアプリに使用するため、できるだけコストは抑えたいです。
色々と調べた結果、処理速度等は物理メモリに比べて低下しますがスワップ領域を使用して、ハードディスクの一部をメモリのように扱うことで不足を補えるようなので、そのアプローチをとってみることにします。
Linux の スワップ領域 は、物理メモリー (RAM) が不足すると使用されます。システムに多くのメモリーリソースが必要で、RAM が不足すると、メモリーの非アクティブなページがスワップ領域に移動します。
使われていないメモリの内容を割り当てたハードディスクの領域(スワップ領域)に移動させることで、RAMの不足を補うといった仕組みのようですね。
スワップ領域の追加
さくらVPSの公式にやり方が記載されていたのでこちらを参照しました。
1.空き容量の確認
df -h /
いくつかファイルシステムが表示されますが/
(ルート)がマウントされている/dev/vda2の空き容量を確認します。
Availが18Gなので十分な容量があることが確認できました。
Filesystem Size Used Avail Use% Mounted on
/dev/vda2 25G 3.7G 18G 15% /
2.スワップファイルの作成
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
-
sudo
:管理者権限で実行 -
dd
:指定したサイズのファイルを作成するコマンド -
if=/dev/zero
:/dev/zero
はデバイスファイルで、ゼロ(0)が無限に出力される。これによりゼロで埋められたデータをスワップファイルに書き込む -
of=/swapfile
:出力ファイルにスワップファイルを指定しています -
bs=1M
:ブロックサイズを1MBに設定 -
count=2048
:上記で指定した1Mのブロックの数を2048に設定し、合計2GB(1MB * 2048 = 2GB)のスワップファイルを作成
これで/
直下にswapfile
が作成されます。
0で埋めてスワップ領域を確保するイメージですね。
3. スワップファイルのアクセス権限の設定
sudo chmod 600 /swapfile
これで作成したswapfileに600の権限を設定します
600はファイルの所有者にのみ読み書き許可を付与する設定です
所有者以外はスワップファイルを読み書きできなくすることで、セキュリティを強化しています。
Linuxの権限については、下記の記事にまとめています!
4. スワップファイルの初期化
作成しただけでは、まだ使えません。
作成したファイルをスワップファイルとして認識させる必要があります
mkswapコマンドが指定したファイルをスワップ領域として初期化するコマンドになります
引数に先ほど作成したswapfileのパスを指定します。
sudo mkswap /swapfile
このコマンドでスワップファイルに必要なメタデータが設定され、システムがスワップ領域として認識できるようになります
5.swapファイルの有効化
次に認識させたswapファイルを有効化します
sudo swapon /swapfile
これでメモリが不足した際に、作成したswapfileを使用するようになります。
設定ができているか確認
free
Swap: 2097148 0 2097148
上記のように Swap領域が表示されるようになっていれば完了です!
6.バックアップの作成
sudo cp -p /etc/fstab /etc/fstab.org
7.swapの設定を永続化
echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstab:
ehcoで出力した/swapfile none swap sw 0 0
設定ファイルに記載したい文字列をteeコマンドに渡して/etc/fstav
ファイルの末尾に追加しています。
設定の意味を下記の通り
- /swapfile: スワップ領域として利用するファイル
- none: デバイス名ではなくファイルを使用するため、none を指定
- swap: スワップ領域であることを示す
- sw: スワップ領域に適用するオプション
- 0 0: ディスクのバックアップやチェックの設定(スワップ領域には適用しないため 0 を指定)
再度MySQLのインストール、起動に挑戦
念の為、一度アンインストールしてから行います。
関連するパッケージ、依存関係の削除
sudo apt-get remove --purge mysql-server mysql-client mysql-common
sudo apt-get autoremove
sudo apt-get autoclean
パッケージリストを更新
sudo apt-get update
再度インストール
sudo apt-get install mysql-server
sudo systemctl status mysql
起動状態の確認
● mysql.service - MySQL Community Server
Loaded: loaded (/lib/systemd/system/mysql.service; enabled; preset: enabled)
Active: active (running) since Fri 2024-10-25 08:40:08 JST; 0 days ago
Docs: man:mysqld(8)
http://dev.mysql.com/doc/refman/en/using-systemd.html
Process: 29759 ExecStartPre=/usr/share/mysql-8.0/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
Main PID: 29795 (mysqld)
Status: "Server is operational"
Tasks: 41 (limit: 504)
Memory: 50.4M
CPU: 29min 27.873s
CGroup: /system.slice/mysql.service
└─29795 /usr/sbin/mysqld
無事インストールし、起動することができました!
まとめ
スワップファイルを作成して有効化することで、なんとかメモリ不足をカバーでき、MySQLも無事にインストール・起動できました。少し手間はかかりますが、物理メモリが増やせない環境での応急処置の一つの方法として勉強になりました!