systemd-nspwan で Elasticsearch の運用をしている。親のホストは ArchLinux なので新しい systemd が入ってくる。
ある日、 pacman -Syu
して systemd を 234 から 235 に上げたら Elasticsearch がエラーで落ちるようになった。
[2017-10-19T07:10:13,955][WARN ][o.e.b.JNANatives ] Unable to lock JVM Memory: error=1, reason=Operation not permitted [2017-10-19T07:10:13,957][WARN ][o.e.b.JNANatives ] This can result in part of the JVM being swapped out. ... ERROR: [1] bootstrap checks failed [1]: memory locking requested for elasticsearch process but memory is not locked
ソースコードを読むと、mlockall
できてなくて落ちていた。
調べた結果、systemd 235 では systemd-nspawn の SystemCallFilter がホワイトリストになり、 mlockall ができなくなった のが原因だった。
解決法
コンテナに CAP_IPC_LOCK
を与えるか、@memlock
グループを許可する。
例えば、 foo というコンテナであれば、 /etc/systemd/nspawn/foo.nspawn
に
[Exec] SystemCallFilter=@memlock # システムコールのみを許可する場合 Capability=CAP_IPC_LOCK # CAP_IPC_LOCK ごと許可する場合
を追加すれば良い。CAP_IPC_LOCK
を与えた場合、 @memlock
は自動で許可される。
詳細
systemd には SystemCallFilter
というのがあって、呼び出せる system call を制限できる。
https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=
systemd-nspawn では、デフォルトでこの制限がかかっており、もともとはブラックリストで制限されていた。
systemd 235 からこのリストのデフォルトがホワイトリスト形式になり、CAP_IPC_LOCK
がない場合は @memlock
が許可されないようになった。
* systemd-nspawn gained support for a new --system-call-filter= command line option for adding and removing entries in the default system call filter it applies. Moreover systemd-nspawn has been changed to implement a system call whitelist instead of a blacklist.
https://github.com/systemd/systemd/blob/c1719d8bc924ed59448616bd748671c5c7a66d93/NEWS
当該PRは以下*1。
https://github.com/systemd/systemd/pull/6818/files#diff-524fbe88b6a5bf2879b598646b22ed25R70
Elasticsearch では bootstrap.memory_lock: true
とした場合に mlockall
を内部で実行するのだが、これが権限不足で失敗していた。
これを解決するには、capability を足すか @memlock
を直接許可すれば良い。sytemd.nspawn 内でどちらも設定できる(「解決法」を参照)。
CAP_IPC_LOCK
を付加すると、自動的に @memlock
が付加される*2。
Note that the applied system call filter is also altered implicitly if additional capabilities are passed using the --capabilities=.
https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html#--system-call-filter=
@memlock
のみを許可した場合、コンテナに CAP_IPC_LOCK
は与えられないので、 RLIMIT_MEMLOCK
の範囲内で mlock
できるようになる。
In Linux 2.6.8 and earlier, a process must be privileged (CAP_IPC_LOCK) in order to lock memory and the RLIMIT_MEMLOCK soft resource limit defines a limit on how much memory the process may lock.
Since Linux 2.6.9, no limits are placed on the amount of memory that a privileged process can lock and the RLIMIT_MEMLOCK soft resource limit instead defines a limit on how much memory an unprivileged process may lock.