Guides

Kubernetes readiness and liveness probes: dangerous defaults on PHP-FPM pods

Why Kubernetes probe defaults cause restart loops on PHP-FPM, and how to configure them in YAML with kubectl commands to verify pod status after deployment.

UptimeMag editorial team · 14 October 2026 · 4 min read

Readiness e liveness probe su Kubernetes: i default pericolosi su un pod PHP-FPM

A PHP-FPM pod that restarts by itself every two minutes with no obvious application errors almost always hides a misconfigured probe. The typical symptom is CrashLoopBackOff in the output of kubectl get pods, with the container coming back up, attempting to respond, failing the health check, and being killed again. In most cases, the culprit is the default probe values left as they are—never designed for a PHP-FPM pool that needs to warm up opcache or open database connections before it can respond.

Kubernetes defaults

According to the official Kubernetes documentation, probe configuration fields have these values when not specified: initialDelaySeconds defaults to 0 seconds, while periodSeconds defaults to 10 seconds. The timeout for each individual check is 1 second, and the number of consecutive failures tolerated before action is triggered—the failureThreshold—defaults to 3.

In practice, with defaults alone, a liveness probe HTTP check starts probing the container 0 seconds after startup, every 10 seconds, and after 3 consecutive failures (so at most 30 seconds after something goes wrong) the kubelet kills the container. After failureThreshold consecutive failures (default 3), the kubelet kills the container and the pod's restartPolicy decides whether it comes back up. Repeated restarts increment the counter until CrashLoopBackOff.

For PHP-FPM this is a real problem: if the image needs to download configurations, warm up opcache, or wait for the database to respond, an initialDelaySeconds of 0 and a period of 10 seconds gives the container only 30 seconds before being considered dead. If the actual startup takes 40–50 seconds, the pod enters a restart loop before it has ever truly been ready.

YAML starting point for a PHP-FPM pod

A reasonable starting point, to be adapted to your application's actual startup times, separates readiness and liveness and adds a startupProbe that absorbs slow startup:

spec:
 containers:
 - name: php-fpm
   image: registry.example.com/myapp-php:1.0
   ports:
   - containerPort: 9000
   startupProbe:
     exec:
       command:
       - sh
       - -c
       - SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
     periodSeconds: 5
     failureThreshold: 24
   readinessProbe:
     exec:
       command:
       - sh
       - -c
       - SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
     initialDelaySeconds: 0
     periodSeconds: 10
     timeoutSeconds: 3
     failureThreshold: 3
   livenessProbe:
     exec:
       command:
       - sh
       - -c
       - SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000
     periodSeconds: 10
     timeoutSeconds: 3
     failureThreshold: 5

The probe uses the built-in ping endpoint in PHP-FPM, which you enable in the pool configuration with ping.path = /ping and ping.response = pong. With the startupProbe active, the kubelet does not execute readiness and liveness checks until startup succeeds: if a startup probe is defined, the delays for liveness and readiness probes do not start until the startup probe succeeds. Here periodSeconds: 5 and failureThreshold: 24 allow up to 120 seconds for PHP-FPM to be ready, without altering the steady-state liveness timings.

The higher failureThreshold on liveness (5 instead of 3) is intentional: a PHP-FPM pool under load can respond more slowly without actually being blocked, and a threshold that is too low on liveness risks killing healthy pods just because they are momentarily busy. The pattern recommended by the official documentation goes in this direction: probe configuration fields let you control startup, liveness, and readiness check behaviour more precisely, using different thresholds for readiness (stricter, to remove traffic immediately) and liveness (more permissive, to avoid restarting containers that are simply slow).

When a startupProbe is really needed

The official documentation gives a precise rule for deciding whether you need a startup probe: if the container typically takes longer to start than initialDelaySeconds + failureThreshold × periodSeconds, you should specify a startup probe that checks the same endpoint as the liveness probe. For a PHP-FPM pod with external dependencies (Redis sessions, application database connection) this condition occurs almost always on first deployment to a new cluster, where images need to be downloaded and init containers consume precious seconds before the main container starts.

Verifying status after deployment

After applying the manifest, the command to see if probes are failing is:

kubectl describe pod <pod-name>

The Events section shows the actual sequence of what happens. A typical example when a liveness probe fails and the container is killed:

Warning Unhealthy 10s (x3 over 20s) kubelet Liveness probe failed: ...
Normal Killing 10s kubelet Container php-fpm failed liveness probe, will be restarted

This sequence, documented in the official probe configuration guide, is the first place to look when a pod restarts without obvious reason: if the events show Unhealthy quickly followed by Killing, the problem is not in the application but in the probe timings. To count how many times it has already happened:

kubectl get pod <pod-name>

The RESTARTS column increments every time a container killed by the probe returns to Running state: the RESTARTS counter increments as soon as a failed container returns to running state. A number that grows over time, combined with Unhealthy/Killing events in quick succession, confirms that the cause is probe configuration and not a genuine application crash.

Alternative: checking the queue instead of simple ping

In environments where the PHP-FPM pool can saturate under load, there is a more granular check that verifies the length of the request queue waiting to be processed, not just whether the process responds. This is an option to consider when simple ping is too permissive and the readiness probe keeps giving the all-clear even with the pool full and requests queued.

Written with the help of artificial intelligence and checked by the editors (EU AI Act, art. 50).