dev-ops-challenges

Resolve Volume Mounts Issue in Kubernetes

Technical Overview

In modern cloud-native architectures, applications are often decomposed into specialized single-purpose containers. A classic example is the Nginx + PHP-FPM pattern:

Since Nginx and PHP-FPM run in separate, isolated containers, they do not share a common filesystem by default. However, both containers require access to the application’s source code: Nginx needs it to verify static file requests, and PHP-FPM needs it to run the script. To solve this, Kubernetes uses Shared Volumes within a multi-container Pod.

graph TD
    subgraph Pod: nginx-phpfpm
        direction TB
        subgraph nginx-container [nginx-container]
            NginxConf["/etc/nginx/nginx.conf <br> (Mounted from ConfigMap)"]
            NginxRoot["/var/www/html <br> (Mounts shared-files)"]
        end
        subgraph php-fpm-container [php-fpm-container]
            PhpRoot["/var/www/html <br> (Mounts shared-files)"]
        end
        emptyDir[("emptyDir Shared Volume <br> (shared-files)")]
        emptyDir <-->|Mounted at /var/www/html| NginxRoot
        emptyDir <-->|Mounted at /var/www/html| PhpRoot
    end
    ConfigMap[("ConfigMap <br> (nginx-config)")] -->|subPath mount| NginxConf

Shared Storage via emptyDir

An emptyDir volume is created when a Pod is assigned to a node and exists as long as that Pod is running on that node. It starts out empty, and all containers in the Pod can read and write the same files in the emptyDir volume, though that volume can be mounted at the same or different paths in each container.

ConfigMap-Based Configuration File Mounting

To run Nginx, configuration files (like nginx.conf) must be injected. Instead of baking custom configurations into the container image, Kubernetes provides ConfigMaps to decouple configuration from containerized applications.


Kubernetes ConfigMaps: Concept & Usage

A ConfigMap is an API object used to store non-confidential data in key-value pairs. Pods can consume ConfigMaps as environment variables, command-line arguments, or configuration files in a volume.

Why Use ConfigMaps?

Single File Overlays using subPath

By default, mounting a ConfigMap volume into a container directory overwrites all existing files in that target directory. For example, if you mount a ConfigMap to /etc/nginx/, you will wipe out other files in /etc/nginx/ like mime.types or fastcgi.conf.

To avoid this, use the subPath property. subPath specifies a relative path within the volume, allowing you to overlay a single file inside a container without modifying the rest of the target directory:

volumeMounts:
- name: nginx-config-volume
  mountPath: /etc/nginx/nginx.conf
  subPath: nginx.conf

Troubleshooting ConfigMaps & Volume Mounts

Volume mount and configuration mismatch issues manifest in specific ways. Below is a structured guide to diagnosing and fixing them.

Common Troubleshooting Scenarios

Scenario 1: Path Inconsistency (HTTP 404 Not Found)

Scenario 2: Container Creation Failure (CreateContainerConfigError / CreateContainerError)

Scenario 3: Stale Configurations (Updates not propagating)


Troubleshooting Checklist & Commands

  1. Describe the Pod Configuration: Inspect the volume configurations, mounts, and container status.
    kubectl describe pod nginx-phpfpm
    
    • Verify the Mounts section for all containers.
    • Verify the Volumes definition section at the bottom.
  2. Inspect the ConfigMap Content: Check that the ConfigMap contains the correct configuration keys and server block details.
    kubectl get configmap nginx-config -o yaml
    
    • Ensure the root directive points to the shared volume mount path.
    • Verify the FastCGI parameter: fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  3. Check Container Logs: Extract log messages to diagnose Nginx errors or PHP execution issues.
    # Nginx container logs
    kubectl logs nginx-phpfpm -c nginx-container
        
    # PHP-FPM container logs
    kubectl logs nginx-phpfpm -c php-fpm-container
    
  4. Interactive Diagnostics: Log into the containers to check directories, configurations, and connectivity.
    # Verify Nginx configuration syntax inside the container
    kubectl exec -it nginx-phpfpm -c nginx-container -- nginx -t
        
    # Check if files exist in the shared volume in Nginx
    kubectl exec -it nginx-phpfpm -c nginx-container -- ls -la /var/www/html
        
    # Check if files exist in the shared volume in PHP-FPM
    kubectl exec -it nginx-phpfpm -c php-fpm-container -- ls -la /var/www/html
    

Infrastructure & Configuration Requirements


Step-by-Step Implementation

Step 1: Diagnose the Inactive Pod Setup

Connect to the Jump Host and query the pod and ConfigMap configurations:

kubectl describe pod nginx-phpfpm

Observe that the mount paths are misaligned (e.g., Nginx mounts shared-files at /usr/share/nginx/html, but PHP-FPM mounts it at /var/www/html).

Next, inspect the ConfigMap to see what document root Nginx expects:

kubectl get configmap nginx-config -o yaml

Note that the configuration expects the root path to be /var/www/html.


Step 2: Extract and Correct the Pod Manifest

Since Pod configurations are immutable, you must export, modify, and replace the running Pod.

Export the running Pod manifest:

kubectl get pod nginx-phpfpm -o yaml > /tmp/nginx-phpfpm.yaml

Edit /tmp/nginx-phpfpm.yaml to ensure the mountPath is aligned. Update both containers to mount the shared-files volume at /var/www/html:

# Inside nginx-container
    volumeMounts:
    - name: shared-files
      mountPath: /var/www/html
    - name: nginx-config-volume
      mountPath: /etc/nginx/nginx.conf
      subPath: nginx.conf

# Inside php-fpm-container
    volumeMounts:
    - name: shared-files
      mountPath: /var/www/html

Step 3: Recreate the Pod

Force delete and reapply the Pod manifest to trigger container recreation:

kubectl delete pod nginx-phpfpm --force --grace-period=0
kubectl apply -f /tmp/nginx-phpfpm.yaml

Ensure the Pod is in a healthy, running status:

kubectl get pods -w

Expected Output:

NAME           READY   STATUS    RESTARTS   AGE
nginx-phpfpm   2/2     Running   0          12s

Step 4: Copy Application Code to the Shared Volume

The web server expects index.php to serve content. Since both containers share the emptyDir volume, copying the file into /var/www/html of either container makes it immediately accessible to both.

Copy the PHP index file from the jump host into the Nginx container:

kubectl cp /home/thor/index.php nginx-phpfpm:/var/www/html/index.php -c nginx-container

Post-Deployment Verification

1. Confirm File Exists on Shared Volume

Verify the file was correctly copied to the shared filesystem on both containers:

kubectl exec nginx-phpfpm -c nginx-container -- ls -la /var/www/html/index.php
kubectl exec nginx-phpfpm -c php-fpm-container -- ls -la /var/www/html/index.php

Expected Output for both commands:

-rw-r--r-- 1 root root ... /var/www/html/index.php

2. Verify Nginx Local Communication

Test the web application by sending a local HTTP request within the Pod:

kubectl exec nginx-phpfpm -c nginx-container -- curl -I http://localhost:8099

Expected Output:

HTTP/1.1 200 OK
Server: nginx/...
Content-Type: text/html; charset=UTF-8
...

The site will now render the dynamic PHP page successfully through Nginx!