Leveraging Laravel Octane with Docker Swarm for High-Concurrency WordPress Headless Microservices
Architectural Overview: Laravel Octane, Docker Swarm, and Headless WordPress Microservices
This architecture leverages Laravel Octane for high-performance PHP execution, Docker Swarm for container orchestration, and a headless WordPress instance to serve content via a robust API. The goal is to build a scalable, resilient system capable of handling high concurrency for microservices that might, for example, power a complex e-commerce frontend, a mobile application backend, or a real-time data dashboard. We’ll focus on the practical implementation details, from Dockerfile construction to Swarm service deployment and Octane configuration.
Dockerizing Laravel Octane Applications
A production-ready Dockerfile for a Laravel Octane application needs to be optimized for speed and security. We’ll use a multi-stage build to keep the final image lean. The core idea is to compile assets and install dependencies in a separate build stage, then copy only the necessary artifacts to a minimal runtime image.
Dockerfile for Laravel Octane
This Dockerfile assumes you are using Composer for dependency management and Node.js/npm for frontend asset compilation. It’s designed to be run within a Docker Swarm environment, so it doesn’t include web server configurations like Nginx directly within the application container; that will be handled by a separate reverse proxy service in the Swarm.
# Stage 1: Build dependencies and compile assets
FROM composer:latest AS builder
WORKDIR /app
# Copy composer files and install dependencies
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction
# Copy application code
COPY . .
# Install Node.js dependencies and compile assets (if applicable)
# Ensure you have a .dockerignore file to exclude unnecessary files like node_modules
RUN npm install && npm run build
# Stage 2: Production runtime
FROM php:8.2-fpm-alpine
# Install necessary PHP extensions
RUN apk add --no-cache \
libzip-dev \
zip \
icu-dev \
libpng-dev \
libjpeg-turbo-dev \
freetype-dev \
oniguruma-dev \
postgresql-dev \
git \
supervisor
RUN docker-php-ext-configure gd --with-freetype --with-jpeg && docker-php-ext-install gd && docker-php-ext-install zip && docker-php-ext-install intl && docker-php-ext-install pdo_pgsql
# Set working directory
WORKDIR /app
# Copy application code from builder stage
COPY --from=builder /app /app
# Copy compiled assets from builder stage
COPY --from=builder /app/public/build /app/public/build
# Install Octane and its dependencies
RUN composer require laravel/octane --no-dev --optimize-autoloader
# Clear cache
RUN php artisan optimize:clear
# Copy supervisor configuration for Octane
COPY docker/supervisor/octane.conf /etc/supervisor/conf.d/octane.conf
# Expose the port Octane will run on (default is 8000 for Swoole/RoadRunner)
EXPOSE 8000
# Set permissions for storage and bootstrap/cache
RUN chown -R www-data:www-data /app/storage /app/bootstrap/cache
# Start supervisor to manage Octane process
CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/supervisord.conf"]
Supervisor Configuration for Octane
Supervisor is crucial for managing the long-running Octane process. We’ll configure it to start and monitor the Octane server.
; docker/supervisor/octane.conf [program:octane] process_name=%(program_name)s_%(process_num)02d command=php artisan octane:start --host=0.0.0.0 --port=8000 --workers=auto --max-requests=5000 --force autostart=true autorestart=true user=www-data numprocs=1 redirect_stderr=true stdout_logfile=/var/log/supervisor/octane.log stderr_logfile=/var/log/supervisor/octane.log
Headless WordPress API Setup
For a headless setup, WordPress will act solely as a content management system. We’ll use the built-in REST API or a plugin like WPGraphQL for more advanced querying. The key is to secure the API and ensure it’s accessible to your Laravel microservices.
Securing the WordPress REST API
Basic authentication or JWT authentication is recommended. For simplicity in this example, we’ll assume basic authentication is configured, perhaps via a plugin or custom code. Ensure your WordPress instance is running in a separate Docker container, accessible within the Docker Swarm network.
Docker Swarm Service Deployment
Docker Swarm provides the orchestration layer. We’ll define services for our Laravel Octane microservices, a reverse proxy (like Traefik or Nginx), and the headless WordPress instance.
Docker Compose File for Swarm
This `docker-compose.yml` file defines the services for our Swarm. We’ll create a network for communication and define replicas for scalability. The `wordpress` service is a placeholder; you’d typically use an official WordPress image with a database.
version: '3.8'
networks:
app-network:
driver: overlay
attachable: true
services:
wordpress:
image: wordpress:latest
networks:
- app-network
deploy:
replicas: 1
restart_policy:
condition: on-failure
# Add environment variables for database connection, etc.
traefik:
image: traefik:v2.9
command:
- --api.insecure=true
- --providers.docker=true
- --providers.docker.swarmmode=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- app-network
deploy:
replicas: 1
placement:
constraints:
- node.role == manager # Run Traefik on manager nodes for simplicity
laravel-microservice-1:
build:
context: . # Assumes Dockerfile is in the root of the project
dockerfile: Dockerfile
image: your-dockerhub-username/laravel-octane-microservice:latest
networks:
- app-network
environment:
# Example environment variables
- APP_ENV=production
- APP_KEY=base64:...
- WP_API_URL=http://wordpress/wp-json/
- WP_API_USER=your_wp_user
- WP_API_PASSWORD=your_wp_password
labels:
- "traefik.enable=true"
- "traefik.http.routers.microservice1.rule=Host(`microservice1.yourdomain.com`)"
- "traefik.http.routers.microservice1.entrypoints=web"
- "traefik.http.services.microservice1.loadbalancer.server.port=8000" # Octane's port
deploy:
replicas: 3 # Scale to 3 instances for high concurrency
restart_policy:
condition: on-failure
update_config:
parallelism: 2
delay: 10s
# Add more laravel-microservice services as needed
# laravel-microservice-2:
# build: ...
# image: ...
# networks: ...
# environment: ...
# labels: ...
# deploy: ...
Deploying to Docker Swarm
Initialize your Swarm if you haven’t already:
docker swarm init
Then, deploy the stack:
docker stack deploy -c docker-compose.yml your_stack_name
Integrating Laravel Octane with WordPress API
Within your Laravel microservice, you’ll consume the headless WordPress API. Octane’s persistent processes mean you can optimize API client connections and caching.
Example: Fetching Posts in Laravel
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$wpApiUrl = config('services.wordpress.url');
$wpUser = config('services.wordpress.user');
$wpPassword = config('services.wordpress.password');
// Use caching to reduce API calls, especially with Octane's persistent processes
$posts = Cache::remember('wp_posts', 60 * 5, function () use ($wpApiUrl, $wpUser, $wpPassword) {
$response = Http::withBasicAuth($wpUser, $wpPassword)
->get("{$wpApiUrl}/wp-json/wp/v2/posts");
if ($response->successful()) {
return $response->json();
}
// Handle API errors appropriately
return [];
});
return response()->json($posts);
}
}
Configuration for WordPress API
# config/services.php
'wordpress' => [
'url' => env('WP_API_URL', 'http://wordpress/wp-json/'),
'user' => env('WP_API_USER', 'your_wp_user'),
'password' => env('WP_API_PASSWORD', 'your_wp_password'),
],
Ensure these environment variables are set in your Docker Swarm service definition for the Laravel microservices.
Octane Configuration and Performance Tuning
Laravel Octane significantly boosts performance by keeping your application’s bootstrap process in memory. Fine-tuning its configuration is key for high-concurrency scenarios.
Octane Server Configuration
The `octane:start` command offers several options:
--host: The IP address to bind to (e.g.,0.0.0.0to listen on all interfaces within the container).--port: The port Octane will listen on (e.g.,8000).--workers: The number of worker processes.autois a good starting point, letting Octane decide based on CPU cores. You might need to tune this based on your Swarm node resources and application’s memory footprint.--max-requests: The number of requests a worker will process before respawning. This helps prevent memory leaks. A value between 5000-10000 is often suitable.--force: Forces Octane to start even if it detects it’s not running in a typical CLI environment (useful for Docker).
Caching Strategies
With Octane, you can leverage in-memory caching (like Redis or Memcached) more effectively. For inter-service communication or shared state, Redis is an excellent choice. Ensure your Laravel application is configured to use Redis:
// config/cache.php
'default' => env('CACHE_DRIVER', 'redis'),
// config/database.php (for Redis connection)
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),
],
'default' => [
'host' => env('REDIS_HOST', 'redis'), // Assuming a separate Redis service in Swarm
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DB', 0),
],
],
Monitoring and Logging
Effective monitoring is critical for a distributed system. Docker Swarm provides basic health checks, and you can integrate more advanced solutions.
Container Health Checks
Add health checks to your Docker Compose file to allow Swarm to manage container health:
# ... inside your laravel-microservice service definition
deploy:
replicas: 3
restart_policy:
condition: on-failure
update_config:
parallelism: 2
delay: 10s
# Add healthcheck
health_check:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8000/health"] # Assuming a /health endpoint in Laravel
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
You’ll need to create a simple `/health` route in your Laravel application:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
class HealthCheckController extends Controller
{
public function show(): JsonResponse
{
// You can add more sophisticated checks here, e.g., database connection
return response()->json(['status' => 'UP']);
}
}
Centralized Logging
Configure a centralized logging solution (e.g., ELK stack, Grafana Loki) to aggregate logs from all your Docker containers. This is essential for debugging issues across multiple microservices.
Conclusion and Next Steps
This architecture provides a robust foundation for building high-concurrency headless WordPress microservices with Laravel Octane and Docker Swarm. Key considerations for production include implementing proper authentication and authorization for API access, setting up robust CI/CD pipelines for automated deployments, and continuously monitoring and tuning performance based on real-world traffic patterns. Further optimizations might involve exploring different Octane SAPI drivers (Swoole, RoadRunner, FrankenPHP) and advanced Swarm networking configurations.