feat(docker): add multi-stage Dockerfile with PHP-FPM on Debian bookworm
This commit is contained in:
parent
862b9f6c16
commit
28b2c61e36
151
build/Dockerfile
151
build/Dockerfile
|
|
@ -1,44 +1,145 @@
|
|||
FROM php:8.4-fpm-alpine
|
||||
# =============================================================================
|
||||
# Stage 1: Build
|
||||
# Installs all PHP + Node dependencies and builds Vite assets.
|
||||
# This stage is NOT used in production — only its outputs are copied.
|
||||
# =============================================================================
|
||||
FROM php:8.4-cli-bookworm AS build
|
||||
|
||||
RUN apk add --no-cache \
|
||||
curl \
|
||||
# System deps for build stage
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
zip \
|
||||
unzip \
|
||||
zip \
|
||||
curl \
|
||||
libzip-dev \
|
||||
imagemagick \
|
||||
libreoffice \
|
||||
libreoffice-lang-de \
|
||||
libfreetype6-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libpng-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# PHP extensions needed for composer install / post-autoload-dump
|
||||
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install gd zip
|
||||
|
||||
# Install Node.js 20 LTS via NodeSource
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Composer
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# ── PHP dependency layer (cached until composer.lock changes) ────────────────
|
||||
COPY composer.json composer.lock ./
|
||||
RUN composer install \
|
||||
--no-dev \
|
||||
--optimize-autoloader \
|
||||
--no-scripts \
|
||||
--no-interaction \
|
||||
--prefer-dist
|
||||
|
||||
# ── Node dependency layer (cached until package-lock.json changes) ───────────
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci --ignore-scripts
|
||||
|
||||
# ── Full source + build ──────────────────────────────────────────────────────
|
||||
COPY . .
|
||||
|
||||
# Run composer post-autoload-dump scripts (package discovery etc.)
|
||||
RUN composer run-script post-autoload-dump --no-interaction || true
|
||||
|
||||
# Build Vite assets (outputs to public/build/)
|
||||
RUN npm run build
|
||||
|
||||
# Copy public/ → public-build/ so the production stage retains built assets
|
||||
# even after public/ becomes a runtime bind-mount target.
|
||||
RUN cp -r public/ public-build/
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Stage 2: Production
|
||||
# PHP-FPM runtime image with all system dependencies.
|
||||
# Node.js is NOT present here.
|
||||
# =============================================================================
|
||||
FROM php:8.4-fpm-bookworm AS production
|
||||
|
||||
# System packages (excluding Node.js — not needed at runtime)
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
supervisor \
|
||||
libzip-dev \
|
||||
libfreetype6-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libpng-dev \
|
||||
libsqlite3-dev \
|
||||
default-mysql-client \
|
||||
ghostscript \
|
||||
poppler-utils \
|
||||
sqlite \
|
||||
sqlite-dev \
|
||||
postgresql-client \
|
||||
mysql-client \
|
||||
nodejs \
|
||||
npm \
|
||||
fcgi
|
||||
sqlite3 \
|
||||
libfcgi-bin \
|
||||
unzip \
|
||||
zip \
|
||||
curl \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN docker-php-ext-install \
|
||||
# LibreOffice for PowerPoint → PDF conversion (large layer, separate cache)
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libreoffice-impress \
|
||||
libreoffice-l10n-de \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# PHP extensions
|
||||
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install \
|
||||
gd \
|
||||
pdo_sqlite \
|
||||
pdo_mysql \
|
||||
zip \
|
||||
bcmath
|
||||
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||
# Install Composer (needed for artisan commands, not for installing packages)
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY build/fpm-healthcheck.conf /usr/local/etc/php-fpm.d/zz-healthcheck.conf
|
||||
COPY build/php-error-logging.conf /usr/local/etc/php-fpm.d/zz-error-logging.conf
|
||||
COPY build/php-errors.ini /usr/local/etc/php/conf.d/errors.ini
|
||||
COPY build/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||
# ── Copy built application from build stage ──────────────────────────────────
|
||||
COPY --from=build /app /app
|
||||
|
||||
# Remove node_modules — not needed at runtime
|
||||
RUN rm -rf /app/node_modules
|
||||
|
||||
# ── Install Docker config files ──────────────────────────────────────────────
|
||||
# Supervisord (manages php-fpm, queue:work, schedule:work)
|
||||
COPY build/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
# PHP runtime config (upload limits, error logging, timezone)
|
||||
COPY build/php.ini /usr/local/etc/php/conf.d/zz-app.ini
|
||||
|
||||
# FPM pool config (replaces default www pool — sets ping endpoint, clear_env=no)
|
||||
COPY build/fpm-pool.conf /usr/local/etc/php-fpm.d/zz-www.conf
|
||||
|
||||
# FPM error logging to stderr
|
||||
COPY build/fpm-error-logging.conf /usr/local/etc/php-fpm.d/zz-error-logging.conf
|
||||
|
||||
# Remove default FPM pool config (replaced by our zz-www.conf above)
|
||||
RUN rm -f /usr/local/etc/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/www.conf.default
|
||||
|
||||
# ── Boot / Init scripts ───────────────────────────────────────────────────────
|
||||
RUN chmod +x /app/build/boot-container.sh /app/build/init-app.sh
|
||||
|
||||
# ── Runtime setup ─────────────────────────────────────────────────────────────
|
||||
EXPOSE 9000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000 | grep -q pong || exit 1
|
||||
# Healthcheck: FPM ping endpoint (starts checking after 60s to allow boot)
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET \
|
||||
cgi-fcgi -bind -connect 127.0.0.1:9000 2>/dev/null | grep -q "pong" || exit 1
|
||||
|
||||
ENTRYPOINT ["entrypoint.sh"]
|
||||
CMD ["php-fpm"]
|
||||
# boot-container.sh runs as root: creates dirs, sets permissions,
|
||||
# creates DB on first run, runs migrations, runs cache commands,
|
||||
# syncs built assets to the bind-mounted public/ directory,
|
||||
# then exec's supervisord (CMD).
|
||||
ENTRYPOINT ["/app/build/boot-container.sh"]
|
||||
CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
|
|
|
|||
Loading…
Reference in a new issue