• 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 Docker Swarm: A Practical Guide to Scalable PHP & Laravel Deployments

Orchestrating Microservices with Docker Swarm: A Practical Guide to Scalable PHP & Laravel Deployments

Setting Up a Docker Swarm Cluster

Before orchestrating microservices, we need a functional Docker Swarm cluster. This guide assumes you have at least two machines (physical or virtual) with Docker installed. One will act as the manager node, and the others as worker nodes.

On the designated manager node, initialize the swarm:

docker swarm init --advertise-addr 

This command will output a docker swarm join command. Execute this command on each worker node to add them to the swarm. For example:

docker swarm join --token SWMTKN-1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x.x.x.x:2377

Verify the cluster status on the manager node:

docker node ls

Defining Microservices with Docker Compose

We’ll define our PHP/Laravel microservices using a docker-compose.yml file. For a typical Laravel application, this would include services for the web application, a database (e.g., MySQL or PostgreSQL), and potentially a cache (e.g., Redis).

version: '3.8'

services:
  app:
    image: php:8.2-fpm-alpine
    container_name: my_laravel_app
    volumes:
      - ./src:/var/www/html
    working_dir: /var/www/html
    networks:
      - app-network
    depends_on:
      - db
      - redis
    environment:
      DB_HOST: db
      DB_PORT: 3306
      DB_DATABASE: laravel_db
      DB_USERNAME: user
      DB_PASSWORD: password
      REDIS_HOST: redis
      REDIS_PORT: 6379
    deploy:
      replicas: 3 # Initial desired replicas
      restart_policy:
        condition: on-failure

  nginx:
    image: nginx:alpine
    container_name: my_nginx_proxy
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - ./src:/var/www/html # Mount app code for Nginx to serve static assets
    networks:
      - app-network
    depends_on:
      - app
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

  db:
    image: mysql:8.0
    container_name: my_mysql_db
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - app-network
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: laravel_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

  redis:
    image: redis:alpine
    container_name: my_redis_cache
    networks:
      - app-network
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

networks:
  app-network:
    driver: overlay

volumes:
  db_data:

Key points:

  • We use the overlay network driver, which is essential for multi-host Swarm communication.
  • The deploy section is crucial for Swarm. It defines the desired state, including the number of replicas (containers) for each service.
  • Environment variables are used to configure the application and its dependencies.
  • Volumes are defined for persistent data (like the database) and for mounting application code.

Building and Pushing Docker Images

For production, it’s best practice to build your application image and push it to a container registry (e.g., Docker Hub, AWS ECR, Google Container Registry). This ensures consistent deployments across your Swarm nodes.

Create a Dockerfile for your Laravel application:

FROM php:8.2-fpm-alpine

RUN apk add --no-cache \
    nginx \
    supervisor \
    git \
    zip \
    unzip \
    icu-dev \
    libzip-dev \
    libpng-dev \
    freetype-dev \
    jpeg-dev \
    libjpeg-turbo-dev \
    libwebp-dev \
    libintl-dev \
    libxml2-dev \
    oniguruma-dev \
    postgresql-dev \
    # Add other necessary packages

RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
    && docker-php-ext-install -j$(nproc) gd \
    && docker-php-ext-install intl zip pdo pdo_mysql # Adjust pdo_mysql if using PostgreSQL

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

COPY ./src /var/www/html
COPY ./docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY ./docker/supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf

WORKDIR /var/www/html

RUN chown -R www-data:www-data /var/www/html \
    && chmod -R 755 /var/www/html \
    && composer install --no-dev --optimize-autoloader \
    && php artisan cache:clear \
    && php artisan config:cache \
    && php artisan route:cache \
    && php artisan view:cache

EXPOSE 80

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

And a corresponding supervisord.conf to manage PHP-FPM and Nginx:

[supervisord]
nodaemon=true
user=root

[program:php-fpm]
command=/usr/local/sbin/php-fpm -D
autostart=true
autorestart=true
priority=10
stdout_logfile=/var/log/supervisor/php-fpm.log
stderr_logfile=/var/log/supervisor/php-fpm.err.log

[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
priority=20
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx.err.log

Build the image:

docker build -t your-dockerhub-username/my-laravel-app:latest .

Tag and push to your registry:

docker push your-dockerhub-username/my-laravel-app:latest

Deploying Services to Docker Swarm

Now, we’ll deploy our services to the Swarm. We’ll modify the docker-compose.yml to use our custom image and remove the container_name as Swarm assigns unique IDs.

version: '3.8'

services:
  app:
    image: your-dockerhub-username/my-laravel-app:latest # Use your custom image
    ports:
      - "8000:80" # Expose app port for external access if needed, or rely on ingress
    networks:
      - app-network
    depends_on:
      - db
      - redis
    environment:
      DB_HOST: db
      DB_PORT: 3306
      DB_DATABASE: laravel_db
      DB_USERNAME: user
      DB_PASSWORD: password
      REDIS_HOST: redis
      REDIS_PORT: 6379
    deploy:
      replicas: 3
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

  nginx:
    image: nginx:alpine
    ports:
      - "80:80" # Publicly accessible port
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    networks:
      - app-network
    depends_on:
      - app
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
      restart_policy:
        condition: on-failure

  db:
    image: mysql:8.0
    networks:
      - app-network
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: laravel_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    volumes:
      - db_data:/var/lib/mysql
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

  redis:
    image: redis:alpine
    networks:
      - app-network
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

networks:
  app-network:
    driver: overlay

volumes:
  db_data:

Deploy the stack to your Swarm cluster:

docker stack deploy -c docker-compose.yml my_laravel_app_stack

This command will create a new “stack” named my_laravel_app_stack and deploy all the defined services across your Swarm nodes. Swarm will ensure the desired number of replicas for each service are running.

Configuring Nginx for Load Balancing

The Nginx service will act as a reverse proxy and load balancer for our PHP application. We need to configure it to forward requests to the available instances of the app service. Swarm’s DNS resolution makes this straightforward.

# ./nginx.conf
upstream php_app {
    # Swarm service name 'app' will resolve to the IPs of its running tasks
    server app:9000;
}

server {
    listen 80;
    index index.php index.html;
    root /var/www/html/public; # Adjust if your public directory is different

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

    location ~ \.php$ {
        try_files /dev/null =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php_app; # Use the upstream name defined above
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ /\.ht {
        deny all;
    }

    # Serve static assets directly from the mounted volume
    location ~* \.(css|js|jpg|jpeg|gif|png|svg|ico|webp)$ {
        expires 1d;
        add_header Cache-Control "public";
        # Ensure this path matches where your static assets are served from
        root /var/www/html/public;
    }
}

In this Nginx configuration:

  • The upstream php_app block defines a group of servers. When you use the service name app (which is the service name in our docker-compose.yml) as a hostname, Docker’s embedded DNS will resolve it to the IP addresses of all running containers (tasks) for that service. Nginx will then round-robin requests to these IPs.
  • We’re passing requests to the PHP-FPM service on port 9000.
  • Static assets are configured to be served directly by Nginx for better performance.

Scaling and Health Checks

Docker Swarm provides built-in mechanisms for scaling and health monitoring.

To scale the application service up or down, update the replicas count in your docker-compose.yml and redeploy:

# Edit docker-compose.yml, change replicas: 3 to replicas: 5
docker stack deploy -c docker-compose.yml my_laravel_app_stack

Swarm will automatically adjust the number of running containers for the app service. The update_config in the deploy section controls how these updates are rolled out, minimizing downtime.

For more robust health checking, you can add a healthcheck directive to your app service in the docker-compose.yml. This allows Swarm to detect unhealthy containers and replace them.

# ... inside the 'app' service definition ...
    deploy:
      replicas: 3
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure
      healthcheck:
        test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"] # Assuming you have a /health endpoint
        interval: 30s
        timeout: 10s
        retries: 3
        start_period: 60s # Give the container time to start up

You would need to implement a simple /health route in your Laravel application that returns a 200 OK status code.

Managing Swarm Services

Here are some essential commands for managing your deployed stack:

  • View running services: docker service ls
  • View tasks (containers) for a service: docker service ps my_laravel_app_stack_app
  • View logs for a service: docker service logs my_laravel_app_stack_app
  • Scale a service manually: docker service scale my_laravel_app_stack_app=5
  • Update a service (e.g., with a new image): docker service update --image your-dockerhub-username/my-laravel-app:new-tag my_laravel_app_stack_app
  • Remove the entire stack: docker stack rm my_laravel_app_stack

This setup provides a solid foundation for deploying scalable PHP and Laravel applications using Docker Swarm, leveraging its orchestration capabilities for resilience and manageability.

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 Docker Swarm: A Practical Guide to Scalable PHP & Laravel Deployments
  • Leveraging PHP 9’s JIT Compiler for Extreme Laravel Performance: A Deep Dive into Runtime Optimization & Benchmarking
  • Architecting Resilient WordPress Headless Deployments with Docker, AWS ECS, and Advanced Caching Strategies
  • Orchestrating Microservices with Kubernetes and PHP 9: A Deep Dive into Scalability and Resilience
  • Unlocking Edge Performance: Advanced Caching Strategies for Laravel Applications with Redis and Cloudflare Workers

Categories

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

Recent Posts

  • Orchestrating Microservices with Docker Swarm: A Practical Guide to Scalable PHP & Laravel Deployments
  • Leveraging PHP 9's JIT Compiler for Extreme Laravel Performance: A Deep Dive into Runtime Optimization & Benchmarking
  • Architecting Resilient WordPress Headless Deployments with Docker, AWS ECS, and Advanced Caching Strategies

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