<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Sysctl on Lessons learned</title><link>https://eghuro.cz/tags/sysctl/</link><description>Recent content in Sysctl on Lessons learned</description><generator>Hugo</generator><language>en-us</language><copyright>© Alexandr Mansurov · Licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)</copyright><lastBuildDate>Wed, 21 Oct 2026 13:13:00 +0200</lastBuildDate><atom:link href="https://eghuro.cz/tags/sysctl/index.xml" rel="self" type="application/rss+xml"/><item><title>Unprivileged LXC containers share the host's per-user kernel limits: 'Too many open files' and 'disk quota exceeded'</title><link>https://eghuro.cz/posts/lxc-containers-share-host-kernel-limits/</link><pubDate>Wed, 21 Oct 2026 13:13:00 +0200</pubDate><guid>https://eghuro.cz/posts/lxc-containers-share-host-kernel-limits/</guid><description>&lt;p&gt;One day, two containers on the same host failed with errors that seemed unrelated. systemd in one of them:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemd[4573]: Failed to create control group inotify object: Too many open files&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemd[4573]: Failed to allocate manager object: Too many open files&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemd[1]: Failed to start user@1000.service - User Manager for UID 1000.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Docker in another, where every container sat at &lt;code&gt;Exited (128)&lt;/code&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;OCI runtime create failed: runc create failed: unable to start container process: error during container init: unable to join session keyring: unable to create session key: disk quota exceeded: unknown&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No file descriptors had run out, and no disk was full. Both errors come from per-user kernel quotas counted on the host, and every unprivileged container there was drawing from the same two.&lt;/p&gt;&#10;&#10;&lt;h2 id="the-setup"&gt;The setup &lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Debian 13, kernel 6.12, LXC 6.0.4&lt;/li&gt;&#10;&lt;li&gt;More unprivileged containers than the hardware comfortably runs, all with the same idmap: container root is host UID 1000000&lt;/li&gt;&#10;&lt;li&gt;systemd in every container, Docker nested in some&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;h2 id="too-many-open-files-inotify-instances"&gt;Too many open files: inotify instances &lt;/h2&gt;&#10;&lt;p&gt;systemd opens inotify instances to watch cgroups and units, and &lt;code&gt;inotify_init1()&lt;/code&gt; fails with &lt;code&gt;EMFILE&lt;/code&gt; when the user&amp;rsquo;s instance limit is reached. strerror turns that into &amp;ldquo;Too many open files&amp;rdquo;. The limit is &lt;code&gt;fs.inotify.max_user_instances&lt;/code&gt;, 128 by default.&lt;/p&gt;&#10;&lt;p&gt;Count the instances per user on the host:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo find /proc/&lt;span class="o"&gt;[&lt;/span&gt;0-9&lt;span class="o"&gt;]&lt;/span&gt;*/fd -lname &lt;span class="s1"&gt;&amp;#39;anon_inode:inotify&amp;#39;&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; cut -d/ -f3 &lt;span class="p"&gt;|&lt;/span&gt; xargs -I&lt;span class="o"&gt;{}&lt;/span&gt; ps -o &lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; -p &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sort &lt;span class="p"&gt;|&lt;/span&gt; uniq -c &lt;span class="p"&gt;|&lt;/span&gt; sort -rn&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /proc/sys/fs/inotify/max_user_instances&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Host root held 23 instances, and uids in the container range (1000000 and up) held 104 between them: 127 of 128. On the first sighting, my coding agent got that far, then dropped it as a side effect of having started too many containers at once. That was half right, since each container&amp;rsquo;s systemd adds about five instances. A day later it came back.&lt;/p&gt;&#10;&lt;p&gt;The &lt;code&gt;lxc&lt;/code&gt; package already ships a higher limit, and it wasn&amp;rsquo;t in effect:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cat /etc/sysctl.d/30-lxc-inotify.conf | grep -v &amp;#39;^#&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fs.inotify.max_user_instances = 1024&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cat /proc/sys/fs/inotify/max_user_instances&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;128&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The file was dated three days after the last boot. &lt;code&gt;/etc/sysctl.d&lt;/code&gt; is applied by &lt;code&gt;systemd-sysctl&lt;/code&gt; at boot, and the package&amp;rsquo;s install hadn&amp;rsquo;t applied it, so the setting sat on disk doing nothing.&lt;/p&gt;&#10;&#10;&lt;h2 id="disk-quota-exceeded-kernel-keys"&gt;Disk quota exceeded: kernel keys &lt;/h2&gt;&#10;&lt;p&gt;runc gives each container it starts a new session keyring. &lt;code&gt;add_key()&lt;/code&gt; fails with &lt;code&gt;EDQUOT&lt;/code&gt; when the user&amp;rsquo;s key quota is full, and strerror calls that &amp;ldquo;Disk quota exceeded&amp;rdquo;. The quota is &lt;code&gt;kernel.keys.maxkeys&lt;/code&gt;, 200 keys for any uid other than root. The host shows usage per UID:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ cat /proc/key-users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0: 127 126/126 107/1000000 2283/25000000&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1000: 12 12/12 12/200 86/20000&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1000000: 198 198/198 198/200 4189/20000&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;198/200&lt;/code&gt; are keys used against the quota. UID 1000000 is root in every container, so all the containers shared those 200 keys, and Docker&amp;rsquo;s restart attempts had nothing left.&lt;/p&gt;&#10;&#10;&lt;h2 id="the-fix"&gt;The fix &lt;/h2&gt;&#10;&lt;p&gt;Raise the limits and apply them right away, not at the next boot. Incus recommends 2000 keys and 2 MB in its &lt;a&#10; href="https://linuxcontainers.org/incus/docs/main/reference/server_settings"&#10; &#10; target="_blank" rel="noopener"&#10; &#10; &#10;&gt;server settings&lt;/a&gt;&#10;; 1024 inotify instances matches the &lt;code&gt;lxc&lt;/code&gt; package.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tee /etc/sysctl.d/60-lxc-limits.conf &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;fs.inotify.max_user_instances = 1024&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;kernel.keys.maxkeys = 2000&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;kernel.keys.maxbytes = 2000000&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sysctl -p /etc/sysctl.d/60-lxc-limits.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With Ansible, &lt;code&gt;ansible.posix.sysctl&lt;/code&gt; with &lt;code&gt;sysctl_set: true&lt;/code&gt; writes the file and sets the live value in one task.&lt;/p&gt;&#10;&lt;p&gt;Then run &lt;code&gt;systemctl reset-failed&lt;/code&gt; in the affected container, and &lt;code&gt;docker start&lt;/code&gt; for the dead Docker containers. Right after, uid 1000000 held 226 keys, already over the old limit.&lt;/p&gt;&#10;&#10;&lt;h2 id="why-the-two-quotas-are-counted-differently"&gt;Why the two quotas are counted differently &lt;/h2&gt;&#10;&lt;p&gt;The two quotas look similar, but separate idmaps would fix only one.&lt;/p&gt;&#10;&lt;p&gt;Keys are counted per host UID, against global sysctls. Containers that share an idmap share one quota. A separate idmap per container (&lt;code&gt;security.idmap.isolated&lt;/code&gt; in LXD and Incus) would give each its own.&lt;/p&gt;&#10;&lt;p&gt;inotify instances are counted per user namespace and charged up the chain of parent namespaces, at each level against the uid that created the child namespace. A new namespace&amp;rsquo;s own limit is &lt;code&gt;INT_MAX&lt;/code&gt;, so the limit that bites is the host&amp;rsquo;s, charged to whoever started the containers. LXC started as root charges host root, which is why the 23 instances of host root&amp;rsquo;s own daemons counted toward the same 128. Separate idmaps don&amp;rsquo;t change that.&lt;/p&gt;&#10;&#10;&lt;h2 id="takeaway"&gt;Takeaway &lt;/h2&gt;&#10;&lt;p&gt;On a container host, &amp;ldquo;Too many open files&amp;rdquo; and &amp;ldquo;disk quota exceeded&amp;rdquo; can mean that every container together hit a per-user kernel quota on the host. Check the host&amp;rsquo;s counters before you debug the container that complained.&lt;/p&gt;&#10;&lt;p&gt;Run the &lt;code&gt;find&lt;/code&gt; count and &lt;code&gt;cat /proc/key-users&lt;/code&gt; on your own container host and compare them with the limits before a container restart finds out for you.&lt;/p&gt;&#10;</description></item></channel></rss>