• 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 » Orchestrating Microservices with Kubernetes: A Deep Dive into PHP-FPM, Laravel Queues, and MySQL Replication on AWS EKS

Orchestrating Microservices with Kubernetes: A Deep Dive into PHP-FPM, Laravel Queues, and MySQL Replication on AWS EKS

Kubernetes Deployment Strategy for PHP-FPM Applications

Deploying PHP-FPM applications on Kubernetes requires careful consideration of resource allocation, scaling, and health checks. We’ll leverage AWS EKS for this example, focusing on a robust deployment strategy that ensures high availability and efficient resource utilization. The core of our PHP application will be a Laravel project, which benefits from efficient background job processing via Laravel Queues.

PHP-FPM Configuration for Kubernetes

The PHP-FPM configuration is critical for performance and stability within a containerized environment. We need to tune the process manager settings to align with Kubernetes’ resource management capabilities. The `pm.max_children`, `pm.start_servers`, `pm.min_spare_servers`, and `pm.max_spare_servers` directives are key. A common approach is to set `pm.max_children` based on the container’s memory limit, leaving room for the web server (e.g., Nginx) and the operating system. For a container with 1GB of RAM, a reasonable starting point might be 10-20 children, depending on the average memory footprint of a single PHP request.

Here’s a sample php-fpm.d/www.conf tailored for Kubernetes:

[global]
pid = /run/php/php7.4-fpm.pid
error_log = /var/log/php/error.log
daemonize = no

[www]
user = www-data
group = www-data
listen = /run/php/php7.4-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

; Process Manager settings
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 2
pm.max_spare_servers = 10
pm.max_requests = 500

; Other settings
request_terminate_timeout = 60s
request_slowlog_timeout = 30s
slowlog = /var/log/php/slow.log
catch_workers_output = yes
access.log = /var/log/php/access.log
clear_env = no

The daemonize = no setting is crucial for containerized environments, ensuring PHP-FPM runs in the foreground and its logs are captured by the container runtime. catch_workers_output = yes is also beneficial for debugging within Kubernetes.

Kubernetes Deployment Manifests

We’ll define a Deployment for our PHP-FPM application and a separate Deployment for our Nginx Ingress Controller (or use AWS ALB Ingress Controller). The PHP-FPM Deployment will manage the pods running our application code and PHP-FPM processes. A Service will expose the PHP-FPM pods to the Nginx Ingress Controller.

PHP-FPM Deployment

This manifest defines the PHP-FPM application deployment. It includes resource requests and limits, readiness and liveness probes, and a volume for persistent logs (though often logs are shipped to a centralized logging system).

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-fpm-app
  labels:
    app: php-fpm
spec:
  replicas: 3
  selector:
    matchLabels:
      app: php-fpm
  template:
    metadata:
      labels:
        app: php-fpm
    spec:
      containers:
      - name: php-fpm
        image: your-dockerhub-username/your-php-fpm-app:latest
        ports:
        - containerPort: 9000
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
        livenessProbe:
          exec:
            command: ["sh", "-c", "kill -0 `cat /run/php/php7.4-fpm.pid`"]
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          exec:
            command: ["sh", "-c", "php-fpm -t"]
          initialDelaySeconds: 5
          periodSeconds: 5
        volumeMounts:
        - name: php-logs
          mountPath: /var/log/php
      volumes:
      - name: php-logs
        emptyDir: {}

PHP-FPM Service

This Service exposes the PHP-FPM pods internally within the cluster, allowing the Nginx Ingress Controller to forward requests.

apiVersion: v1
kind: Service
metadata:
  name: php-fpm-service
spec:
  selector:
    app: php-fpm
  ports:
    - protocol: TCP
      port: 9000
      targetPort: 9000

Nginx Ingress Controller Configuration

Assuming you have an Nginx Ingress Controller deployed (e.g., using the official Helm chart), you’ll create an Ingress resource to route external traffic to your application. This Ingress will point to the php-fpm-service.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-laravel-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    # Add other Nginx specific annotations as needed
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: php-fpm-service # This should point to your Nginx service if Nginx is separate
            port:
              number: 80 # Assuming Nginx listens on port 80

Note: The above Ingress example assumes Nginx is directly serving static assets and proxying to PHP-FPM. A more common pattern is to have a separate Nginx container within the same pod or a dedicated Nginx Deployment that proxies to the PHP-FPM Service. If using AWS ALB Ingress Controller, the annotations and structure will differ.

Laravel Queues and Background Job Orchestration

For background job processing, Laravel Queues are essential. We’ll deploy a separate Kubernetes Deployment for the queue worker. This worker will continuously poll the queue for new jobs and execute them. This decouples long-running tasks from the web request lifecycle, improving application responsiveness.

Queue Worker Deployment

This deployment runs a container that executes the php artisan queue:work command. It’s crucial to configure appropriate resource requests and limits, as queue workers can be resource-intensive.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: laravel-queue-worker
  labels:
    app: queue-worker
spec:
  replicas: 2 # Scale based on job load
  selector:
    matchLabels:
      app: queue-worker
  template:
    metadata:
      labels:
        app: queue-worker
    spec:
      containers:
      - name: queue-worker
        image: your-dockerhub-username/your-laravel-app:latest # Same app image, different entrypoint/command
        command: ["php", "artisan", "queue:work", "--tries=3", "--timeout=300"]
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "1000m"
        env:
        - name: QUEUE_CONNECTION
          value: "redis" # Or database, sqs, etc.
        # Add other necessary environment variables

The command overrides the default container entrypoint to start the queue worker. The --tries and --timeout flags are essential for robust job handling. Scaling the number of replicas for this deployment should be based on the observed load on your queues.

Queue Worker Service (Optional but Recommended)

While not strictly necessary for the worker to function, a Service can be useful for monitoring or exposing metrics if your worker application exposes them.

apiVersion: v1
kind: Service
metadata:
  name: laravel-queue-worker-service
spec:
  selector:
    app: queue-worker
  ports:
    - protocol: TCP
      port: 8080 # Example port for metrics
      targetPort: 8080

MySQL Replication on AWS EKS

For database high availability, we’ll configure MySQL replication. This typically involves a primary instance and one or more replica instances. On AWS EKS, you have several options:

  • AWS RDS: The simplest and most recommended approach. Provision a Multi-AZ RDS instance for automatic failover and read replicas for scaling read traffic. EKS pods connect to the RDS endpoint.
  • Self-Managed MySQL on EKS: Deploy MySQL using StatefulSets and PersistentVolumes. This offers more control but significantly increases operational complexity.

We’ll focus on the self-managed approach for demonstration, as it highlights Kubernetes orchestration capabilities. For production, AWS RDS is generally preferred.

MySQL StatefulSet and Service

A StatefulSet is ideal for databases as it provides stable network identifiers and persistent storage for each pod. We’ll define a primary and a replica configuration.

apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
  labels:
    app: mysql
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None # Headless service
  selector:
    app: mysql
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: "mysql-headless"
  replicas: 2 # 1 primary, 1 replica
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        ports:
        - containerPort: 3306
          name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secrets
              key: root-password
        - name: MYSQL_DATABASE
          value: "laravel_db"
        - name: MYSQL_USER
          value: "laravel_user"
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secrets
              key: user-password
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mysql-persistent-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi
      storageClassName: "gp2" # Or your preferred EBS CSI driver storage class

This setup creates a headless service for stable DNS names (e.g., mysql-0.mysql-headless.default.svc.cluster.local) and a StatefulSet. You’ll need to manually configure replication between the pods after they are up and running, or use a more sophisticated operator like Percona Operator for MySQL.

Configuring MySQL Replication

Manual replication setup involves:

  • Initializing the primary MySQL instance with a specific server ID and enabling binary logging.
  • Configuring a replication user on the primary.
  • On the replica instance, setting its server ID, and then using CHANGE MASTER TO with the primary’s details and the replication user credentials.
  • Starting the replication process.

This process is complex to automate within Kubernetes manifests alone and often requires custom scripts or operators. For instance, you might have an init container that checks if it’s the first pod (primary) or a subsequent pod (replica) and configures itself accordingly.

A simplified approach for demonstration within Kubernetes might involve a single MySQL pod acting as primary and another pod configured as a replica. The application would then be configured to use the primary for writes and potentially a read-only replica Service for reads.

Application Configuration for Database Access

Your Laravel application’s .env file (or environment variables injected via Kubernetes) will need to reflect the database setup. For read/write splitting, you’d define multiple database connections.

DB_CONNECTION=mysql
DB_HOST=mysql-0.mysql-headless.default.svc.cluster.local # Primary DB
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=laravel_user
DB_PASSWORD=your_user_password

DB_READ_HOST=mysql-1.mysql-headless.default.svc.cluster.local # Replica DB
DB_READ_PORT=3306
DB_READ_DATABASE=laravel_db
DB_READ_USERNAME=laravel_user
DB_READ_PASSWORD=your_user_password

In your Laravel application’s config/database.php, you would configure read/write connections:

return [
    // ... other configurations
    'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            // ...
        ],

        'mysql_read' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_READ_HOST', '127.0.0.1'),
            'port' => env('DB_READ_PORT', '3306'),
            'database' => env('DB_READ_DATABASE', 'forge'),
            'username' => env('DB_READ_USERNAME', 'forge'),
            'password' => env('DB_READ_PASSWORD', ''),
            // ...
        ],
    ],

    'redis' => [
        // ... Redis configuration for queues
    ],
];

Then, in your Eloquent models, you can specify the connection:

class User extends Model
{
    protected $connection = 'mysql_read'; // Use read replica for fetching users
}

class Order extends Model
{
    protected $connection = 'mysql'; // Use primary for orders
}

Monitoring and Logging

Effective monitoring and logging are paramount in a microservices architecture. For PHP-FPM, ensure logs are collected. For Laravel Queues, monitor queue lengths and job processing times. For MySQL, track replication lag and performance metrics.

  • Logging: Integrate with a centralized logging solution like Elasticsearch/Fluentd/Kibana (EFK) or AWS CloudWatch Logs. Configure your PHP-FPM and application to output logs in a structured format (e.g., JSON).
  • Metrics: Deploy Prometheus and Grafana for metrics collection and visualization. Use exporters for PHP-FPM (e.g., pm_exporter), MySQL, and potentially custom application metrics.
  • Alerting: Configure Alertmanager to notify on critical events, such as high replication lag, failing queue workers, or PHP error rates exceeding thresholds.

Conclusion and Next Steps

This deep dive provides a foundational Kubernetes deployment strategy for PHP-FPM and Laravel applications on AWS EKS, incorporating essential components like queue workers and MySQL replication. Key takeaways include the importance of fine-tuning PHP-FPM settings for containers, defining robust Kubernetes manifests with health checks, and understanding the complexities of database orchestration. For production environments, leveraging managed services like AWS RDS and considering Kubernetes Operators for stateful applications will significantly reduce operational overhead and enhance reliability.

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

  • Orchestrating Microservices with Kubernetes: A Deep Dive into PHP-FPM, Laravel Queues, and MySQL Replication on AWS EKS
  • Mastering Containerized WordPress: Advanced Docker Orchestration for Scalable Headless Deployments
  • Leveraging PHP 8.3 JIT and Laravel Octane for Near Real-Time Microservices: A Performance and Scalability Deep Dive
  • Leveraging PHP 8.3’s JIT Compiler and Vectorization for Extreme Performance Gains in Laravel Applications
  • Unlocking Serverless PHP 9: A Deep Dive into Lamdba-Optimized Laravel Deployments with Layers and Custom Runtimes

Categories

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

Recent Posts

  • Orchestrating Microservices with Kubernetes: A Deep Dive into PHP-FPM, Laravel Queues, and MySQL Replication on AWS EKS
  • Mastering Containerized WordPress: Advanced Docker Orchestration for Scalable Headless Deployments
  • Leveraging PHP 8.3 JIT and Laravel Octane for Near Real-Time Microservices: A Performance and Scalability Deep Dive

Top Categories

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

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