Containerisation (Docker for PHP)
debt(d5/e5/b7/t5)
Closest to 'specialist tool catches' (d5). The term's detection_hints.tools lists docker, hadolint, and trivy — these are specialist DevOps tools that can catch issues like single-stage Dockerfiles, missing multi-stage builds, and security vulnerabilities in images. These aren't default linters but require deliberate adoption.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes writing a multi-stage Dockerfile, which is more than a one-line patch. Fixing common_mistakes like removing baked secrets, adding proper volume mounts, and refactoring away from root user requires changes to Dockerfile, docker-compose, CI/CD configs, and potentially application code for secret handling.
Closest to 'strong gravitational pull' (b7). Per applies_to, containerisation affects all PHP contexts (web, cli, queue-worker). Once adopted, every developer must understand Docker workflows, all deployments flow through container builds, local development depends on container parity, and CI/CD pipelines are shaped by image building. It's a load-bearing infrastructure choice that influences how the entire team works, though it doesn't quite reach b9 'defines system shape' since the PHP code itself remains portable.
Closest to 'notable trap' (t5). The misconception field explicitly states that developers wrongly believe containers provide VM-level isolation when they actually share the host kernel. This is a documented gotcha that most developers eventually learn but can lead to serious security oversights initially. The common_mistakes reinforce this — running as root, storing data inside containers, using :latest tags are all traps that stem from misunderstanding container ephemerality and isolation boundaries.
Also Known As
TL;DR
Explanation
Docker containers bundle PHP, extensions, nginx/FPM configuration, and application code into an immutable image. Benefits: environment parity (eliminates 'works on my machine'), fast deployment, horizontal scaling, and isolation. A PHP production Dockerfile typically: starts from php:8.3-fpm-alpine, installs required extensions with docker-php-ext-install, copies Composer dependencies, and sets non-root user. Multi-stage builds separate build dependencies from runtime — keeping production images lean. Docker Compose orchestrates local development with PHP-FPM, nginx, MySQL, and Redis containers. For production, containers run on Kubernetes, ECS, or similar orchestrators.
Diagram
flowchart TD
subgraph Host OS
KERN[Linux Kernel]
subgraph Container A
PHPFPM[PHP-FPM]
APP[App Code]
end
subgraph Container B
NGINX[nginx]
end
subgraph Container C
MYSQL[MySQL]
end
end
NGINX -->|FastCGI| PHPFPM
PHPFPM --> MYSQL
KERN -.->|namespaces + cgroups| PHPFPM & NGINX & MYSQL
style KERN fill:#6e40c9,color:#fff
style PHPFPM fill:#238636,color:#fff
style NGINX fill:#1f6feb,color:#fff
style MYSQL fill:#d29922,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Running containers as root inside the container — any container escape gives the attacker root on the host.
- Storing persistent data inside the container — it disappears when the container restarts.
- Using latest as the image tag in production — you lose control of which version is deployed.
- Baking secrets into the image — they are visible to anyone who can pull the image.
Code Examples
// Dockerfile anti-patterns:
FROM ubuntu:latest # Unpinned — breaks on new release
RUN apt-get install -y php # No version pin
COPY . /app # Copies .git, node_modules, .env
RUN composer install # Dev dependencies included
USER root # Running as root — security risk
// Better:
FROM php:8.3-fpm-alpine
COPY --chown=www-data:www-data . /app
RUN composer install --no-dev --optimize-autoloader
USER www-data
# Dockerfile — production PHP-FPM image
FROM php:8.3-fpm-alpine AS base
RUN docker-php-ext-install pdo_mysql opcache
COPY php.ini /usr/local/etc/php/conf.d/app.ini
FROM base AS vendor
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --prefer-dist
FROM base AS production
COPY --from=vendor /app/vendor ./vendor
COPY . .
RUN php artisan config:cache && php artisan route:cache
USER www-data