Containerizing Laravel with Docker and orchestrating with Kubernetes gives you consistent environments, easy scaling, and reliable deployments. This is the exact setup I've used in production for European-standard payroll and SaaS applications.

Laravel Dockerfile

A multi-stage Dockerfile keeps the final image lean:

dockerfile
FROM php:8.2-fpm-alpine AS base

RUN apk add --no-cache git curl libpng-dev oniguruma-dev libxml2-dev zip unzip
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

WORKDIR /var/www
COPY . .

RUN composer install --no-dev --optimize-autoloader
RUN chown -R www-data:www-data /var/www

EXPOSE 9000
CMD ["php-fpm"]

Docker Compose for Local Development

yaml
version: '3.8'

services:
  app:
    build: .
    container_name: laravel_app
    volumes:
      - .:/var/www
    networks:
      - laravel

  nginx:
    image: nginx:alpine
    container_name: laravel_nginx
    ports:
      - "8000:80"
    volumes:
      - .:/var/www
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    networks:
      - laravel

  mysql:
    image: mysql:8.0
    container_name: laravel_mysql
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: password
    ports:
      - "3306:3306"
    networks:
      - laravel

networks:
  laravel:
    driver: bridge

Kubernetes Deployment

Deployment Config

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: laravel-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: laravel-app
  template:
    metadata:
      labels:
        app: laravel-app
    spec:
      containers:
      - name: laravel-app
        image: your-registry/laravel-app:latest
        ports:
        - containerPort: 9000
        env:
        - name: DB_HOST
          value: "mysql-service"
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"

Service Config

yaml
apiVersion: v1
kind: Service
metadata:
  name: laravel-service
spec:
  selector:
    app: laravel-app
  ports:
  - port: 80
    targetPort: 9000
  type: LoadBalancer

CI/CD with GitHub Actions

blade
name: Deploy to Kubernetes
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Build Docker image
      run: docker build -t laravel-app:${{ github.sha }} .

    - name: Push to registry
      run: |
        docker tag laravel-app:${{ github.sha }} your-registry/laravel-app:${{ github.sha }}
        docker push your-registry/laravel-app:${{ github.sha }}

    - name: Deploy to Kubernetes
      run: kubectl set image deployment/laravel-app laravel-app=your-registry/laravel-app:${{ github.sha }}

Horizontal Pod Autoscaling

yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: laravel-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: laravel-app
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 80

Production tip: Always use specific image tags (like the git SHA) instead of latest . It makes rollbacks trivial and deployments fully reproducible.

Conclusion

Start with Docker Compose for local development to ensure environment consistency across your team. When you're ready for production, Kubernetes gives you autoscaling, zero-downtime deployments, and easy rollbacks. The GitHub Actions pipeline automates the whole process on every push to main.

Author bio block:

About the Author

Kamruzzaman Polash — Software Engineer specialising in Laravel, REST APIs, and scalable backend systems. 10+ projects delivered for clients worldwide.

Portfolio Contact GitHub LinkedIn

Work with me

Need help with your Laravel architecture?

I build clean, maintainable Laravel backends for SaaS products — REST APIs, queue systems and production patterns like the one in this article.