これは、なにをしたくて書いたもの?
Linuxにおけるリソース制御といえば、ulimitです。
limits.conf(5) - Linux manual page
/etc/security/limits.conf
ファイルや/etc/security/limits.d
ディレクトリ内に[任意の名前].conf
ファイルを作成して
nofile
などの値を設定すればOKです。
ですが、systemd制御下で動作するプロセスはこの事情が違います。前々からなんとなく知ってはいましたが、
自分で設定したことがなかったので試しておくことにしました。
環境
今回の環境は、こちら。Ubuntu Linux 20.04 LTSです。
$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.3 LTS Release: 20.04 Codename: focal $ uname -srvmpio Linux 5.4.0-91-generic #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
また、リソース制御を行う対象のサービスとして、nginxを使うことにします。
$ sudo apt install nginx
バージョン。
$ nginx -v nginx version: nginx/1.18.0 (Ubuntu)
インストールした時点で、nginxはrootユーザーで起動しています。
$ ps -ef | grep nginx | grep -v grep root 3976 1 0 14:32 ? 00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; www-data 3977 3976 0 14:32 ? 00:00:00 nginx: worker process www-data 3978 3976 0 14:32 ? 00:00:00 nginx: worker process
この時の/proc/[PID]/limits
を見ると、Max open filesのsoft limitが1024になっているので、こちらを変更してみましょう。
$ cat /proc/$(cat /run/nginx.pid)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7596 7596 processes Max open files 1024 524288 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7596 7596 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
/etc/security/limits〜が効かないことを確認する
まずは/etc/security/limits〜が効かないことを確認してみます。
rootユーザーにスイッチして、現在の値を確認。
$ sudo su - # ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 7596 max locked memory (kbytes, -l) 65536 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 7596 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
ファイルの書き方は、/etc/security/limits.conf
ファイルに書かれているので
/etc/security/limits.conf
# /etc/security/limits.conf # #Each line describes a limit for a user in the form: # #<domain> <type> <item> <value> # #Where: #<domain> can be: # - a user name # - a group name, with @group syntax # - the wildcard *, for default entry # - the wildcard %, can be also used with %group syntax, # for maxlogin limit # - NOTE: group and wildcard limits are not applied to root. # To apply a limit to the root user, <domain> must be # the literal username root. # #<type> can have the two values: # - "soft" for enforcing the soft limits # - "hard" for enforcing hard limits # #<item> can be one of the following: # - core - limits the core file size (KB) # - data - max data size (KB) # - fsize - maximum filesize (KB) # - memlock - max locked-in-memory address space (KB) # - nofile - max number of open file descriptors # - rss - max resident set size (KB) # - stack - max stack size (KB) # - cpu - max CPU time (MIN) # - nproc - max number of processes # - as - address space limit (KB) # - maxlogins - max number of logins for this user # - maxsyslogins - max number of logins on the system # - priority - the priority to run user process with # - locks - max number of file locks the user can hold # - sigpending - max number of pending signals # - msgqueue - max memory used by POSIX message queues (bytes) # - nice - max nice priority allowed to raise to values: [-20, 19] # - rtprio - max realtime priority # - chroot - change root to directory (Debian-specific) # #<domain> <type> <item> <value> # #* soft core 0 #root hard core 100000 #* hard rss 10000 #@student hard nproc 20 #@faculty soft nproc 20 #@faculty hard nproc 50 #ftp hard nproc 0 #ftp - chroot /ftp #@student - maxlogins 4 # End of file
こんなファイルを作成。
/etc/security/limits.d/root.limits.conf
root - nofile 10240
1度シェルを抜けて、再度rootにスイッチして確認。
$ sudo su - # ulimit -n 10240 # ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 7596 max locked memory (kbytes, -l) 65536 max memory size (kbytes, -m) unlimited open files (-n) 10240 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 7596 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
open files
の値が増えていることが確認できます。
このあたりは、PAMの範囲です。
$ grep -r limit /etc/pam.d /etc/pam.d/runuser:session required pam_limits.so /etc/pam.d/systemd-user:session required pam_limits.so /etc/pam.d/sshd:# access limits that are hard to express in sshd_config. /etc/pam.d/sshd:# Set up user limits from /etc/security/limits.conf. /etc/pam.d/sshd:session required pam_limits.so /etc/pam.d/atd:session required pam_limits.so /etc/pam.d/login:# set access limits. /etc/pam.d/login:# Sets up user limits according to /etc/security/limits.conf /etc/pam.d/login:# (Replaces the use of /etc/limits in old login) /etc/pam.d/login:session required pam_limits.so /etc/pam.d/su:# Sets up user limits according to /etc/security/limits.conf /etc/pam.d/su:# (Replaces the use of /etc/limits in old login) /etc/pam.d/su:session required pam_limits.so /etc/pam.d/cron:# Sets up user limits, please define limits for cron tasks /etc/pam.d/cron:# through /etc/security/limits.conf /etc/pam.d/cron:session required pam_limits.so
なのですが、nginxを再起動しても
$ sudo systemctl restart nginx
こちらのMax open filesの値は変わりません。
$ cat /proc/$(cat /run/nginx.pid)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7596 7596 processes Max open files 1024 524288 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7596 7596 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
こちらは事情が異なります、と。
今回は、これを変更できるようにすることが目的です。
systemdのドキュメントを読む
systemdのユニットのリソース制御は、ユニット定義ファイルで行います。
こちらを見ると、プロセスのリソース制御について書かれています。
PROCESS PROPERTIES
LimitCPU=, LimitFSIZE=, LimitDATA=, LimitSTACK=, LimitCORE=, LimitRSS=, LimitNOFILE=, LimitAS=, LimitNPROC=, LimitMEMLOCK=, LimitLOCKS=, LimitSIGPENDING=, LimitMSGQUEUE=, LimitNICE=, LimitRTPRIO=, LimitRTTIME=
[https://man7.org/linux/man-pages/man5/systemd.exec.5.html:title]
各項目が、ulimitのどの項目に該当するかも書かれていますね。
Table 1. Resource limit directives, their equivalent ulimit shell commands and the unit used
LimitNOFILE
ulimit -n
プロセスのリソース制御も含め、こういったカテゴリのものが設定できるようなので、ドキュメントには
目を通しておくとよいでしょう。
- PATHS
- USER/GROUP IDENTITY
- CAPABILITIES
- SECURITY
- MANDATORY ACCESS CONTROL
- PROCESS PROPERTIES
- SCHEDULING
- SANDBOXING
- …
今回の対象のnginxのサービスユニット定義ファイルはこちらなので
/etc/systemd/system/multi-user.target.wants/nginx.service
# Stop dance for nginx # ======================= # # ExecStop sends SIGSTOP (graceful stop) to the nginx process. # If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control # and sends SIGTERM (fast shutdown) to the main process. # After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends # SIGKILL to all the remaining processes in the process group (KillMode=mixed). # # nginx signals reference doc: # http://nginx.org/en/docs/control.html # [Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) After=network.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;' ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;' ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid TimeoutStopSec=5 KillMode=mixed [Install] WantedBy=multi-user.target
Service
にLimitNOFILE
を設定。
[Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;' ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;' ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid TimeoutStopSec=5 KillMode=mixed LimitNOFILE=10240
設定をリロードして、nginxを再起動。
$ sudo systemctl daemon-reload $ sudo systemctl restart nginx
変更が反映されましたね。
$ cat /proc/$(cat /run/nginx.pid)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7596 7596 processes Max open files 10240 10240 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7596 7596 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
hard limitも一緒の値になってしまいましたが。
これが気持ち悪い場合は、以下のようにするとsoft limitとhard limitをそれぞれ指定できます。
LimitNOFILE=10240:524288
再読み込みして、再起動後して確認。
$ cat /proc/$(cat /run/nginx.pid)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7596 7596 processes Max open files 10240 524288 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7596 7596 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
soft limitとhard limitをそれぞれ指定できました。
これは、ドキュメントにそのように書いてあります。
Resource limits may be specified in two formats: either as single value to set a specific soft and hard limit to the same value, or as colon-separated pair soft:hard to set both limits individually (e.g. "LimitAS=4G:16G").
ここで、1度ユニット定義ファイルを元に戻します。
[Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;' ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;' ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid TimeoutStopSec=5 KillMode=mixed
このように、パッケージでインストールされたユニット定義ファイルを触るのは嫌だと思うかもしれません。
そこで、「drop-in」という仕組みを使います。以下のように/etc/systemd/system/[サービス名].d
というディレクトリを
作成します。
$ sudo mkdir /etc/systemd/system/nginx.service.d
この中に置いたファイルは、「drop-in」という仕組みでユニット構成ファイルをオーバーライドできるようです。
※なのですが、drop-inについて調べるとだいたい先ほどmkdir
で作成したディレクトリの情報が現れるのですが、これは
どこの情報なんでしょうね?
In addition to the "main" configuration file, drop-in configuration snippets are read from /usr/lib/systemd/.conf.d/, /usr/local/lib/systemd/.conf.d/, and /etc/systemd/.conf.d/. Those drop-ins have higher precedence and override the main configuration file. Files in the .conf.d/ configuration subdirectories are sorted by their filename in lexicographic order, regardless of in which of the subdirectories they reside. When multiple files specify the same option, for options which accept just a single value, the entry in the file sorted last takes precedence, and for options which accept a list of values, entries are collected as they occur in the sorted files.
When packages need to customize the configuration, they can install drop-ins under /usr/. Files in /etc/ are reserved for the local administrator, who may use this logic to override the configuration files installed by vendor packages. Drop-ins have to be used to override package drop-ins, since the main configuration file has lower precedence. It is recommended to prefix all filenames in those subdirectories with a two-digit number and a dash, to simplify the ordering of the files.
systemd-system.conf(5) - Linux manual page
ファイル名には2桁の数字を付けることが推奨されているようなので
It is recommended to prefix all filenames in those subdirectories with a two-digit number and a dash, to simplify the ordering of the files.
こんな感じに作成して
/etc/systemd/system/nginx.service.d/00-limits.conf
[Service] LimitNOFILE=10240:524288
再読み込みさせると
$ sudo systemctl daemon-reload $ sudo systemctl restart nginx
反映されました。
$ cat /proc/$(cat /run/nginx.pid)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7596 7596 processes Max open files 10240 524288 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7596 7596 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
systemctl status
を見ると、「Drop-In」という表示が現れるようになっています。
$ sudo systemctl status nginx ● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Drop-In: /etc/systemd/system/nginx.service.d └─00-limits.conf Active: active (running) since Thu 2021-12-02 15:32:01 JST; 42s ago Docs: man:nginx(8) Process: 6734 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Process: 6735 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Main PID: 6736 (nginx) Tasks: 3 (limit: 2278) Memory: 3.5M CGroup: /system.slice/nginx.service ├─6736 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; ├─6737 nginx: worker process └─6738 nginx: worker process 12月 02 15:32:01 ubuntu2004.localdomain systemd[1]: Starting A high performance web server and a reverse proxy server... 12月 02 15:32:01 ubuntu2004.localdomain systemd[1]: Started A high performance web server and a reverse proxy server.
全体のデフォルト値を変更する
最後に、systemdで管理しているユニット全体のデフォルト値を変更してみましょう。あまり使う機会はない気はしますが。
先ほどのnginxのdrop-inのファイルはコメントアウトして
/etc/systemd/system/nginx.service.d/00-limits.conf
#[Service] #LimitNOFILE=10240:524288
nginxにも反映しておきます(デフォルトに戻しておきます)。
$ cat /proc/$(cat /run/nginx.pid)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7596 7596 processes Max open files 1024 524288 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7596 7596 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
これは、以下で指定します。
DefaultLimitCPU=, DefaultLimitFSIZE=, DefaultLimitDATA=, DefaultLimitSTACK=, DefaultLimitCORE=, DefaultLimitRSS=, DefaultLimitNOFILE=, DefaultLimitAS=, DefaultLimitNPROC=, DefaultLimitMEMLOCK=, DefaultLimitLOCKS=, DefaultLimitSIGPENDING=, DefaultLimitMSGQUEUE=, DefaultLimitNICE=, DefaultLimitRTPRIO=, DefaultLimitRTTIME=
ファイルの場所は、このあたりのようですね。
/etc/systemd/system.conf, /etc/systemd/system.conf.d/.conf, /run/systemd/system.conf.d/.conf, /usr/lib/systemd/system.conf.d/*.conf
~/.config/systemd/user.conf, /etc/systemd/user.conf, /etc/systemd/user.conf.d/.conf, /run/systemd/user.conf.d/.conf, /usr/lib/systemd/user.conf.d/*.conf
systemd-system.conf(5) - Linux manual page
実際、/etc/systemd/system.conf
ファイルを見ると、コメントアウトされていますが設定項目があるのがわかります。
$ grep DefaultLimit /etc/systemd/system.conf
#DefaultLimitCPU= #DefaultLimitFSIZE= #DefaultLimitDATA= #DefaultLimitSTACK= #DefaultLimitCORE= #DefaultLimitRSS= #DefaultLimitNOFILE=1024:524288 #DefaultLimitAS= #DefaultLimitNPROC= #DefaultLimitMEMLOCK= #DefaultLimitLOCKS= #DefaultLimitSIGPENDING= #DefaultLimitMSGQUEUE= #DefaultLimitNICE= #DefaultLimitRTPRIO= #DefaultLimitRTTIME=
ちなみに、これはManager
という設定カテゴリになります。
[Manager]
これらの項目は、systemdで管理されているサービスすべてに影響するので、あまり使うことはないかなと思いますが。
試すだけ試しておきましょう。
ここで、以下のように設定して
[Manager] DefaultLimitNOFILE=10240:524288
反映。
$ sudo systemctl daemon-reload $ sudo systemctl restart nginx
確認。
$ cat /proc/$(cat /run/nginx.pid)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7596 7596 processes Max open files 10240 524288 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7596 7596 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
今回はnginxだけ再起動して確認してみましたが、デフォルト値設定後に起動したプロセスには影響するように
なります。
また、このファイルも別に切り出すことができます。
ルールがこうなので
/etc/systemd/system.conf, /etc/systemd/system.conf.d/.conf, /run/systemd/system.conf.d/.conf, /usr/lib/systemd/system.conf.d/*.conf
~/.config/systemd/user.conf, /etc/systemd/user.conf, /etc/systemd/user.conf.d/.conf, /run/systemd/user.conf.d/.conf, /usr/lib/systemd/user.conf.d/*.conf
ディレクトリを作成して
$ sudo mkdir /etc/systemd/system.conf.d
ファイルを作成。
/etc/systemd/system.conf.d/00-override.conf
[Manager] DefaultLimitNOFILE=10240:524288
再読込して、反映。
$ sudo systemctl daemon-reload $ sudo systemctl restart nginx
変更が確認できました。
$ cat /proc/$(cat /run/nginx.pid)/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 7596 7596 processes Max open files 10240 524288 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 7596 7596 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
まとめ
systemd制御下で動作するプロセスの、リソース制御を行ってみました。
drop-inファイルの場所とドキュメントの書かれ方にちょっと癖がある気がしますが(Ubunut Linuxだからですかね…)、
ここだけちょっとハマりました。
だいたいやり方はわかったので良しとしましょう。