• 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 8/9 and Laravel in a Dockerized AWS Environment

Orchestrating Microservices with Kubernetes: A Deep Dive into PHP 8/9 and Laravel in a Dockerized AWS Environment

Setting the Stage: Dockerizing PHP 8/9 Laravel Applications

Before we can orchestrate, we must containerize. This section details a robust Docker setup for a typical PHP 8/9 Laravel application, focusing on production-readiness. We’ll leverage multi-stage builds to keep our final image lean and secure.

Consider a standard Dockerfile for our Laravel application:

# Stage 1: Builder
FROM php:8.2-fpm AS builder

# Install essential extensions and tools
RUN apt-get update && apt-get install -y \
    git \
    unzip \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    acl \
    supervisor \
    && rm -rf /var/lib/apt/lists/* \
    && 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

# Set working directory
WORKDIR /var/www/html

# Copy composer.json and composer.lock
COPY --chown=www-data:www-data composer.json composer.lock ./

# Install Composer dependencies
RUN composer install --no-dev --no-autoloader --no-scripts --prefer-dist \
    && composer clear-cache

# Copy the rest of the application code
COPY --chown=www-data:www-data . .

# Install Composer autoloader and run post-install scripts
RUN composer dump-autoload --optimize --no-dev

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

# Stage 2: Production Image
FROM php:8.2-fpm-alpine AS production

# Install only necessary extensions for runtime
RUN apk add --no-cache \
    libzip \
    libpng \
    libjpeg-turbo \
    freetype \
    oniguruma \
    libxml2 \
    acl \
    supervisor \
    && 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

# Copy application code from builder stage
COPY --from=builder --chown=www-data:www-data /var/www/html /var/www/html

# Copy optimized autoloader from builder stage
COPY --from=builder --chown=www-data:www-data /var/www/html/vendor /var/www/html/vendor

# Ensure correct permissions
RUN chown -R www-data:www-data storage bootstrap/cache && chmod -R 775 storage bootstrap/cache

# Copy supervisor configuration
COPY docker/supervisor/app.conf /etc/supervisor/conf.d/app.conf

# Expose port
EXPOSE 9000

# Start supervisor
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

The supervisor configuration (docker/supervisor/app.conf) is crucial for managing the PHP-FPM process and any background queue workers:

[program:php-fpm]
process_name=%(program_name)s_%(process_num)02d
command=/usr/local/sbin/php-fpm --nodaemonize --fpm-config /usr/local/etc/php-fpm.conf
autostart=true
autorestart=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/supervisor/php-fpm.log

[program:queue-worker]
process_name=%(program_name)s_%(process_num)02d
command=php artisan queue:work --tries=3 --timeout=60
autostart=true
autorestart=true
user=www-data
numprocs=2 ; Adjust based on expected load
redirect_stderr=true
stdout_logfile=/var/log/supervisor/queue-worker.log

This setup ensures that PHP-FPM is always running and provides a template for managing queue workers. The multi-stage build significantly reduces the final image size by discarding build dependencies.

Kubernetes Deployment Strategy: Deployments and Services

For Kubernetes, we’ll define Deployments to manage our application pods and Services to expose them internally and externally. We’ll also consider a HorizontalPodAutoscaler for dynamic scaling.

A typical Kubernetes Deployment manifest:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: laravel-app-deployment
  labels:
    app: laravel-app
spec:
  replicas: 3 # Initial number of replicas
  selector:
    matchLabels:
      app: laravel-app
  template:
    metadata:
      labels:
        app: laravel-app
    spec:
      containers:
      - name: laravel-app
        image: YOUR_ECR_REPO/laravel-app:latest # Replace with your ECR image
        ports:
        - containerPort: 9000
        env:
        - name: APP_ENV
          value: "production"
        - name: APP_KEY
          valueFrom:
            secretKeyRef:
              name: laravel-secrets
              key: app-key
        - name: DB_HOST
          value: "mysql-service" # Assuming a MySQL service named mysql-service
        - name: DB_PORT
          value: "3306"
        - name: DB_DATABASE
          valueFrom:
            secretKeyRef:
              name: laravel-secrets
              key: db-name
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              name: laravel-secrets
              key: db-user
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: laravel-secrets
              key: db-password
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /healthz # A simple health check endpoint in Laravel
            port: 9000
          initialDelaySeconds: 15
          periodSeconds: 20
        readinessProbe:
          httpGet:
            path: /healthz
            port: 9000
          initialDelaySeconds: 5
          periodSeconds: 10
      # Optional: Node selectors or affinity rules for specific node placement
      # nodeSelector:
      #   kubernetes.io/os: linux
      # affinity:
      #   podAffinity:
      #     requiredDuringSchedulingIgnoredDuringExecution:
      #     - labelSelector:
      #         matchExpressions:
      #         - key: app
      #           operator: In
      #           values:
      #           - laravel-app
      #       topologyKey: "kubernetes.io/hostname"

And a corresponding Service to route traffic to the application pods:

apiVersion: v1
kind: Service
metadata:
  name: laravel-app-service
spec:
  selector:
    app: laravel-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9000 # The port PHP-FPM is listening on inside the container
  type: ClusterIP # Use LoadBalancer or NodePort for external access, or an Ingress controller

For external access, we’ll typically use an Ingress controller (like AWS ALB Ingress Controller or Nginx Ingress Controller). Here’s a basic Ingress resource:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: laravel-app-ingress
  annotations:
    # Annotations specific to your Ingress controller (e.g., AWS ALB)
    kubernetes.io/ingress.class: "alb"
    alb.ingress.kubernetes.io/scheme: "internet-facing"
    alb.ingress.kubernetes.io/target-type: "ip"
spec:
  rules:
  - host: your-app.example.com # Your domain name
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: laravel-app-service
            port:
              number: 80

The HorizontalPodAutoscaler will automatically adjust the number of replicas based on CPU utilization:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: laravel-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: laravel-app-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70 # Scale up when CPU utilization reaches 70%

Managing Background Jobs: Kubernetes Jobs and CronJobs

Laravel’s queue system is essential for background processing. In Kubernetes, we can manage queue workers using Deployments (as shown above with supervisor) or more granularly with Jobs for one-off tasks and CronJobs for scheduled tasks.

For a persistent queue worker pool managed by Supervisor within the application pod, the previous Deployment configuration is sufficient. However, for specific, long-running or batch jobs, a dedicated Job resource is more appropriate:

apiVersion: batch/v1
kind: Job
metadata:
  name: laravel-batch-job
spec:
  template:
    spec:
      containers:
      - name: laravel-batch-processor
        image: YOUR_ECR_REPO/laravel-app:latest # Use the same application image
        command: ["php", "artisan", "my:custom:batch-job", "--env=production"] # Your custom Artisan command
        envFrom: # Inherit environment variables from a ConfigMap or Secrets
        - configMapRef:
            name: laravel-config
        - secretRef:
            name: laravel-secrets
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
      restartPolicy: Never # Or OnFailure
  backoffLimit: 4 # Number of retries before marking the job as failed

For scheduled tasks (e.g., daily reports), Kubernetes CronJobs are the standard:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: laravel-cron-daily-report
spec:
  schedule: "0 2 * * *" # Run daily at 2 AM
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: laravel-cron-reporter
            image: YOUR_ECR_REPO/laravel-app:latest
            command: ["php", "artisan", "reports:generate:daily", "--env=production"]
            envFrom:
            - configMapRef:
                name: laravel-config
            - secretRef:
                name: laravel-secrets
            resources:
              requests:
                memory: "128Mi"
                cpu: "100m"
              limits:
                memory: "256Mi"
                cpu: "200m"
          restartPolicy: OnFailure
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 1

Ensure your Laravel application has the necessary Artisan commands registered (e.g., app/Console/Kernel.php) and that your .env variables are correctly mapped via Kubernetes ConfigMaps and Secrets.

Database and Cache Orchestration with AWS RDS and ElastiCache

For production environments, relying on local databases within containers is not advisable. AWS RDS for MySQL (or PostgreSQL) and ElastiCache for Redis provide managed, scalable, and highly available solutions. These services are accessed directly by your application pods.

When configuring your Laravel application’s .env file (which will be populated via Kubernetes Secrets), the database connection details will point to the AWS service endpoints:

DB_CONNECTION=mysql
DB_HOST=your-rds-instance.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com
DB_PORT=3306
DB_DATABASE=your_database_name
DB_USERNAME=your_db_user
DB_PASSWORD=your_db_password

REDIS_HOST=your-elasticache-redis-node.xxxxxxxxxxxx.ng.0001.use1.cache.amazonaws.com
REDIS_PORT=6379
REDIS_PASSWORD=null # If no password is set

In Kubernetes, these sensitive values should be stored in Secrets. For example, a Secret for database credentials:

apiVersion: v1
kind: Secret
metadata:
  name: laravel-secrets
type: Opaque
data:
  app-key: YOUR_BASE64_ENCODED_APP_KEY
  db-name: YOUR_BASE64_ENCODED_DB_NAME
  db-user: YOUR_BASE64_ENCODED_DB_USER
  db-password: YOUR_BASE64_ENCODED_DB_PASSWORD

And a ConfigMap for non-sensitive configuration:

apiVersion: v1
kind: ConfigMap
metadata:
  name: laravel-config
data:
  APP_ENV: "production"
  APP_URL: "https://your-app.example.com"
  # Add other non-sensitive .env variables here

Your application pods will then mount these ConfigMaps and Secrets as environment variables, as demonstrated in the Deployment manifest earlier. This decouples configuration and secrets from your container image, enhancing security and manageability.

CI/CD Pipeline Integration with AWS ECR and EKS

A robust CI/CD pipeline is paramount. We’ll outline a workflow using AWS CodePipeline, CodeBuild, and ECR to build, test, and deploy our Dockerized Laravel application to EKS.

The pipeline typically involves these stages:

  • Source Stage: Triggered by code commits to a repository (e.g., AWS CodeCommit, GitHub).
  • Build Stage (AWS CodeBuild):
    • Checks out code.
    • Builds the Docker image using the Dockerfile.
    • Pushes the image to AWS ECR (Elastic Container Registry).
    • Runs unit and integration tests.
  • Deploy Stage (AWS CodePipeline/EKS):
    • Updates the Kubernetes Deployment resource to pull the new image from ECR. This can be done by updating the image tag in the Kubernetes manifest and applying it, or by using tools like Argo CD or Flux CD for GitOps-based deployments.

A simplified buildspec.yml for AWS CodeBuild:

version: 0.2

phases:
  install:
    runtime-versions:
      php: 8.2 # Ensure the runtime matches your Dockerfile
    commands:
      - echo "Installing dependencies..."
      - apt-get update -y && apt-get install -y docker.io && rm -rf /var/lib/apt/lists/*
      - echo "Logging in to Amazon ECR..."
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
      - REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c1-7)
      - IMAGE_TAG=$COMMIT_HASH-$CODEBUILD_BUILD_ID
  pre_build:
    commands:
      - echo "Pulling existing image if it exists..."
      - docker pull $REPOSITORY_URI:$IMAGE_TAG || true
  build:
    commands:
      - echo "Building the Docker image..."
      - docker build -t $REPOSITORY_URI:$IMAGE_TAG .
      - echo "Pushing the Docker image to ECR..."
      - docker push $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - echo "Running tests..."
      # Example: Run PHPUnit tests
      - docker run --rm -v $(pwd):/app -w /app php:8.2-cli php artisan test
      - echo "Deployment preparation complete."
      # If using kubectl directly, configure kubectl here and apply manifests
      # - echo "Deploying to EKS..."
      # - aws eks update-kubeconfig --name $EKS_CLUSTER_NAME --region $AWS_DEFAULT_REGION
      # - sed "s|YOUR_ECR_REPO/laravel-app:latest|$REPOSITORY_URI:$IMAGE_TAG|g" kubernetes/deployment.yaml > kubernetes/deployment-temp.yaml
      # - kubectl apply -f kubernetes/deployment-temp.yaml
      # - rm kubernetes/deployment-temp.yaml
      # - kubectl apply -f kubernetes/service.yaml
      # - kubectl apply -f kubernetes/ingress.yaml
      # - kubectl apply -f kubernetes/hpa.yaml

# Define environment variables for CodeBuild
# These would be set in the CodePipeline/CodeBuild configuration
# e.g., IMAGE_REPO_NAME, AWS_ACCOUNT_ID, EKS_CLUSTER_NAME

The deployment step in CodePipeline can then be configured to trigger an EKS update. For more advanced GitOps workflows, tools like Argo CD or Flux CD can monitor a Git repository containing your Kubernetes manifests and automatically apply changes when new image tags are updated in ECR or referenced in Git.

Monitoring and Logging Strategies

Effective monitoring and logging are critical for maintaining a healthy Kubernetes cluster and application. We’ll leverage Prometheus for metrics and Fluentd/Fluent Bit for log aggregation.

Metrics:

  • Prometheus: Deploy Prometheus to your EKS cluster. It can scrape metrics from various sources, including Kubernetes itself, node exporters, and application-specific metrics.
  • Application Metrics: Instrument your Laravel application to expose metrics. Libraries like prometheus_client for PHP can be used. Expose these metrics via an HTTP endpoint (e.g., /metrics) that Prometheus can scrape.
  • Alerting: Configure Alertmanager to send notifications based on Prometheus alerts (e.g., high error rates, low replica counts, high latency).

Logging:

  • Fluentd/Fluent Bit DaemonSet: Deploy Fluentd or Fluent Bit as a DaemonSet on your EKS cluster. This ensures a logging agent runs on each node.
  • Log Aggregation: Configure the DaemonSet to collect logs from all containers (including PHP-FPM, queue workers, etc.) and forward them to a centralized logging system like AWS CloudWatch Logs, Elasticsearch, or Splunk.
  • Structured Logging: Ensure your Laravel application logs in a structured format (e.g., JSON). This makes log parsing and querying much easier in your centralized logging system. You can achieve this by using a custom log formatter in Laravel’s logging configuration.

Example of a basic structured log formatter in Laravel (app/Providers/AppServiceProvider.php):

use Illuminate\Support\ServiceProvider;
use Monolog\Formatter\JsonFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        $this->app->extend('log', function ($log) {
            $handler = new StreamHandler(storage_path('logs/laravel.log'), Logger::DEBUG);
            $handler->setFormatter(new JsonFormatter());
            $log->getMonolog()->pushHandler($handler);
            return $log;
        });
    }
}

This ensures that logs generated by Laravel’s logging facade will be in JSON format, simplifying ingestion and analysis by log aggregation tools.

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

  • Leveraging PHP 9’s JIT and Vector API for Extreme Performance in High-Concurrency Laravel Applications
  • Beyond the Basics: Advanced Docker Multi-Stage Builds for Optimized PHP 8/9 Application Deployment and Security Hardening
  • Leveraging PHP 9’s JIT Compilation and Typed Properties for High-Performance, Secure WordPress REST APIs
  • Orchestrating Microservices with Kubernetes: A Deep Dive into PHP 8/9 and Laravel in a Dockerized AWS Environment
  • Leveraging PHP 8.3’s JIT and Vector API for High-Performance WordPress Headless Applications on AWS Lambda

Categories

  • apache (1)
  • AWS (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (664)
  • Desktop Applications (14)
  • DevOps (24)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (21)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • Performance & Security Optimization (4)
  • PHP (79)
  • 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 (150)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (59)
  • WordPress Plugin Development (728)
  • WordPress Theme Development (357)

Recent Posts

  • Leveraging PHP 9's JIT and Vector API for Extreme Performance in High-Concurrency Laravel Applications
  • Beyond the Basics: Advanced Docker Multi-Stage Builds for Optimized PHP 8/9 Application Deployment and Security Hardening
  • Leveraging PHP 9's JIT Compilation and Typed Properties for High-Performance, Secure WordPress REST APIs

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