何が起きているか
スクリプトを実行したり、サービスを起動したり、サーバーにSSH接続しようとしたりすると、突然すべてがこのエラーで止まってしまいます:
bash: fork: retry: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
新しいプロセスが起動できません。SSH接続はタイムアウトし、cronジョブは無言で失敗します。RAMは十分あり、CPUはアイドル状態で、サーバーは明らかに動いているのに、何もforkできません。**最大ユーザープロセス数(nproc)**の上限に達してしまっているのです。
Linuxは各ユーザーが任意の時点で所有するプロセス数を追跡しています。その上限に達すると、fork()がEAGAINを返します。これがまさに今起きていることです。
まず診断する
現在の制限を確認する
# 現在のシェルセッションの制限を確認
ulimit -a
# 最大ユーザープロセス数を確認
ulimit -u
古いシステムではデフォルト値が非常に低く設定されています:
max user processes (-u) 1024
最近のsystemdディストリビューションはデフォルト値が高め(Ubuntu 22.04では63503など)ですが、専用ユーザーで動作するサービスは多くの場合、PAMの低い制限値を継承します。場合によってはまだ1024のままです。
影響を受けているユーザーが実行中のプロセス数を数える
# 'www-data' を実際のユーザー名に置き換えてください
ps -u www-data --no-header | wc -l
# またはプロセス数でソートして全ユーザーを表示
ps aux | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
この数がulimitの値以上または近い場合、問題が確認できます。
PAMで設定された制限(実際の上限)を確認する
grep -r nproc /etc/security/limits.conf /etc/security/limits.d/
次のような内容が表示されることがあります:
* soft nproc 1024
* hard nproc 4096
soft制限はプロセスが開始時に持つ値です。hard制限はプロセスが自分で引き上げられる最大値です。両方が低いことが原因です。
systemdが強制する制限を確認する(サービス向け)
注意点があります:影響を受けているプロセスがsystemdサービスの場合、/etc/security/limits.confはまったく適用されないことが多く、systemdが独自に制限を管理します。
# 実行中のサービス(例:nginx)の有効な制限を確認
systemctl show nginx | grep -i task
# または特定のPIDの /proc を確認
cat /proc/$(pgrep -o nginx)/limits | grep processes
修正する
方法1:現在のセッションの制限を引き上げる(一時的)
簡単なテストや一回限りのスクリプトに適しています。シェルを閉じると同時にリセットされます。
# soft制限を8192に引き上げる
ulimit -u 8192
# 確認
ulimit -u
引き上げられるのはhard制限までです。hard制限の引き上げにはroot権限が必要です。
方法2:PAM経由で恒久的な制限を設定する(ログインユーザーとデーモン向け)
/etc/security/limits.d/に新しいファイルを追加します。limits.confを直接編集するより整理されています:
sudo nano /etc/security/limits.d/99-nproc.conf
以下の行を追加します(実際のワークロードに合わせて値を調整してください):
# 全ユーザーのnprocを引き上げる
* soft nproc 65536
* hard nproc 65536
# または特定のユーザーを対象にする
www-data soft nproc 32768
www-data hard nproc 32768
# rootは * ワイルドカードから除外されることが多いため、必要であれば明示的に設定する
root soft nproc unlimited
root hard nproc unlimited
**重要:**PAMの制限は新しいログインセッションにのみ適用されます。既存のプロセスは古い制限を維持します。変更を反映させるにはサービスを再起動するか、一度ログアウトして再ログインしてください。
方法3:systemdサービスの制限を修正する
PAMの制限はsystemdが起動したサービスには届きません。ドロップインファイルを使ってサービスごとに上書きします:
sudo systemctl edit nginx
以下を追加します:
[Service]
TasksMax=infinity
LimitNPROC=65536
その後、リロードして再起動します:
sudo systemctl daemon-reload
sudo systemctl restart nginx
すべてのsystemdサービスのグローバルデフォルトを引き上げるには、/etc/systemd/system.confを編集します:
sudo nano /etc/systemd/system.conf
[Manager]
DefaultTasksMax=infinity
sudo systemctl daemon-reload
方法4:プロセスリークを確認する(根本原因を修正する)
制限を引き上げるのは症状への対処です。ゾンビプロセスや無限に子プロセスを生成するループが真の問題であれば、制限を上げても長くはもちません。
# ゾンビプロセスを一覧表示
ps aux | awk '$8 == "Z"'
# 特定ユーザーのプロセス数が増え続けているか監視
watch -n 2 "ps -u myuser --no-header | wc -l"
# 子プロセスを大量に生成している親プロセスを探す
ps -eo pid,ppid,user,comm | awk '{print $2}' | sort | uniq -c | sort -rn | head -5
カウントが増え続けて一向に減らない場合はリークです。アプリケーションを修正してください。
修正が効いたか確認する
# limits.confの変更を適用後、新しいセッションを開いて確認:
ulimit -u
# systemdサービスの場合、新しい制限が有効になっているか確認:
cat /proc/$(pgrep -o nginx)/limits | grep processes
# ストレステスト — 100個のバックグラウンドプロセスを起動:
for i in $(seq 1 100); do sleep 1 & done
# 'Resource temporarily unavailable' が出ずに完了するはず
jobs | wc -l
kill $(jobs -p)
クイックリファレンス:ディストリビューション別の一般的なデフォルト値
- CentOS 6 / RHEL 6:非rootユーザーのデフォルトnproc = 1024 — JavaアプリケーションやRuby on Railsのデプロイメントは常にこの値を超えてしまいます
- CentOS 7 / RHEL 7+:
/etc/security/limits.d/20-nproc.confが4096で同梱されています —limits.confではなくこの特定のファイルを確認して上書きしてください - Ubuntu 20.04+:systemd管理で、TasksMaxのデフォルトはシステム最大値の15%(一般的なVPSでは約4915)— 高い同時実行性を持つサービスはまだ上限に達します
- Dockerコンテナ:デフォルトではホストのulimitを継承します。多数の並行プロセスを持つコンテナを実行する際は
--ulimit nproc=65535:65535を渡してください
実際によくある原因:CIランナー
最もよく見かける場面は、JenkinsやGitLab Runnerのインスタンスで20並列ビルドを実行している場合です。各ジョブはシェル、コンパイラ、テストスイートをforkします。1ジョブあたり60以上のプロセスが、20ジョブ分で掛け合わされ、数秒で1024を超えてしまいます。
サービスを実行するユーザーに対しては、nprocを少なくとも65536に設定してください。コストはゼロです。これはメモリの予約ではなく、カーネルの計算上の制限に過ぎません。
もう一点:PAMは設定されているがsystemdがサービスを管理しているシステムでは、limits.confを修正するだけでは解決しません。両方の設定が必要です。

