ulimit -n in a container, and the file descriptors it needs

The file descriptor limit inside a container comes from the daemon’s default rather than the host’s, and a process that opens many sockets finds it at the worst moment.

$ docker run --rm alpine sh -c 'ulimit -n'
1048576        # the 20.10 default: generous

# but a compose service can be given less, or a base
# image's entrypoint can lower it:
services:
  php:
    ulimits:
      nofile:
        soft: 65536
        hard: 65536

# and the symptom when it is too low:
#   "Too many open files" in the nginx or php-fpm log

The 20.10 default is high enough that this is rarely the problem, and the case that still bites is an image whose entrypoint sets a lower soft limit for its own reasons. Setting both soft and hard explicitly is worth doing for anything holding many connections — a proxy, a worker with a large pool — because the failure is a request that fails rather than a process that dies, so it is easy to attribute to something else.