Setting up a local development environment can often feel like navigating a complex maze, especially when juggling multiple technologies. But fear not, because Docker Compose is here to simplify your life! This guide will walk you through creating a development environment using Docker Compose with PHP, Nginx, and MariaDB. This powerful combination allows you to build and test your PHP applications in a consistent and isolated environment, minimizing those dreaded "it works on my machine" moments. So, let's dive in and get our hands dirty with some code!

    Understanding Docker Compose

    Before we jump into the specifics, let's take a moment to understand what Docker Compose actually is. Simply put, Docker Compose is a tool for defining and running multi-container Docker applications. It uses a YAML file to configure your application's services, networks, and volumes. With a single command, you can create and start all the services defined in your Compose file. This streamlines the process of setting up complex development environments, making it easier to manage and share your projects.

    Why use Docker Compose? Imagine having to manually configure and start separate Docker containers for your PHP application, Nginx web server, and MariaDB database. That sounds like a headache, right? Docker Compose eliminates this hassle by allowing you to define all these services in a single file and manage them as a single unit. This not only simplifies the setup process but also ensures that all your services are properly linked and configured to work together seamlessly. Furthermore, using Docker Compose ensures consistency across different environments. Whether you're working on your local machine, in a staging environment, or in production, you can be confident that your application will behave the same way, reducing the risk of unexpected issues.

    Prerequisites

    Before we begin, make sure you have the following installed on your system:

    • Docker: The core containerization platform. You can download it from the official Docker website.
    • Docker Compose: Usually comes bundled with Docker Desktop. If not, you can install it separately following the instructions on the Docker website.

    It's also helpful to have a basic understanding of Docker concepts, such as images, containers, networks, and volumes. However, this guide will walk you through everything step-by-step, so don't worry if you're new to Docker. We're here to help you every step of the way!

    Creating the Docker Compose File

    The heart of our setup is the docker-compose.yml file. This file defines the services that make up our application, their configurations, and how they interact with each other. Create a new directory for your project and create a file named docker-compose.yml inside it. This file will contain all the instructions Docker Compose needs to build and run our environment.

    Here's an example docker-compose.yml file:

    version: "3.8"
    services:
      app:
        build:
          context: .
          dockerfile: Dockerfile
        image: my-php-app
        container_name: php-app
        volumes:
          - ./src:/var/www/html
        ports:
          - "8000:80"
        depends_on:
          - db
        environment:
          - DB_HOST=db
          - DB_DATABASE=mydatabase
          - DB_USERNAME=myuser
          - DB_PASSWORD=mypassword
    
      db:
        image: mariadb:10.6
        container_name: mariadb
        volumes:
          - db_data:/var/lib/mysql
        environment:
          - MYSQL_ROOT_PASSWORD=rootpassword
          - MYSQL_DATABASE=mydatabase
          - MYSQL_USER=myuser
          - MYSQL_PASSWORD=mypassword
        ports:
          - "3306:3306"
    
      nginx:
        image: nginx:alpine
        container_name: nginx
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./nginx/conf.d:/etc/nginx/conf.d
          - ./src:/var/www/html
        depends_on:
          - app
    
    volumes:
      db_data:
    

    Let's break down this file section by section:

    Version

    The version key specifies the version of the Docker Compose file format. Using the latest version is generally recommended.

    Services

    The services section defines the different services that make up our application. In this case, we have three services: app (PHP), db (MariaDB), and nginx (Nginx web server).

    App Service (PHP)

    • build: Specifies how to build the Docker image for the PHP application. The context specifies the directory containing the Dockerfile, and the dockerfile specifies the name of the Dockerfile.
    • image: The name of the image to be built.
    • container_name: The name of the container.
    • volumes: Maps the ./src directory on your host machine to the /var/www/html directory inside the container. This allows you to edit your PHP code on your host machine and have the changes reflected in the container in real-time.
    • ports: Maps port 8000 on your host machine to port 80 inside the container. This allows you to access your PHP application through your web browser at http://localhost:8000.
    • depends_on: Specifies that the app service depends on the db service. This ensures that the MariaDB container is started before the PHP container.
    • environment: Sets environment variables that will be available inside the PHP container. These variables are used to configure the database connection.

    DB Service (MariaDB)

    • image: Specifies the Docker image to use for the MariaDB database. In this case, we're using the mariadb:10.6 image from Docker Hub.
    • container_name: The name of the container.
    • volumes: Creates a named volume called db_data and mounts it to the /var/lib/mysql directory inside the container. This ensures that your database data is persisted even if the container is stopped or removed.
    • environment: Sets environment variables for the MariaDB database, such as the root password, database name, user name, and password.
    • ports: Maps port 3306 on your host machine to port 3306 inside the container. This allows you to connect to your MariaDB database from your host machine using a database client.

    Nginx Service

    • image: Specifies the Docker image to use for the Nginx web server. We're using the nginx:alpine image, which is a lightweight version of Nginx.
    • container_name: The name of the container.
    • ports: Maps port 80 and 443 on your host machine to ports 80 and 443 inside the container. This allows you to access your web application through your web browser at http://localhost or https://localhost.
    • volumes: Maps the ./nginx/conf.d directory on your host machine to the /etc/nginx/conf.d directory inside the container. This allows you to configure Nginx by placing your configuration files in the ./nginx/conf.d directory. It also maps the ./src directory to /var/www/html to serve your application files.
    • depends_on: Specifies that the nginx service depends on the app service. This ensures that the PHP container is started before the Nginx container.

    Volumes

    The volumes section defines the named volumes used by our services. In this case, we have one volume: db_data. Named volumes are a way to persist data across container restarts and upgrades. They are managed by Docker and are stored in a separate location on your host machine.

    Creating the Dockerfile

    The Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Create a file named Dockerfile in the same directory as your docker-compose.yml file.

    Here's an example Dockerfile for a PHP application:

    FROM php:8.1-fpm-alpine
    
    RUN apk update && apk add --no-cache \
        postgresql-dev \
        libzip-dev \
        icu-dev \
        oniguruma-dev
    
    RUN docker-php-ext-install -j$(nproc) \
        pdo pdo_pgsql zip intl mbstring  bcmath
    
    RUN pecl install xdebug \
        && docker-php-ext-enable xdebug
    
    WORKDIR /var/www/html
    
    COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
    
    COPY . .
    
    RUN composer install --no-ansi --no-dev --no-interaction --no-plugins --no-scripts --optimize-autoloader
    
    EXPOSE 9000
    
    CMD ["php-fpm"]
    

    Let's break down this Dockerfile section by section:

    • FROM: Specifies the base image to use for our PHP application. In this case, we're using the php:8.1-fpm-alpine image, which is a lightweight version of PHP 8.1 with the FPM (FastCGI Process Manager) server.
    • RUN: Executes commands inside the container. In this case, we're updating the package index and installing some necessary PHP extensions, such as pdo_pgsql for PostgreSQL support, zip for ZIP archive support, and intl for internationalization support.
    • WORKDIR: Sets the working directory inside the container to /var/www/html. This is where our PHP application code will be located.
    • COPY: Copies files from your host machine to the container. In this case, we're copying the composer.json and composer.lock files to the /var/www/html directory, and then running composer install to install the PHP dependencies.
    • EXPOSE: Exposes port 9000 on the container. This is the port that the PHP-FPM server will listen on.
    • CMD: Specifies the command to run when the container starts. In this case, we're starting the PHP-FPM server.

    Configuring Nginx

    Create a directory named nginx in your project root, and inside it, create a directory named conf.d. Inside the conf.d directory, create a file named default.conf. This file will contain the Nginx configuration for your application.

    Here's an example default.conf file:

    server {
        listen 80;
        index index.php index.html;
        server_name localhost;
        root /var/www/html/public;
    
        location / {
            try_files $uri $uri/ /index.php?$query_string;
        }
    
        location ~ \.php$ {
            fastcgi_pass app:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PHP_VALUE "error_reporting=E_ALL";
        }
    }
    

    This configuration file tells Nginx to listen on port 80, set the document root to /var/www/html/public, and forward PHP requests to the PHP-FPM server running in the app container. Make sure to adjust the root directive to point to the correct directory in your application.

    Running the Application

    Now that we have our docker-compose.yml file, Dockerfile, and Nginx configuration, we can start our application. Open a terminal in your project directory and run the following command:

    docker-compose up -d --build
    

    This command will build the Docker images, create the containers, and start the application in detached mode (in the background). The --build flag ensures that the Docker images are rebuilt if there are any changes to the Dockerfile or the docker-compose.yml file.

    Once the application is running, you can access it in your web browser at http://localhost. If you mapped port 8000, access it via http://localhost:8000.

    Stopping the Application

    To stop the application, run the following command in your project directory:

    docker-compose down
    

    This command will stop and remove the containers, networks, and volumes defined in the docker-compose.yml file. This is a clean way to shut down your development environment when you're finished working on it.

    Conclusion

    Congratulations! You've successfully set up a local development environment using Docker Compose with PHP, Nginx, and MariaDB. This setup allows you to build and test your PHP applications in a consistent and isolated environment, minimizing the risk of compatibility issues and making it easier to collaborate with other developers.

    By using Docker Compose, you've streamlined your development workflow and gained more control over your application's environment. This is a valuable skill for any modern developer, and it will save you countless hours of debugging and configuration in the long run. So keep practicing, keep experimenting, and keep building amazing things with Docker Compose!