• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Beyond `docker-compose`: Orchestrating Microservices with Kubernetes and PHP-FPM for Extreme Laravel Scalability

Beyond `docker-compose`: Orchestrating Microservices with Kubernetes and PHP-FPM for Extreme Laravel Scalability

Kubernetes as the Microservice Orchestration Layer

While docker-compose is excellent for local development and simple deployments, it quickly becomes a bottleneck when scaling microservices in production. Kubernetes (K8s) offers a robust, declarative, and highly available platform for managing containerized applications. For a Laravel-based microservice architecture, K8s provides the necessary primitives to manage deployments, scaling, networking, and resilience.

We’ll focus on deploying a typical Laravel application, which often relies on PHP-FPM for request processing and a separate web server (like Nginx or Apache) for serving static assets and proxying requests. In a K8s environment, this translates to distinct container images and Kubernetes resources.

Containerizing Laravel with PHP-FPM

The core of our Laravel application will be containerized using PHP-FPM. This separates the application logic from the web server, allowing independent scaling and management. We’ll build a Docker image that includes our Laravel code, dependencies, and the PHP-FPM process manager.

Consider a typical Dockerfile for a PHP-FPM service:

# Use an official PHP image as a parent image
FROM php:8.2-fpm

# Set the working directory in the container
WORKDIR /var/www/html

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    zip \
    unzip \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    libonig-dev \
    libxml2-dev \
    libssl-dev \
    libcurl4-openssl-dev \
    libsqlite3-dev \
    libpq-dev \
    acl \
    vim \
    cron \
    && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd \
    && docker-php-ext-install pdo pdo_mysql zip exif pcntl opcache sockets \
    && pecl install redis \
    && docker-php-ext-enable redis \
    && docker-php-ext-install bcmath \
    && docker-php-ext-install sockets \
    && docker-php-ext-install opcache

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

# Copy the application code
COPY . .

# Install Composer dependencies
RUN composer install --no-dev --optimize-autoloader --no-interaction

# Set permissions for storage and bootstrap/cache
RUN chown -R www-data:www-data storage bootstrap/cache && chmod -R 775 storage bootstrap/cache

# Expose port 9000 for PHP-FPM
EXPOSE 9000

# Start PHP-FPM
CMD ["php-fpm"]

Key points:

  • We use a specific PHP version (8.2-fpm) to ensure consistency.
  • Essential system packages and PHP extensions are installed.
  • Composer is installed globally for dependency management.
  • Application code is copied, and dependencies are installed with optimization flags for production.
  • Permissions for storage and bootstrap/cache are set correctly for the www-data user.
  • The container exposes port 9000, the default for PHP-FPM.
  • The CMD is set to php-fpm, ensuring the FPM process runs when the container starts.

Kubernetes Deployment for PHP-FPM

In Kubernetes, we define our application’s desired state using YAML manifests. A Deployment resource manages stateless applications, ensuring a specified number of replicas are running and handling updates. For our PHP-FPM service, this would look something like:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: laravel-php-fpm
  labels:
    app: laravel
    tier: php-fpm
spec:
  replicas: 3 # Start with 3 replicas
  selector:
    matchLabels:
      app: laravel
      tier: php-fpm
  template:
    metadata:
      labels:
        app: laravel
        tier: php-fpm
    spec:
      containers:
      - name: php-fpm
        image: your-docker-registry/laravel-app-php-fpm:latest # Replace with your image
        ports:
        - containerPort: 9000
        livenessProbe:
          exec:
            command: ["kill", "-0", "1"] # Basic check if the process is alive
          initialDelaySeconds: 10
          periodSeconds: 5
        readinessProbe:
          exec:
            command: ["sh", "-c", "php-fpm -t"] # Check FPM configuration
          initialDelaySeconds: 10
          periodSeconds: 5
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        volumeMounts:
        - name: app-storage
          mountPath: /var/www/html/storage
        - name: app-bootstrap-cache
          mountPath: /var/www/html/bootstrap/cache
      volumes:
      - name: app-storage
        emptyDir: {} # Placeholder, will be replaced by persistent storage
      - name: app-bootstrap-cache
        emptyDir: {} # Placeholder, will be replaced by persistent storage

Explanation:

  • replicas: 3: We specify an initial desired state of 3 running PHP-FPM pods. K8s will ensure this count is maintained.
  • selector: This links the Deployment to the Pods it manages.
  • template: Defines the Pod specification.
  • image: Points to your container image in a registry.
  • ports: Exposes the PHP-FPM port.
  • livenessProbe and readinessProbe: Crucial for K8s to manage pod health. The liveness probe restarts a failing container, while the readiness probe determines if a pod is ready to receive traffic. The php-fpm -t command is a simple way to check FPM configuration validity.
  • resources: Defines CPU and memory requests and limits. This is vital for resource management and preventing noisy neighbor issues.
  • volumeMounts and volumes: For stateful data like logs, sessions, or cached views, we’d typically use Persistent Volumes (PVs) and Persistent Volume Claims (PVCs). For simplicity here, emptyDir is used as a placeholder, but in production, you’d configure appropriate storage solutions (e.g., NFS, Ceph, cloud provider storage).

Kubernetes Service for PHP-FPM

A Kubernetes Service provides a stable IP address and DNS name for a set of Pods. This allows other services (like our web server) to discover and communicate with the PHP-FPM pods without needing to know their individual IP addresses, which can change.

apiVersion: v1
kind: Service
metadata:
  name: laravel-php-fpm-service
  labels:
    app: laravel
spec:
  selector:
    app: laravel
    tier: php-fpm # Selects pods with these labels
  ports:
    - protocol: TCP
      port: 9000
      targetPort: 9000 # The port PHP-FPM is listening on
  type: ClusterIP # Only accessible within the cluster

This ClusterIP service makes the PHP-FPM pods accessible at the stable DNS name laravel-php-fpm-service.your-namespace.svc.cluster.local (or just laravel-php-fpm-service within the same namespace) on port 9000.

Containerizing the Web Server (Nginx)

A separate container will handle incoming HTTP requests, serve static assets, and proxy dynamic requests to the PHP-FPM service. Nginx is a common choice.

# Use an official Nginx image
FROM nginx:alpine

# Remove default Nginx configuration
RUN rm /etc/nginx/conf.d/default.conf

# Copy custom Nginx configuration
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Copy static assets (if any, or mount them)
# COPY public/ /usr/share/nginx/html/

# Expose port 80
EXPOSE 80

# Start Nginx
CMD ["nginx", "-g", "daemon off;"]

And the corresponding nginx.conf:

server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/html; # Assuming your Laravel public dir is mapped here

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        # Use the Kubernetes service name for PHP-FPM
        fastcgi_pass laravel-php-fpm-service:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    # Serve static files directly
    location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|webp)$ {
        expires 1y;
        add_header Cache-Control "public";
    }
}

Crucially, the fastcgi_pass directive points to the Kubernetes Service name for PHP-FPM (laravel-php-fpm-service:9000). This is how Nginx discovers and communicates with the PHP-FPM pods.

Kubernetes Deployment and Service for Nginx

Similar to PHP-FPM, we define a Deployment for Nginx and a Service to expose it externally.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: laravel-nginx
  labels:
    app: laravel
    tier: web
spec:
  replicas: 2 # Fewer replicas for the web tier might suffice
  selector:
    matchLabels:
      app: laravel
      tier: web
  template:
    metadata:
      labels:
        app: laravel
        tier: web
    spec:
      containers:
      - name: nginx
        image: your-docker-registry/laravel-app-nginx:latest # Replace with your image
        ports:
        - containerPort: 80
        livenessProbe:
          httpGet:
            path: / # Basic check on Nginx root
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: / # Basic check on Nginx root
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 5
        resources:
          requests:
            cpu: "50m"
            memory: "64Mi"
          limits:
            cpu: "200m"
            memory: "256Mi"
        volumeMounts:
        - name: app-storage-nginx # Mount storage for logs, etc.
          mountPath: /var/log/nginx
        - name: app-public-assets # Mount public assets if not baked into image
          mountPath: /var/www/html # Or wherever Nginx expects them
      volumes:
      - name: app-storage-nginx
        emptyDir: {} # Use Persistent Volume for logs in production
      - name: app-public-assets
        emptyDir: {} # Use Persistent Volume or ConfigMap for static assets
apiVersion: v1
kind: Service
metadata:
  name: laravel-nginx-service
  labels:
    app: laravel
spec:
  selector:
    app: laravel
    tier: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer # Expose externally via cloud provider LB or NodePort

The type: LoadBalancer for the Nginx service is key for external access. In cloud environments (AWS, GCP, Azure), this automatically provisions a cloud load balancer. For on-premises or bare-metal setups, you might use NodePort and manage external access via an external load balancer (like HAProxy or Traefik) or use an Ingress Controller.

Managing Persistent Data and Configuration

Stateful components require careful handling in Kubernetes:

  • Database: For production, never run your database inside a standard K8s Deployment. Use managed database services (RDS, Cloud SQL) or deploy a dedicated database cluster using operators (e.g., Crunchy Data PostgreSQL Operator, Percona Operator for MySQL).
  • Cache/Sessions: Redis or Memcached should be deployed as separate StatefulSets or managed services.
  • File Storage (e.g., Laravel storage directory): Use Persistent Volumes (PVs) and Persistent Volume Claims (PVCs). This ensures data persists across pod restarts and can be shared if necessary. For shared access (e.g., multiple Nginx pods needing to write logs), consider NFS or distributed file systems.
  • Configuration: Sensitive information like database credentials, API keys, etc., should be managed using Kubernetes Secrets. Non-sensitive configuration can be managed via ConfigMaps. These can be mounted as files into pods or injected as environment variables.

Example of mounting a ConfigMap for Nginx configuration:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  nginx.conf: |
    # ... your nginx.conf content here ...
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: laravel-nginx
spec:
  # ... other spec ...
  template:
    # ... other template spec ...
    spec:
      containers:
      - name: nginx
        # ... other container spec ...
        volumeMounts:
        - name: nginx-config-volume
          mountPath: /etc/nginx/conf.d
      volumes:
      - name: nginx-config-volume
        configMap:
          name: nginx-config

Scaling and Observability

Kubernetes excels at scaling. You can manually adjust replica counts or use the HorizontalPodAutoscaler (HPA) to automatically scale based on CPU or memory utilization.

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: laravel-php-fpm-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: laravel-php-fpm
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70 # Scale up when CPU utilization reaches 70%
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70 # Scale up when Memory utilization reaches 70%

For observability, integrate:

  • Logging: Deploy a cluster-level logging agent (e.g., Fluentd, Filebeat) to collect logs from all pods and forward them to a centralized logging system (Elasticsearch, Loki).
  • Metrics: Use Prometheus to scrape metrics from your applications and Kubernetes components. Grafana can then be used for visualization.
  • Tracing: Implement distributed tracing (e.g., Jaeger, Zipkin) to track requests across microservices.

Conclusion: Moving Beyond Compose

Transitioning from docker-compose to Kubernetes for a Laravel microservice architecture unlocks true scalability, resilience, and manageability. By defining your PHP-FPM and Nginx services as distinct Deployments and Services, leveraging Kubernetes’ health checks, and carefully managing persistent data and configuration, you can build robust, high-performance applications capable of handling significant load. This approach provides the foundation for advanced patterns like service meshes, CI/CD integration, and sophisticated auto-scaling strategies.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Beyond `docker-compose`: Orchestrating Microservices with Kubernetes and PHP-FPM for Extreme Laravel Scalability
  • Scaling Laravel Applications with Redis Streams: A Deep Dive into Real-time Event Architectures
  • Leveraging Docker Compose and Kubernetes for Scalable, Zero-Downtime WordPress Headless Deployments
  • Orchestrating High-Availability WordPress with Headless CMS and Multi-Region AWS Deployments
  • Leveraging PHP 9’s JIT and GC Enhancements for Microservice Performance at Scale with Laravel

Categories

  • apache (1)
  • AWS (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (664)
  • Desktop Applications (14)
  • DevOps (88)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (89)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • Performance & Security Optimization (10)
  • PHP (310)
  • PHP Development (49)
  • Plugins & Themes (244)
  • Programming Languages (10)
  • Python (20)
  • Ruby on Rails (1)
  • Security (1)
  • Security & Compliance (650)
  • SEO & Growth (492)
  • Server (118)
  • Softwares (1)
  • Ubuntu (9)
  • Uncategorized (630)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (169)
  • WordPress Plugin Development (728)
  • WordPress Theme Development (357)

Recent Posts

  • Beyond `docker-compose`: Orchestrating Microservices with Kubernetes and PHP-FPM for Extreme Laravel Scalability
  • Scaling Laravel Applications with Redis Streams: A Deep Dive into Real-time Event Architectures
  • Leveraging Docker Compose and Kubernetes for Scalable, Zero-Downtime WordPress Headless Deployments

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (728)
  • Debugging & Troubleshooting (664)
  • Security & Compliance (650)
  • Uncategorized (630)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala