はじめに
「Bunは速い」。
もはや耳にタコができるほど聞いた言葉ですし、ローカル開発環境ではその爆速さに日々助けられています。
しかし、「速さはリソース(メモリ・CPU)の犠牲の上に成り立っている」 ということを、低スペックVPSでのデプロイ作業中に痛感しました。
本記事は、低メモリ環境でBunのビルドが落ち、結局npmに助けられた話と、その原因・解決策のまとめです。
環境と事象
環境
- VPS: メモリ 1GBの格安プラン
- OS: Ubuntu 22.04
- ランタイム: Bun v1.x
起こったこと
ローカルで開発したアプリをVPSにプルし、いざ起動準備。
bun install
bun run build
すると、いつまで経っても終わらない、あるいは唐突にコンソールに表示される非情なメッセージ。
Killed
ログを確認すると、OOM Killer(Out of Memory Killer) によってプロセスが強制終了されていました。
試しに npm install && npm run build を試してみると、時間はかかるものの、なんと完走しました。
なぜ「最新・最速」のBunがコケて、「枯れた」npmが動くのでしょうか。
原因:Bunは「全力」を出しすぎる
Bunが高速である理由の一つに、「利用可能なハードウェアリソース(CPUコア・メモリ)を極限まで並列利用する」 という設計思想があります。
- Bun: 「メモリあるだけ全部使って並列処理して、最短時間で終わらせるぜ!」
- npm: 「リソースを見ながら、順番にやっていくよ(比較的)」
ハイスペックな開発機(MacBook Proなど)ではBunのアプローチが最適ですが、リソースがカツカツのVPSでは、Bunが「まだいける」と判断してメモリを食いつぶした瞬間にOS側の許容量を超え、プロセスごとキルされてしまっていたのです。
解決策:それでもBunを使いたい場合
「npmに戻る」のも一つの手ですが、ロックファイルの互換性や開発体験の統一を考えると、サーバー上でもBunを使いたいケースは多いはずです。以下の3つの対策があります。
1. スワップ(Swap)領域を作成する【推奨】
物理メモリが足りないなら、ディスクをメモリ代わりに使うのが物理的かつ確実な解決策です。多くの格安VPSではデフォルトでスワップが無効になっています。
# 1GBのスワップファイルを作成する場合
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 確認
free -h
これで速度は落ちますが、OOMで落ちることはなくなります。
2. 並列数を制限して「手加減」させる
Bunには「本気を出させない」ための環境変数が用意されています。
インストールの並列数を1にする:
BUN_INSTALL_CONCURRENCY=1 bun install
JavaScriptエンジンのメモリ使用量にキャップをかける:
# 例:512MBに制限
BUN_JSC_forceRAMSize=536870912 bun install
3. ビルドと実行を分離する(ベストプラクティス)
そもそも、「非力なVPS上でビルドするな」 という話でもあります。
-
GitHub ActionsなどのCI環境で
bun buildを行う。 - 生成された
distディレクトリなどの成果物だけをVPSに転送する。 - VPS上では実行(ランタイムとしてのBun利用)のみ行う。
これならVPSのメモリは実行に必要な分だけで済みます。
それでも局所的なニーズとしてVPS上でビルドせざるを得ないことはあるはずです。
まとめ:npm再考
今回の件で、npm(およびNode.js)の「穏やかな挙動」は、リソース制約の厳しい環境においては一種の「堅牢性」である と再認識しました。
- リソースが潤沢な環境(ローカル・CI): Bun で爆速開発
-
リソースが貧弱な環境(格安VPS):
- Swapを設定して Bun を使う
- ビルド済みファイルを持ち込む
- あえて npm を使う
「速い」が正義とは限らない。適材適所でツールを選んでいきましょう。