2026-09-03 17:45:35 +01:00
|
|
|
# syntax=docker/dockerfile:1
|
|
|
|
|
|
2026-09-04 13:37:07 +01:00
|
|
|
# --- Stage 1: build the Vue frontend ---------------------------------------
|
|
|
|
|
FROM node:24-alpine AS frontend
|
|
|
|
|
|
|
|
|
|
WORKDIR /web
|
|
|
|
|
|
|
|
|
|
# Dependencies in their own layer, cached unless the manifests change. npm ci
|
2026-09-06 17:25:16 +01:00
|
|
|
# resolves this stage's (musl) platform binaries for rollup/esbuild. The cache
|
|
|
|
|
# mount keeps the npm download cache warm across builds, so a lockfile bump
|
|
|
|
|
# only re-fetches what actually changed.
|
2026-09-04 13:37:07 +01:00
|
|
|
COPY web/package.json web/package-lock.json ./
|
2026-09-06 17:25:16 +01:00
|
|
|
RUN --mount=type=cache,target=/root/.npm npm ci
|
2026-09-04 13:37:07 +01:00
|
|
|
|
|
|
|
|
COPY web/ ./
|
|
|
|
|
RUN npm run build # vue-tsc type-check, then `vite build` -> /web/dist
|
|
|
|
|
|
2026-09-05 02:15:39 +01:00
|
|
|
# --- Stage 2: PHP + Apache runtime, on Alpine -------------------------------
|
|
|
|
|
FROM alpine:3.24
|
2026-09-03 17:45:35 +01:00
|
|
|
|
2026-09-05 02:15:39 +01:00
|
|
|
# apk's php83 packages are prebuilt (no compiling PHP from source, unlike the
|
|
|
|
|
# official Debian php:8.3-apache image), and split finely enough to pull in
|
|
|
|
|
# only what this app actually uses. php83-apache2 is Alpine's mod_php SAPI
|
|
|
|
|
# module -- the same role as php:8.3-apache's --with-apxs2 build. This alone
|
|
|
|
|
# takes the final image from ~735MB to ~90MB.
|
|
|
|
|
RUN apk add --no-cache \
|
|
|
|
|
apache2 \
|
2026-09-03 17:45:35 +01:00
|
|
|
curl \
|
2026-09-05 02:15:39 +01:00
|
|
|
php83 \
|
|
|
|
|
php83-apache2 \
|
|
|
|
|
php83-ctype \
|
|
|
|
|
php83-curl \
|
|
|
|
|
php83-fileinfo \
|
|
|
|
|
php83-iconv \
|
|
|
|
|
php83-mbstring \
|
|
|
|
|
php83-opcache \
|
|
|
|
|
php83-openssl \
|
|
|
|
|
php83-pdo \
|
|
|
|
|
php83-pdo_sqlite \
|
|
|
|
|
php83-phar \
|
|
|
|
|
php83-session \
|
|
|
|
|
php83-tokenizer \
|
|
|
|
|
su-exec \
|
|
|
|
|
# apk doesn't symlink an unversioned `php` -- composer's own wrapper
|
|
|
|
|
# script (copied in below) and bin/migrate.php's shebang both expect one.
|
|
|
|
|
&& ln -s /usr/bin/php83 /usr/local/bin/php
|
2026-09-03 17:45:35 +01:00
|
|
|
|
|
|
|
|
# --- Composer ----------------------------------------------------------------
|
2026-09-05 02:15:39 +01:00
|
|
|
# Borrowed from the official composer image rather than apk's own `composer`
|
|
|
|
|
# package, which drags in an entire second PHP interpreter (php85) as a
|
|
|
|
|
# dependency just to run the phar -- multi-stage COPY takes only the binary.
|
2026-09-03 17:45:35 +01:00
|
|
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
|
|
|
|
|
|
|
|
|
# --- Apache: document root -> public/, allow .htaccess rewrites -------------
|
2026-09-05 02:15:39 +01:00
|
|
|
COPY docker/apache.conf /etc/apache2/conf.d/zz-app.conf
|
|
|
|
|
|
|
|
|
|
# --- Entrypoint: migrate, then hand off to Apache ---------------------------
|
|
|
|
|
# Copied early, alongside the other rarely-changing setup above -- after
|
|
|
|
|
# COPY . . (below) every later layer re-runs on nearly every build, so this
|
|
|
|
|
# would otherwise redo work for a file that essentially never changes.
|
2026-09-06 17:25:16 +01:00
|
|
|
COPY --chmod=0755 docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
2026-09-03 17:45:35 +01:00
|
|
|
|
|
|
|
|
WORKDIR /var/www/html
|
|
|
|
|
|
|
|
|
|
# --- PHP dependencies (own layer, cached unless composer.* changes) --------
|
2026-09-06 17:25:16 +01:00
|
|
|
# The cache mount keeps Composer's package cache warm across builds, so a
|
|
|
|
|
# composer.lock bump only re-fetches the packages that changed.
|
2026-09-03 17:45:35 +01:00
|
|
|
COPY composer.json composer.lock ./
|
2026-09-06 17:25:16 +01:00
|
|
|
RUN --mount=type=cache,target=/tmp/composer-cache \
|
|
|
|
|
COMPOSER_CACHE_DIR=/tmp/composer-cache \
|
|
|
|
|
composer install --no-dev --no-interaction --no-progress --prefer-dist --no-autoloader
|
2026-09-03 17:45:35 +01:00
|
|
|
|
|
|
|
|
# --- Application source ----------------------------------------------------
|
|
|
|
|
COPY . .
|
|
|
|
|
RUN composer dump-autoload --optimize --no-dev \
|
|
|
|
|
&& mkdir -p storage \
|
2026-09-05 02:15:39 +01:00
|
|
|
&& chown -R apache:apache storage
|
2026-09-03 17:45:35 +01:00
|
|
|
|
2026-09-04 13:37:07 +01:00
|
|
|
# --- Built frontend: served from the web root next to the API front controller
|
|
|
|
|
COPY --from=frontend /web/dist/ ./public/
|
|
|
|
|
|
2026-09-03 17:45:35 +01:00
|
|
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
2026-09-05 02:15:39 +01:00
|
|
|
CMD ["httpd", "-D", "FOREGROUND"]
|
2026-09-03 17:45:35 +01:00
|
|
|
|
|
|
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
|
|
|
|
|
CMD curl -fsS http://localhost/api/health || exit 1
|