Run multiple PHP versions of Applications in the docker

Step 1: Project Structure

Create a directory structure that separates each Laravel application:

laravel-docker/
│
├── app1/                     # Laravel App 1 using PHP 7.4
│   ├── laravel/              # Laravel application files
│
├── app2/                     # Laravel App 2 using PHP 8.0
│   ├── laravel/              # Laravel application files
│
├── app3/                     # Laravel App 3 using PHP 8.1
│   ├── laravel/              # Laravel application files
│
├── docker/
│   ├── php7.4/               # PHP 7.4 Docker configuration
│   │   └── Dockerfile
│   │
│   ├── php8.0/               # PHP 8.0 Docker configuration
│   │   └── Dockerfile
│   │
│   ├── php8.1/               # PHP 8.1 Docker configuration
│   │   └── Dockerfile
│
└── docker-compose.yml        # Docker Compose configuration file

Step 2: Install Nginx on Your Host Machine

Install Nginx on your local machine using the appropriate command based on your operating system:

  • Ubuntu/Debian: sudo apt update sudo apt install nginx
  • CentOS/RHEL: sudo yum install epel-release sudo yum install nginx
  • MacOS (Homebrew): brew install nginx

Step 3: Configure Nginx

Edit the Nginx configuration file to connect with PHP running inside Docker containers. Create a server block in Nginx to point to the Dockerized PHP service.

Nginx Configuration (/etc/nginx/sites-available/laravel):

# Configuration for App 1 using PHP 7.4
server {
    listen 80;
    server_name app1.localhost;
    root /path/to/app1/laravel/public;

    index index.php index.html index.htm;

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

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9001;  # PHP 7.4
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.ht {
        deny all;
    }
}

# Configuration for App 2 using PHP 8.0
server {
    listen 80;
    server_name app2.localhost;
    root /path/to/app2/laravel/public;

    index index.php index.html index.htm;

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

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9002;  # PHP 8.0
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.ht {
        deny all;
    }
}

# Configuration for App 3 using PHP 8.1
server {
    listen 80;
    server_name app3.localhost;
    root /path/to/app3/laravel/public;

    index index.php index.html index.htm;

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

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9003;  # PHP 8.1
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.ht {
        deny all;
    }
}

Enable the configuration:

sudo ln -s /etc/nginx/sites-available/laravel /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

Step 4: Create a Separate Docker Compose File for MySQL

Create a docker-compose.db.yml file dedicated to MySQL.

docker-compose.db.yml (For MySQL Service)

version: '3.8'

services:
  # MySQL Service (shared by all apps)
  mysql:
    image: mysql:5.7
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: laravel
      MYSQL_USER: laravel
      MYSQL_PASSWORD: secret
    volumes:
      - db_data:/var/lib/mysql
    ports:
      - "3306:3306" # Expose MySQL port for connections from apps

volumes:
  db_data:

Step 5: Configure Individual Docker Compose Files for Each App

Modify the docker-compose files for each application to remove the MySQL service and connect them to the shared MySQL container.

docker-compose.app1.yml (For App 1 – PHP 7.4)

version: '3.8'

services:
  # PHP 7.4 Service for App 1
  php7.4:
    build:
      context: ./docker/php7.4
    container_name: php7.4
    volumes:
      - ./app1/laravel:/var/www/html
    ports:
      - "9001:9000" # Mapping port for PHP 7.4
    depends_on:
      - mysql # Ensure the PHP service waits for MySQL to be ready
    networks:
      - shared-network

networks:
  shared-network:
    external: true

docker-compose.app2.yml (For App 2 – PHP 8.0)

version: '3.8'

services:
  # PHP 8.0 Service for App 2
  php8.0:
    build:
      context: ./docker/php8.0
    container_name: php8.0
    volumes:
      - ./app2/laravel:/var/www/html
    ports:
      - "9002:9000" # Mapping port for PHP 8.0
    depends_on:
      - mysql # Ensure the PHP service waits for MySQL to be ready
    networks:
      - shared-network

networks:
  shared-network:
    external: true

docker-compose.app3.yml (For App 3 – PHP 8.1)

version: '3.8'

services:
  # PHP 8.1 Service for App 3
  php8.1:
    build:
      context: ./docker/php8.1
    container_name: php8.1
    volumes:
      - ./app3/laravel:/var/www/html
    ports:
      - "9003:9000" # Mapping port for PHP 8.1
    depends_on:
      - mysql # Ensure the PHP service waits for MySQL to be ready
    networks:
      - shared-network

networks:
  shared-network:
    external: true

Step 6: Create the Shared Network

To allow the services in different Docker Compose files to communicate, create an external Docker network named shared-network. This network will connect the MySQL container with the PHP containers across different Compose files.

Create the shared network using the following command:

docker network create shared-network

Step 7: Update Laravel Environment Configuration

In each Laravel application’s .env file, configure the database connection to use the shared MySQL service. Set the DB_HOST to mysql (the name of the MySQL service as defined in docker-compose.db.yml).

Example .env Configuration for Each App:

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=secret

Step 8: Start the MySQL Container

First, bring up the MySQL service using its separate Docker Compose file:

docker-compose -f docker-compose.db.yml up -d

Step 9: Start Each Application

Start each Laravel application using its respective Docker Compose file:

  1. Start App 1 (PHP 7.4):docker-compose -f docker-compose.app1.yml up -d
  2. Start App 2 (PHP 8.0):docker-compose -f docker-compose.app2.yml up -d
  3. Start App 3 (PHP 8.1):docker-compose -f docker-compose.app3.yml up -d

Access Your Applications

Summary

This setup effectively decouples the MySQL service into a separate container while allowing multiple Laravel applications to connect seamlessly. It simplifies database management and provides a scalable architecture where you can adjust each Laravel environment independently without affecting the shared database service. Let me know if you need further adjustments or assistance!

Leave a Comment

Your email address will not be published. Required fields are marked *