4

I'm new to Kubernetes and I'm trying to figure out what resource limits I should set for my php webapp.

My first guess is that if I have configured php fpm to use a maximum of 256M of memory then should I configure kubernetes to limit to 256M as well.

The setup would be like this:

  1. In the Dockerfile that builds the php container, I set php memory_limit to 256M:

    sed -i '/^;php_admin_value\[memory_limit\]/cphp_value[memory_limit] = 256M' /usr/local/etc/php-fpm.d/www.conf
    
  2. In my Kubernetes Deployment I set resource limits like this on the fpm container:

    resources:
      requests:
        cpu: "500m"
        memory: "128Mi"
      limits:
        cpu: "1"
        memory: "256Mi"
    

The thing that makes me ask the question is that PHP.net's documentation says:

memory_limit integer

This sets the maximum amount of memory in bytes that a script is allowed to allocate. This helps prevent poorly written scripts for eating up all available memory on a server.

php fpm can serve many requests at the same time and I guess each request runs a script completely independent from the others. They do not share the memory_limit setting. If that's the case, maybe my Kubernetes container limit should be higher than the php memory_limit setting?

Ok, but how much higher!? If I limit cpu: 1 I guess it means there can't be real parallel-processing going on, but there can still be many processes sharing the CPU, with the OS switching when blocked by IO. I think the fpm pm.max_children setting will tell me how many scripts can be run so how much memory can be taken at the maximum. But this is where it gets confusing because in our non-Kubernetes setup we choose the max_children based on how much memory the instance has. The formula we use is:

max_children = (RAM - 2Gb) / 80Mb

# Where:
#  * We Reserve 2Gb for the system.
#  * We saw that each request needs on average 40Mb of memory, so we chose 80Mb to be safe.

This equation goes out the window in the Kubernetes world as the RAM is prescribed at runtime and you don't need to reserve any for the system because the container ONLY runs php.

I'm thinking to use:

memory_limit = 256M
max_children = 10

resources:
  requests:
    cpu: "500m"
    memory: "512Mi"
  limits:
    cpu: "1"
    memory: "2Gi"
  • Normal case: 10 children using 40M each. Memory usage: 400M
  • High case: 10 children using 80M each Memory usage: 800M
  • Max case: 10 children using 256M each Memory usage: 2560M. Very unlikely to happen but if it did, Kubernetes would set Pod to OOMKilled I think because it's more than the limit.

Does this thinking seem reasonable? I don't think it'll allow for good packing because 10 children will hardly ever need the 2Gi limit. We will use HPA to add more pods if resources are stretched.

What did you do in your Kubernetes setup?

2
  • 1
    What you should be thinking about is: How much memory does your PHP script actually need to run? If it usually only needs 40M but occasionally needs 256M then if it doesn't get that, whatever operation needed that memory will fail. Aug 3, 2018 at 15:41
  • 1
    I know this is old, but regarding > Kubernetes would set Pod to OOMKilled I think because it's more than the limit I think this won't happen easily with php-fpm, because the oom_killer of Linux will more likely kill the php-fpm worker process first, which then gets replaced by a fresh instance by php-fpm. Essentially, I think OOM issues in php-fpm containers can go unnoticed, unless you check the looks specifically for patterns like SIGKILL etc.
    – mark
    Apr 21, 2022 at 8:28

1 Answer 1

4

Setting up container resource requests and limits is the first step towards using resources effectively in your Kubernetes cluster. After you set them, make sure you have monitoring and alerting in place to determine if you need to adapt these values or upgrade your cluster. If your container experiences memory pressure, the kernel will aggressively drop page cache entries to satisfy demand and may eventually be killed by the Linux Out of Memory (OOM) Killer. Since K8s disables swap (by passingmemory-swappiness=0 to Docker), it’s quite an unforgiving environment for misconfiguration.

Below you can find articles that are good to read for K8s limits and requests understanding:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .