Containerization is a lightweight, portable, and self-sufficient method of packaging an application and its dependencies into a single unit called a container. Docker is the most popular platform for containerization, allowing developers to build, ship, and run any application anywhere.
Why Containerization for PHP?
1. Environment Consistency: Ensures that your development, testing, and production environments are identical, eliminating "it works on my machine" problems. You define your PHP version, extensions, web server (Nginx/Apache), and database (MySQL/PostgreSQL) once, and everyone uses the same setup.
2. Isolation: Each application (or even microservice within an application) runs in its own isolated container, preventing conflicts between dependencies. For example, you can easily run projects requiring PHP 7.4 and PHP 8.2 side-by-side without interference.
3. Portability: Containers encapsulate everything needed to run the application, making it easy to move between different host systems (e.g., from a developer's laptop to a cloud server) without worrying about underlying system configurations.
4. Simplified Development Workflow: Onboarding new team members becomes trivial; they just need Docker installed and can spin up the entire development environment with a single command (`docker-compose up`).
5. Scalability: Docker containers are easy to replicate, making it straightforward to scale your PHP application horizontally by running multiple instances of your web and application containers.
6. Dependency Management: Easily manage external services like databases, caching systems (Redis, Memcached), message queues (RabbitMQ), etc., by running them as separate containers orchestrated by Docker Compose.
Key Docker Components for PHP Applications:
* Dockerfile: A text file that contains all the commands a user could call on the command line to assemble an image. For PHP, this typically involves specifying a base PHP image (e.g., `php:8.2-fpm-alpine`), installing necessary PHP extensions, and copying your application code.
* Image: A read-only template with instructions for creating a Docker container. Based on a Dockerfile.
* Container: A runnable instance of a Docker image. What actually runs your PHP application and services.
* Docker Compose: A tool for defining and running multi-container Docker applications. With a `docker-compose.yml` file, you can configure all your services (e.g., Nginx, PHP-FPM, MySQL) and their interconnections, then launch them all with a single command.
Common PHP Docker Setup:
A typical Dockerized PHP application involves at least three services:
1. Web Server (Nginx or Apache): Listens for incoming HTTP requests and forwards PHP requests to the PHP-FPM service.
2. PHP-FPM (FastCGI Process Manager): A dedicated process that executes PHP scripts. The web server communicates with PHP-FPM via FastCGI protocol.
3. Database (MySQL, PostgreSQL, etc.): Stores application data. The PHP-FPM container connects to this database container.
Example Code
// To set up this example, create the following file structure:
// my-php-app/
// ├── docker-compose.yml
// ├── Dockerfile
// ├── nginx/
// │ └── default.conf
// └── src/
// └── index.php
// --- File: docker-compose.yml ---
// This file defines the services for your multi-container PHP application.
version: '3.8'
services:
web:
image: nginx:alpine # Use a lightweight Nginx image
ports:
- "80:80" # Map host port 80 to container port 80
volumes:
- ./src:/var/www/html # Mount your application code into Nginx's document root
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf # Mount custom Nginx config
depends_on:
- app # Ensure the 'app' service starts before 'web'
app:
build:
context: . # Look for Dockerfile in the current directory
dockerfile: Dockerfile
volumes:
- ./src:/var/www/html # Mount your application code into PHP-FPM's working directory
environment:
# Environment variables for PHP application to connect to the database
DATABASE_HOST: db
DATABASE_USER: user
DATABASE_PASSWORD: password
DATABASE_NAME: my_database
db:
image: mysql:8.0 # Use MySQL 8.0 image
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: my_database
MYSQL_USER: user
MYSQL_PASSWORD: password
volumes:
- db_data:/var/lib/mysql # Persist database data in a named volume
volumes:
db_data: # Define the named volume for database persistence
# --- File: Dockerfile ---
# This Dockerfile builds the PHP-FPM application image.
FROM php:8.2-fpm-alpine # Start with a lightweight PHP-FPM base image (PHP 8.2)
# Install system dependencies and PHP extensions
RUN apk add --no-cache \
nginx \ # Nginx is not strictly needed here if we use a separate Nginx container, but can be useful for debugging or single-container apps
mysql-client \ # For connecting to MySQL from the PHP container
git \
build-base \
autoconf \
libtool \
&& docker-php-ext-install pdo_mysql opcache \ # Install PDO MySQL and Opcache extensions
&& docker-php-ext-enable opcache # Enable Opcache
# Set the working directory inside the container
WORKDIR /var/www/html
# Copy application code from 'src/' directory to the container's working directory
# NOTE: In docker-compose, we use a volume mount for development, so this COPY might be skipped in some workflows
# For production images, you would copy the code here.
# COPY src/ .
# Expose port 9000 for PHP-FPM (the Nginx container will connect to this port)
EXPOSE 9000
# Command to run PHP-FPM when the container starts
CMD ["php-fpm"]
# --- File: nginx/default.conf ---
# Nginx configuration to proxy PHP requests to PHP-FPM.
server {
listen 80;
index index.php index.html;
root /var/www/html; # Nginx serves files from this directory
# Try to serve files directly, otherwise pass to index.php
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Pass PHP scripts to PHP-FPM
location ~ \.php$ {
try_files $uri =404; # Return 404 if PHP file not found
fastcgi_split_path_info ^(.+\.php)(/.+)$; # Split URI into script name and path info
fastcgi_pass app:9000; # Forward requests to the 'app' service (PHP-FPM) on port 9000
fastcgi_index index.php;
include fastcgi_params; # Include standard FastCGI parameters
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
# --- File: src/index.php ---
<?php
// Simple PHP application to demonstrate containerization
echo "<h1>Hello from a Dockerized PHP Application!</h1>";
echo "<p>This page is served by Nginx and processed by PHP-FPM running inside Docker containers.</p>";
// Optional: Try to connect to the database
$host = getenv('DATABASE_HOST') ?: 'db';
$user = getenv('DATABASE_USER') ?: 'user';
$password = getenv('DATABASE_PASSWORD') ?: 'password';
$dbname = getenv('DATABASE_NAME') ?: 'my_database';
try {
$dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "<p style='color: green;'>Successfully connected to the database!</p>";
// Example: Create a simple table and insert data if not exists
$pdo->exec("CREATE TABLE IF NOT EXISTS messages (id INT AUTO_INCREMENT PRIMARY KEY, message VARCHAR(255))");
$stmt = $pdo->prepare("SELECT COUNT(*) FROM messages WHERE message = ?");
$stmt->execute(['Hello Docker!']);
if ($stmt->fetchColumn() == 0) {
$pdo->exec("INSERT INTO messages (message) VALUES ('Hello Docker!')");
echo "<p>Inserted 'Hello Docker!' into messages table.</p>";
}
// Retrieve and display messages
$stmt = $pdo->query("SELECT message FROM messages");
echo "<h2>Messages from DB:</h2><ul>";
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "<li>" . htmlspecialchars($row['message']) . "</li>";
}
echo "</ul>";
} catch (PDOException $e) {
echo "<p style='color: red;'>Could not connect to the database: " . htmlspecialchars($e->getMessage()) . "</p>";
echo "<p>Please ensure the 'db' service is running correctly and credentials are correct.</p>";
}
echo "<h2>PHP Info:</h2>";
phpinfo();
?>
// To run this example:
// 1. Save the files as described above.
// 2. Navigate to the 'my-php-app' directory in your terminal.
// 3. Run: `docker-compose up --build -d`
// 4. Open your browser and go to `http://localhost`
// 5. To stop and remove containers, networks, and volumes: `docker-compose down -v`








Containerization with Docker and PHP