環境
- Ubuntu 24.04
問題
カーネルパラメータを変更したく、 /etc/sysctl.d/配下にの/etc/sysctl.d/99-my.conf に
net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.ipv4.tcp_rmem = 4096 87380 16777216 net.ipv4.tcp_wmem = 4096 65536 16777216
設定した。しかし sysctl -p しても反映されない。AIに聞いてみたら sysctl -p ではなかった。
誤解してた
結論から言うと、引数なしの sysctl -p は /etc/sysctl.conf しか読み込まない。/etc/sysctl.d/ 配下の .conf ファイルは最初から対象外だ。
つまり 99-my.conf に何を書こうが sysctl -p では永遠に反映されない。コメントしか書かれていない実質空の /etc/sysctl.conf を読み直して、何事もなかったかのように終了していただけだった。
正解はこっち。
sudo sysctl --system
読み込む対象の違いはこうなっている。
| コマンド | 読み込む対象 |
|---|---|
sysctl -p |
/etc/sysctl.conf のみ(引数でファイル指定も可) |
sysctl -p /etc/sysctl.d/99-my.conf |
指定した1ファイルのみ |
sysctl --system |
/etc/sysctl.d/、/run/sysctl.d/、/usr/lib/sysctl.d/ などの配下の .conf ファイルを優先順位に従って全部読み込み、最後に /etc/sysctl.conf も反映 |
ややこしいのは、同じ /etc/sysctl.d/ に vm.swappiness あたりを置いていると「そっちは効いてるじゃん」となるケース。あれはブート時にsystemdの systemd-sysctl.service が /etc/sysctl.d/*.conf を全部読んで適用しているからで、sysctl -p が効いたわけではない。再起動さえ挟めば反映されるので、余計に原因が分かりにくい。
反映されたかどうかの確認
sysctl net.core.rmem_max
sysctl --system は適用したファイルを順に出力してくれるので、パラメータ名のtypoやカーネルモジュール未ロードがあれば sysctl: cannot stat ... のようなエラーがその場で出る。文法チェックも兼ねられて便利。
それでも値が変わらないなら、他のファイルに上書きされている可能性を疑う。
grep -r "rmem_max" /etc/sysctl.d/ /etc/sysctl.conf /etc/ufw/sysctl.conf 2>/dev/null
/etc/sysctl.d/ 内では同じパラメータがあった場合、ファイル名のアルファベット順で後勝ちになる。Ubuntuにはデフォルトで 99-sysctl.conf -> ../sysctl.conf というシンボリックリンクが置かれていて、これは 99-my.conf より後("s" > "m")に処理される。/etc/sysctl.conf 側に同じキーが書いてあれば当然そっちが勝つ。
あとufwを使っているなら /etc/ufw/sysctl.conf も見ておいたほうがいい。こいつが /etc/sysctl.conf の設定を上書きすることがあり、地味に見落としやすい罠になっている。
昔は sysctl -p が正解だと思ってた
10年以上前に触っていたときは sysctl -p で通っていたはずなんだが、と思って調べてみたら、sysctl -p の挙動自体は当時から今まで一切変わっていなかった。変わったのは周辺のエコシステムのほうだった。
- 設定を
/etc/sysctl.d/に分割して置くやり方が普及した。- これはsystemdが持ち込んだ仕組みで、
systemd-sysctl.serviceがブート時に/etc/sysctl.d/*.confを自動で読み込む。 - Ubuntuがsystemdを正式採用したのは15.04(2015年)で、それ以前はUpstartやSysV initが主流。
- 設定は
/etc/sysctl.confに全部書いてsysctl -pで読ませる、という運用がごく普通だった
- これはsystemdが持ち込んだ仕組みで、
- procps側に
--systemオプションが追加された。- それ以前は
/etc/sysctl.d/配下を手動でまとめて反映させたければ、ファイルを1個ずつsysctl -p ファイル名で指定するしかなかった
- それ以前は
なので「昔は sysctl -p でよかった」という記憶自体は間違っていない。今でも /etc/sysctl.conf に直書きしている環境なら sysctl -p で問題なく反映される。設定の置き場所だけ今風の /etc/sysctl.d/ に乗り換えておいて、コマンドは昔のまま、というギャップにハマっただけだった。
ちなみに --system の読み込み順は /etc/sysctl.d/ → /run/sysctl.d/ → /usr/lib/sysctl.d/ → ... → 最後に /etc/sysctl.conf となっている。この一覧の最後に /etc/sysctl.conf が居座っているあたり、今でもこいつは「最後に読まれて他を上書きできる」特別な立ち位置を保ち続けているらしい。