acc-docker-multistage-knowledge
SKILL.md
Docker Multi-Stage Build Knowledge Base
Patterns and best practices for multi-stage Docker builds in PHP applications.
Multi-Stage Build Flow
┌─────────────────────────────────────────────────────────────────────────────┐
│ MULTI-STAGE BUILD PIPELINE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Stage 1: deps Stage 2: extensions Stage 3: build │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Composer │ │ PHP Ext │ │ App Build │ │
│ │ Install │ │ Compile │ │ Assets │ │
│ │ │ │ │ │ Optimize │ │
│ │ vendor/ │ │ *.so files │ │ Cache warm │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ │ COPY --from=deps │ COPY --from=extensions│ │
│ └────────────┐ ┌──────┘ ┌───────────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────┐ │
│ │ Stage 4: production │ │
│ │ ┌───────────────────┐ │ │
│ │ │ Minimal base │ │ │
│ │ │ + vendor/ │ │ │
│ │ │ + extensions │ │ │
│ │ │ + app code │ │ │
│ │ │ + optimized cfg │ │ │
│ │ └───────────────────┘ │ │
│ │ Final image: ~80MB │ │
│ └─────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Stage Naming Convention
| Stage Name | Purpose | Base Image |
|---|---|---|
deps |
Composer dependency installation | composer:2 |
extensions |
PHP extension compilation | php:8.4-fpm-alpine |
build |
Asset compilation, cache warmup | php:8.4-cli-alpine |
dev |
Development with Xdebug, tools | php:8.4-fpm-alpine |
production |
Final minimal runtime image | php:8.4-fpm-alpine |
Stage 1: Composer Dependencies
# syntax=docker/dockerfile:1
FROM composer:2 AS deps
WORKDIR /app
# Copy only dependency manifests first for layer caching
COPY composer.json composer.lock ./
# Install production deps only (no dev)
RUN composer install \
--no-dev \
--no-scripts \
--no-autoloader \
--prefer-dist \
--no-interaction
# Copy source and dump optimized autoloader
COPY src/ src/
COPY config/ config/
RUN composer dump-autoload --optimize --classmap-authoritative
Stage 2: PHP Extensions Builder
FROM php:8.4-fpm-alpine AS extensions
RUN apk add --no-cache --virtual .build-deps \
$PHPIZE_DEPS \
icu-dev \
libpq-dev \
libzip-dev \
freetype-dev \
libjpeg-turbo-dev \
libpng-dev \
&& docker-php-ext-configure gd \
--with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) \
intl \
pdo_pgsql \
zip \
gd \
opcache \
&& pecl install redis apcu \
&& docker-php-ext-enable redis apcu \
&& apk del .build-deps
Stage 3: Production Final
FROM php:8.4-fpm-alpine AS production
# Runtime-only dependencies (no build tools)
RUN apk add --no-cache \
icu-libs \
libpq \
libzip \
freetype \
libjpeg-turbo \
libpng
# Copy compiled extensions from builder stage
COPY /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
# Copy vendor directory from deps stage
COPY /app/vendor /app/vendor
# Copy application code
COPY . /app
WORKDIR /app
# PHP production configuration
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
USER www-data
EXPOSE 9000
CMD ["php-fpm"]
Cache Optimization Patterns
BuildKit Cache Mounts
# Cache composer packages across builds
RUN \
composer install --no-dev --optimize-autoloader
# Cache APK packages across builds
RUN \
apk add --no-cache icu-dev libpq-dev
Layer Ordering for Cache Hits
# Ordered from least to most frequently changed:
1. Base image + system packages (rarely changes)
2. PHP extensions (changes with requirements)
3. Composer dependencies (changes with composer.lock)
4. Application configuration (changes occasionally)
5. Application source code (changes frequently)
Cache From Pattern (CI/CD)
# Build with cache from registry
docker build \
--cache-from=registry.io/app:deps-cache \
--cache-from=registry.io/app:latest \
--target production \
-t registry.io/app:latest .
ARG Scoping Across Stages
# Global ARG (before first FROM) — available in FROM lines only
ARG PHP_VERSION=8.4
FROM php:${PHP_VERSION}-fpm-alpine AS base
# PHP_VERSION is NOT available here unless redeclared
ARG PHP_VERSION
RUN echo "Building with PHP ${PHP_VERSION}"
FROM php:${PHP_VERSION}-cli-alpine AS build
# Must redeclare ARG in each stage that needs it
ARG APP_ENV=prod
RUN echo "Building for ${APP_ENV}"
COPY --from Patterns
# Copy from named stage
COPY /app/vendor /app/vendor
# Copy from external image
COPY /usr/bin/composer /usr/local/bin/composer
# Copy specific extension files
COPY /usr/local/lib/php/extensions/no-debug-non-zts-*/ \
/usr/local/lib/php/extensions/no-debug-non-zts-*/
# Copy with ownership
COPY /app /app
Parallel Builds with BuildKit
# Enable BuildKit for parallel stage execution
DOCKER_BUILDKIT=1 docker build .
# Or via docker buildx
docker buildx build --target production .
BuildKit automatically detects independent stages and builds them in parallel:
deps ──────────────┐
├──▶ production
extensions ────────┘
│
build ──── (depends on deps, runs after)
Target Selection
# Build only development image
docker build --target dev -t app:dev .
# Build only production image
docker build --target production -t app:prod .
# Build specific intermediate stage for debugging
docker build --target extensions -t app:ext-debug .
Minimizing Final Image
| Technique | Savings | Example |
|---|---|---|
| Alpine base | ~80MB | php:8.4-fpm-alpine vs php:8.4-fpm |
| Multi-stage (no build tools) | ~200MB | Separate builder from runtime |
.dockerignore |
Variable | Exclude .git, tests/, docs/ |
| No dev dependencies | ~50MB | composer install --no-dev |
| Optimized autoloader | ~5MB | --classmap-authoritative |
| Removed package cache | ~10MB | apk add --no-cache or rm -rf /var/cache/apk/* |
References
For base image selection guidance, see acc-docker-base-images-knowledge.
For extension installation details, see acc-docker-php-extensions-knowledge.
Weekly Installs
1
Repository
dykyi-roman/awe…ude-codeGitHub Stars
39
First Seen
Feb 11, 2026
Security Audits
Installed on
opencode1
claude-code1