Per service ulimits

Posted on May 12, 2015

In the good old days of sysvinit, if you wanted to run some extra code during start up, you were either (ab)using the sysconfig file or patching the init script itself. The init scripts in many packages are not as marked as configuration, which means in those cases your edits were lost. If it was marked as configuration then you have to merge your changes with those fixes manually. In either case … not ideal.

With systemd our “init scripts” are no longer shell scripts. Some of you might say “another argument against this crap”. But actually … systemd gives us an official solution for this problem. No more hacking init scripts. No more abusing sysconfig files

Let’s solve the problem

The original case of the question I got was “I need to increase the max file handles for dovecot. Can you add a sysconfig file? Your current init script does not use one.”

So my first answer was “Well no because we use systemd units on newer distros”.

So lets create the systemd override file. The fileformat will be from man 5 systemd.conf. For setting the maxfilehandles the file would look like.

Run systemctl edit servicename.service and add the following content:

[Service]
LimitNOFILE=8192
TasksMax=4096

So what about sysvinit?

Ideally if you introduce this way to support per service ulimits, it should also work with init scripts. For this we could add a patch to rc.status which converts the systemd syntax into ulimit calls. It will also need to handle translations like infinity -> unlimited.

Silver bullet?

Is the solution for systemd the silver bullet? No. you can still introduce conflicting changes, but the chances of a breakage are much lower. Also you can not override e.g. ExecStart. If you try it, systemd will complain that multiple ExecStart lines are only supported for oneshot services. But Pascal Volk from #dovecot came up with a nice solution for this as well.

For the main service file we use:

[Unit]
Description=Dovecot IMAP/POP3 email server
Documentation=man:dovecot(1)
Documentation=http://wiki2.dovecot.org/
After=local-fs.target network.target
 
[Service]
Type=simple
ExecStart=/usr/sbin/dovecot -F $OPTIONS
ExecReload=/usr/sbin/dovecot reload
NonBlocking=yes

[Install]
WantedBy=multi-user.target

That way we can add additional commandline arguments with a /etc/systemd/system/dovecot.service.d/service.conf, that looks like this:

[Service]
Environment='OPTIONS=-p'

Neat isn’t it?