How does Ulimit-n computation works?

I got a haproxy 1.8 vanilla alpine docker image running with maxconn = 2000

curl -s http://host:port/stats | grep -E 'limit|maxcon'
<b>system limits:</b> memmax = unlimited; ulimit-n = 4015<br>
<b>maxsock = </b> 4017; <b>maxconn = </b> 2000; <b>maxpipes = </b> 0<br>

Sometimes I get the following Warning in my logs:

[WARNING] 0/0 (0) : [/usr/local/sbin/haproxy.main()] FD limit (4015) too low for maxconn=2000/maxsock=4017. Please raise 'ulimit-n' to 4017 or more to avoid any trouble.

I find it very odd since I read this in haproxy doc:

ulimit-n
Sets the maximum number of per-process file-descriptors to . By
default, it is automatically computed, so it is recommended not to use this
option.

here is the version I use:

# /usr/local/sbin/haproxy -vv
HA-Proxy version 1.8.4-1deb90d 2018/02/08
Copyright 2000-2018 Willy Tarreau <willy@haproxy.org>

Build options :
  TARGET  = linux2628
  CPU     = generic
  CC      = gcc
  CFLAGS  = -O2 -g -fno-strict-aliasing -Wdeclaration-after-statement -fwrapv -Wno-null-dereference -Wno-unused-label
  OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_LUA=1 USE_PCRE=1

Default settings :
  maxconn = 2000, bufsize = 16384, maxrewrite = 1024, maxpollevents = 200

Built with OpenSSL version : OpenSSL 1.0.2n  7 Dec 2017
Running on OpenSSL version : OpenSSL 1.0.2n  7 Dec 2017
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports : SSLv3 TLSv1.0 TLSv1.1 TLSv1.2
Built with Lua version : Lua 5.3.4
Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND
Encrypted password support via crypt(3): yes
Built with multi-threading support.
Built with PCRE version : 8.41 2017-07-05
Running on PCRE version : 8.41 2017-07-05
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Built with zlib version : 1.2.11
Running on zlib version : 1.2.11
Compression algorithms supported : identity("identity"), deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
Built with network namespace support.

Available polling systems :
      epoll : pref=300,  test result OK
       poll : pref=200,  test result OK
     select : pref=150,  test result OK
Total: 3 (3 usable), will use epoll.

Available filters :
        [SPOE] spoe
        [COMP] compression
        [TRACE] trace

Is it a bug in haproxy or something I am doing wrong ?

Can you share you configuration? Are you sure you are starting haproxy as root?

I confirm I am running haproxy as root.

here is my simple config:

global
    log     127.0.0.1:<LOG_PORT> local0 warning emerg

defaults
    log     global

    option  dontlognull
    option  tcplog
    option  logasap

listen stats
    log     global

    mode    http
    bind    :<STATS_PORT>

    stats enable
    stats hide-version
    stats refresh 15s
    stats show-node
    stats uri /stats

listen xx
    log     global

    mode    tcp
    bind    :<PORT>

    server s1 <HOST>:<PORT> check

might also be of interest:

/ # ulimit -Hn
1048576
/ # ulimit -Sn
1048576

I have the same issue with HAProxy 1.8.8

pid = 1151 (process #2, nbproc = 2, nbthread = 1)
uptime = 0d 0h14m36s
system limits: memmax = unlimited; ulimit-n = 4096
maxsock = 1000069; maxconn = 500000; maxpipes = 0
current conns = 1; current pipes = 0/0; conn rate = 0/sec
Running tasks: 1/52; idle = 100 %

Here si the conf

[root@haproxy01 ~]# cat /etc/haproxy/haproxy.cfg
# This file managed by Puppet
global
  chroot  /var/lib/haproxy
  cpu-map  1-2 0-1
  log  127.0.0.1 local0 debug
  maxconn  500000
  nbproc  2
  spread-checks  5
  stats  socket /var/run/haproxy.stat mode 600 level admin process 1
  stats  bind-process 1
  tune.ssl.default-dh-param  2048

defaults
  log  global
  timeout  connect 5s

And the processes look like this:

[root@haproxy01 ~]# ps aux | grep hapr
root      33842  0.0  0.0 178124  4520 pts/1    S+   may15   0:00 ssh haproxy02
root      35678  0.0  0.1  81156 10120 ?        Ss   may15   0:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid
root      35682  0.3  0.7 161576 63148 ?        Ss   may15   8:28 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid
root      35683  0.3  0.7 161936 63568 ?        Ss   may15   8:33 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid
root     111407  0.0  0.0 112660   980 pts/0    S+   11:41   0:00 grep --color=auto hapr

It seems the processes started by Systemd, Supervisord or (maybe) any other init system don’t take those values set globally.
If I set in:

[root@haproxy03 ~]# vi /etc/systemd/system/multi-user.target.wants/haproxy.service

this:

[Service]
LimitNOFILE=infinity

Then I get:

image

for what it’s worth: I use the master worker mode

I see there is a FD_SETSIZE variable in Makefile… so I am wondering whether there is no way to get higher ulimit -n:

TARGET_CFLAGS = -fomit-frame-pointer -DFD_SETSIZE=65536 -D_REENTRANT -D_XOPEN_SOURCE=500 -D__EXTENSIONS__

Since I run this through systemd I have also set up the following:

[root@haproxy03 ~]# cat /etc/systemd/system/haproxy.service.d/90-limits.conf 
# This file managed by Puppet - DO NOT EDIT
[Service]
LimitNOFILE=1000100

Those are the /var/log/messages:

un 14 11:47:14 haproxy03 systemd: Starting HAProxy Load Balancer...
Jun 14 11:47:14 haproxy03 haproxy: [WARNING] 164/114714 (4255) : [/usr/sbin/haproxy.main()] Ca
nnot raise FD limit to 2000272, limit is 65536.
Jun 14 11:47:14 haproxy03 haproxy: [WARNING] 164/114714 (4255) : [/usr/sbin/haproxy.main()] FD
 limit (65536) too low for maxconn=1000100/maxsock=2000272. Please raise 'ulimit-n' to 2000272
 or more to avoid any trouble.
Jun 14 11:47:14 haproxy03 systemd: Started HAProxy Load Balancer.