As discovered in the course of investigating bug 739274, the OpenRC runscript for docker defines a set of default options for the ulimit builtin which assume that the running shell is bash. The original reporter was not initially aware that docker was the cause, and I am now reporting this issue on his behalf.
Such an assumption is unacceptable for several reasons. Firstly, openrc-run(8) makes use of sh(1), except in the case that openrc was built with USE="bash". Secondly, it cannot be assumed that sh(1) is bash, even though it is by default in Gentoo. Thirdly, POSIX only defines one option for the ulimit builtin, which is -f and that's used for setting RLIMIT_FSIZE. All other options are non-standard, and no implementation of the POSIX Shell Command Language is under any obligation to implement them. Fourthly, even where a sh(1) implementation does implement any non-standard options, they will inevitably differ. For example, bash supports the -u option to define RLIMIT_NPROC but dash supports the -p option for this purpose.
In short, if the runscript is going to continue to define bash-specific ulimit options then it should make a point of running bash. I shall attach a revised runscript which addresses the issue in this manner.
Note that the original bug stands on its own merits because OpenRC has weak error reporting in the case that the ulimit command fails, presenting an opportunity to improve it.
Created attachment 681301 [details]
This is a replacement docker.initd file which differs by spawning an instance of bash to set the rlimits before replacing itself with docker. Andrew, would you mind testing this?
Created attachment 681307 [details]
First one contained a silly typo. Try this one.
Oh, I've already rebuilt my openrc with +bash, but sure, why not. I'll report the results upon the next boot (running it directly yields no problems). Thanks Kerin!
(In reply to Andrew from comment #3)
> Oh, I've already rebuilt my openrc with +bash, but sure, why not. I'll
> report the results upon the next boot (running it directly yields no
> problems). Thanks Kerin!
Note that, after starting docker with the revised runscript, you may test that the intended rlimits have taken effect by running:
read -r pid < /run/docker.pid && cat "/proc/$pid/limits"
Assuming that you haven't defined and customised DOCKER_ULIMIT in the conf.d file, you should see that the reported limits reflect the intention of the default options (-c unlimited -n 1048576 -u unlimited). Moreover, it should do so regardless of which /bin/sh provider you are using.
I recommend opening a bug upstream and asking them to remove
the non-posix options from the init script. The init script should not,
by default, use non-posix ulimit options.
They could document other recommended options in docker.confd.
Which options are non-posix? Also do you want to open the bug or should
As explained in the opening comment and in bug 739274, -f is the only option specified by POSIX. If one is to be serious about POSIX conformance, one must walk the walk, not just talk the talk. There is simply no sugar-coating the fact that there is only one standard option and that there is no generalised mechanism allowing for OpenRC runscripts to assert rlimits in a fashion that is independent of the shell. Other init systems address this issue by taking direct responsibility for defining rlimits - such as systemd - or by offering helpers - such as s6 with its s6-softlimit utility.
I do sometimes file bugs upstream but won't be doing so on this occasion. You suggest that it might be possible to define equivalent rc_ulimit options in the conf.d file for some of the more popular shells. This is simply not feasible. Let's take dash as an example. The present set of options can be made to work with two caveats. Firstly, -u must be changed to -p. I did mention this in the other bug. Secondly, one _cannot_ overload ulimit with multiple option/value pairs. Instead, one would have to run three consecutive ulimit commands, like so:-
ulimit -c unlimited && ulimit -n 1048576 && ulimit -p unlimited
All of this should amply demonstrate that OpenRC's ulimit support is useless outside of the confines of bash. Even putting aside the obvious issue of option portability, OpenRC has no expectation that it might need to run ulimit more than once, nor does it know how to do so. Perhaps now you can understand why the attached runscript compromises by having bash set the rlimits. If there were an obviously better option, I would have taken it.
(In reply to Kerin Millar from comment #2)
> Created attachment 681307 [details]
> First one contained a silly typo. Try this one.
So I've tried this init script (with openrc -bash flag) and Docker started properly with correct limits.
(In reply to Andrew from comment #7)
> So I've tried this init script (with openrc -bash flag) and Docker started
> properly with correct limits.
Good. As bash is part of @system, I think that it is a reasonable solution until such time as OpenRC offers a shell-independent way of defining resource limits.
As an aside, I noticed something interesting about the way in which the ulimit builtin operates in bash. It internally defines all possible rlimits but calculates the options supported by the platform during runtime. That means that the option parser can reject options based on the platform, though the documentation and builtin help always imply that all are recognisable, if not actionable.
$ help ulimit | grep -- -T
-T the maximum number of threads
$ ulimit -T
-bash: ulimit: -T: invalid option
ulimit: usage: ulimit [-SHabcdefiklmnpqrstuvxPT] [limit]