Builds met meerdere fasen en optimalisatie
Verklein images en scheid build van runtime.
Builds met meerdere fasen en optimalisatie is een gratis PHP Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject PHP Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus PHP Academy bevat in totaal 4 lessen.
Waarom meerdere fasen
Een image met één fase bevat Composer, bouwafhankelijkheden, ontwikkelheaders en je tests/-map in productie. Met builds met meerdere fasen kun je compileren en installeren in een omvangrijke bouwfase en alleen de voltooide artefacten naar een slanke runtimefase kopiëren.
Resultaat: kleinere images, een kleiner aanvalsoppervlak, sneller ophalen en geen compilers die naar productie worden meegeleverd.
Fasen benoemen
Elke FROM ... AS name start een nieuwe fase. Latere fasen kunnen met COPY --from=name bestanden uit eerdere fasen halen. Alleen de laatste fase wordt je image; tussenliggende fasen worden weggegooid (maar in de cache bewaard).
# Stage 1: dependencies
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --prefer-dist --ignore-platform-reqs
# Stage 2: runtime
FROM php:8.3-fpm-alpine AS runtime
WORKDIR /app
COPY --from=vendor /app/vendor ./vendor
COPY . .Bouwafhankelijkheden scheiden
Het compileren van extensies vereist autoconf, gcc en ontwikkelheaders — niets hiervan hoort in de runtime. Gebruik het installatieprogramma in een bouwfase en kopieer daarna de gecompileerde .so-bestanden en het bijbehorende ini-bestand van conf.d naar een schone runtimefase.
FROM php:8.3-fpm-alpine AS ext-builder
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions redis igbinary opcache intl
FROM php:8.3-fpm-alpine AS runtime
# Copy compiled extensions + their enable configs
COPY --from=ext-builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=ext-builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/Volgorde voor laagcaching
Docker cachet lagen van boven naar beneden en maakt alles onder een gewijzigde laag ongeldig. Orden ze van minst naar meest vaak veranderend:
- Basis + extensies (zelden)
composer.lock+ install (af en toe)- Broncode van de applicatie (bij elke commit)
- Automatisch laden (bij elke commit)
Dat betekent dat een wijziging die alleen de code betreft de volledige gecachte laag met afhankelijkheden hergebruikt.
# BAD: copying all source before composer install
# busts the vendor layer on every code change
COPY . .
RUN composer install
# GOOD: lock first, then source
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-autoloader
COPY . .
RUN composer dump-autoload --optimizeCachekoppelingen van BuildKit
Met BuildKit (DOCKER_BUILDKIT=1) kun je een permanente cache koppelen die tussen builds blijft bestaan zonder in de image terecht te komen. Ideaal voor de globale cache van Composer, zodat herhaalde builds pakketten niet opnieuw hoeven te downloaden.
# syntax=docker/dockerfile:1
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN --mount=type=cache,target=/tmp/composer-cache \
COMPOSER_CACHE_DIR=/tmp/composer-cache \
composer install --no-dev --prefer-distDe imagegrootte meten
Inspecteer de laagverdeling om opgeblazen onderdelen te vinden. docker history toont hoeveel grootte elke instructie heeft toegevoegd; hulpmiddelen zoals dive tonen verspilde ruimte. Het doel is een runtimefase zonder compilers, Composer of ontwikkelafhankelijkheden.
# Compare sizes
docker images myapp
# Per-layer contribution
docker history --no-trunc --format '{{.Size}}\t{{.CreatedBy}}' myapp:latest
# Deep inspection of wasted bytes
dive myapp:latestDe laatste fase opschonen
De runtimefase mag Composer, het extensie-installatiescript of je testsuite NIET bevatten. Kopieer vendor en broncode uit de bouwfasen; voer nooit composer uit in de laatste fase. Verwijder het installatieprogramma na gebruik als je het daar móét uitvoeren.
FROM php:8.3-fpm-alpine AS runtime
WORKDIR /app
# bring extensions + vendor in from builders — no Composer here
COPY --from=ext-builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=ext-builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
COPY --from=vendor /app/vendor ./vendor
COPY . .
USER www-data
CMD ["php-fpm"]Beperkingen van Distroless / Scratch
PHP kan niet op een werkelijk lege scratch draaien — het heeft libc en gedeelde bibliotheken nodig. De praktische ondergrens is alpine (musl) of een minimale Debian in distroless-stijl. Alpine is het kleinst, maar let op systeembibliotheken die glibc verwachten; als je segmentatiefouten met NSS/ICU tegenkomt, val je terug op php:8.3-fpm-bookworm.
# Smallest practical PHP runtime
FROM php:8.3-fpm-alpine
# If musl causes native-lib issues (e.g., some ICU edge cases),
# the glibc Debian slim variant is the safe fallback:
# FROM php:8.3-fpm-bookwormFasen als doel kiezen
Eén Dockerfile kan dev en productie bedienen via --target. Voeg bovenop runtime een dev-fase toe die Composer-ontwikkelafhankelijkheden en Xdebug opnieuw toevoegt; bouw --target=runtime voor productie en --target=dev lokaal.
FROM runtime AS dev
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions xdebug @composer
USER root
RUN composer install # includes dev deps
# Build prod: docker build --target runtime -t app:prod .
# Build dev: docker build --target dev -t app:dev .Redeneren over laaggroottes
Met een snel denkmodel kun je cachegedrag voorspellen. Dit CLI-fragment simuleert de klassieke fout van onbeperkte laaggroei tegenover begrensde groei en laat zien waarom het belangrijk is om opschonen te combineren in dezelfde RUN.
<?php
// Simulate layer sizes (MB) for two strategies
$installSteps = [120, 8, 8, 8];
// Separate RUN per step keeps temp files in layers
$separate = array_sum($installSteps);
// Single RUN with cleanup removes temp files before commit
$combined = max($installSteps); // peak, then cleaned
echo "Separate layers total: {$separate} MB\n";
echo "Combined+cleanup: {$combined} MB\n";
echo 'Saved: ' . ($separate - $combined) . " MB\n";
?>Combineren en opschonen in één RUN
Elke RUN is een laag; bestanden verwijderen in een latere laag maakt de image niet kleiner, omdat eerdere lagen de bytes nog steeds bevatten. Installeer, gebruik en ruim op binnen één RUN, zodat de tijdelijke bestanden nooit worden vastgelegd.
RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS && \
pecl install redis && \
docker-php-ext-enable redis && \
apk del .build-deps && \
rm -rf /tmp/pear /var/cache/apk/*Snelle controle
Waarom moeten bouwafhankelijkheden worden verwijderd in dezelfde RUN als waarin ze zijn geïnstalleerd?
Samenvatting
Builds met meerdere fasen houden compilers en ontwikkelafhankelijkheden buiten productie. Je hebt geleerd om: fasen te benoemen en artefacten te COPY --from; lagen van minst naar meest veranderlijk te ordenen voor caching; BuildKit-cachekoppelingen voor Composer te gebruiken; grootte te meten met docker history/dive; bewust te kiezen tussen alpine en glibc; dev- en productiefasen als doel te kiezen; en installatie en opschoning te combineren in één RUN.
Leer PHP met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 49
- Lessen
- 195
Veelgestelde vragen
Is de les “Builds met meerdere fasen en optimalisatie” gratis?
Ja — de volledige tekst van “Builds met meerdere fasen en optimalisatie” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus PHP Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus PHP Academy bevat in totaal 4 lessen.
Wat leer ik in “Builds met meerdere fasen en optimalisatie”?
Verklein images en scheid build van runtime. Je oefent met PHP Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met PHP Academy te beginnen?
Ervaring vooraf is niet nodig. PHP Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “Builds met meerdere fasen en optimalisatie”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over PHP Academy?
Ja. Elke les over PHP Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Een PHP-applicatie containeriseren
- Builds met meerdere fasen en optimalisatie
- Docker Compose voor lokale stacks
- CI/CD met GitHub Actions