What Do You Need to Know First?

To understand this article, you should first know the basics of Kubernetes, web servers, and how PHP works.

Let's start!

Our Kubernetes Setup: A Single-Node Cluster

Let's consider a simple Kubernetes setup with a single node and no worker nodes.

We have an Ingress-NGINX controller as the main entry point. It routes requests to a Service, and the Service routes traffic to the appropriate Pods.

What Happens When a Client Requests index.php?

Suppose a client requests a file called index.php. What happens?

The request reaches Ingress-NGINX, which forwards it to the PHP Pod. PHP receives the request, recognizes that the file has a .php extension, executes the PHP code, and returns the generated response. The same process happens in reverse when the response travels back to the client.

Now, you might think this is how everything works. So, what's wrong with this explanation?

Almost everything I described above is incorrect!

Let's understand why.

The First Problem: HTTP vs. FastCGI

Ingress-NGINX communicates with backend services using HTTP, but PHP-FPM does not normally understand HTTP. It uses the FastCGI protocol to receive PHP execution requests.

Yes, NGINX supports FastCGI, but the standard Kubernetes Ingress backend configuration does not natively specify a FastCGI backend. Custom configuration or another NGINX setup is needed.

The Second Problem: Static-File Serving

But another major issue arises: static-file serving.

Suppose the browser receives index.php's generated HTML and finds references to CSS or JavaScript files. It sends separate requests for those files.

If the files are not available to the web server handling those requests, how will they be served?

PHP-FPM is not a general-purpose HTTP static-file server. Although PHP can read files using filesystem functions and return their contents, PHP-FPM is designed to execute PHP code, not to serve static assets efficiently over HTTP.

How Do We Solve This Problem in PHP?

Therefore, in a typical PHP-FPM architecture, we need an HTTP-speaking web server, such as NGINX or Apache.

We can use one of the following approaches:

  • Same container: Run the web server and PHP-FPM in the same container.
  • Sidecar pattern: Run the web server and PHP-FPM in two containers within the same Pod.
  • Separate web-server tier: Run web-server Pods separately and configure them to communicate with PHP-FPM Pods.
  • CDN: Use a Content Delivery Network for static-file delivery.

Now Let's Move to Node.js

Node.js can handle HTTP requests directly. Therefore, when a client requests a static file, Node.js can serve it without requiring an additional web server.

Does Node.js Use Zero-Copy to Serve Static Files?

Node.js can also benefit from operating-system optimizations such as sendfile() in supported file-transfer paths. These optimizations can avoid certain memory copies by allowing the kernel to transfer file data to a socket without first copying the file contents into a user-space buffer.

However, Node.js does not guarantee zero-copy for every static-file request.

An Important Point: The Linux Kernel in Kubernetes

One important thing to remember: the Linux kernel is shared by ordinary Linux containers running on the same host machine. Each Pod does not have its own separate Linux kernel.

This is important when discussing operating-system features such as sendfile() and how applications interact with the kernel.

The Main Question: Why Does This Difference Matter?

Now comes the most important question: if both PHP and Node.js can serve application requests, but PHP-FPM typically uses an additional web server while Node.js can serve static files directly, why does this difference matter?

Scenario: Scaling to 20 or 30 Pods

Let's consider a scaled application with 20 or 30 Pods.

In a typical PHP-FPM architecture, we may need a web server alongside PHP-FPM in every application Pod. This adds another process and consumes additional resources.

With Node.js, we can handle HTTP requests and serve static files within the same application process, without necessarily running another web server.

An Alternative: Using a CDN

Alternatively, we can use a CDN for static-file delivery in either architecture. This reduces the static-file traffic handled by application Pods and can improve delivery performance.

Conclusion: The Main Crux

This is the main crux of the discussion: how the architecture of PHP and Node.js affects static-file serving, resource consumption, and scalability in Kubernetes.

The key difference is that PHP-FPM separates PHP execution from HTTP serving, while Node.js can combine HTTP handling and static-file serving within the same application process.

Understanding this distinction helps us make better architectural decisions when deploying and scaling applications in Kubernetes.