# syntax=docker/dockerfile:1 ############################################################################### # Base # # Both stages share it, so dependencies are resolved against exactly the PHP # that will run them — Filament requires ext-intl, and a composer image that # lacks it would either refuse to install or, worse, install something the # runtime cannot use. ############################################################################### # PHP 8.4, not the 8.3 that composer.json's `^8.3` suggests: the lock file # resolved Symfony 8, which requires >=8.4.1. Building on 8.3 fails at # `composer install`, which is a much better place to find out than a deploy. FROM dunglas/frankenphp:1-php8.4 AS base WORKDIR /app # gd with WebP is not optional: it is what App\Services\Media\ImageProcessor # derives every responsive version with. exif is what stops a photo taken # sideways staying sideways. pcntl lets the queue worker shut down cleanly # instead of being killed mid-job. RUN install-php-extensions \ pdo_pgsql \ gd \ exif \ intl \ zip \ pcntl \ opcache \ && apt-get update \ && apt-get install -y --no-install-recommends postgresql-client \ && rm -rf /var/lib/apt/lists/* # In base rather than only in runtime, so the test stage runs under the same # PHP settings production does — a memory limit that is only set in production # is a memory limit nothing has tried. COPY docker/php.ini /usr/local/etc/php/conf.d/app.ini ############################################################################### # Dependencies ############################################################################### FROM base AS vendor COPY --from=composer:2 /usr/bin/composer /usr/bin/composer COPY composer.json composer.lock ./ # `--no-scripts` because the post-install hooks boot the application, and the # application cannot boot before its code is here. They are run explicitly in # the runtime stage instead, where everything exists. RUN composer install \ --no-dev \ --no-scripts \ --no-autoloader \ --prefer-dist \ --no-interaction COPY . . RUN composer dump-autoload --no-dev --optimize --classmap-authoritative ############################################################################### # Test # # The production image is built with --no-dev, which leaves out the test runner # itself. Verifying this application against Postgres therefore needs its own # stage — see docker-compose.test.yml, and the JSON-column queries it exists to # exercise. ############################################################################### FROM base AS test # Only the dev dependencies need this one, so production stays without it. RUN install-php-extensions bcmath COPY --from=composer:2 /usr/bin/composer /usr/bin/composer COPY composer.json composer.lock ./ RUN composer install --no-scripts --no-autoloader --prefer-dist --no-interaction COPY . . # An empty .env: the file is excluded from the build context on purpose, and # without it every single test emits a "failed to open stream" warning that # buries the real output. RUN touch .env \ && composer dump-autoload --optimize \ && php artisan package:discover --ansi ############################################################################### # Runtime ############################################################################### FROM base AS runtime LABEL org.opencontainers.image.title="Pireon Admin" \ org.opencontainers.image.description="Admin panel and REST API for the collective" COPY docker/Caddyfile /etc/caddy/Caddyfile COPY --from=vendor /app/vendor ./vendor COPY . . COPY docker/entrypoint.sh /usr/local/bin/entrypoint RUN chmod +x /usr/local/bin/entrypoint # Filament serves its own CSS and JS from public/; publishing them at build # time means the running container never writes to public/. # # There is deliberately no Node stage: the only `@vite` directive left is in # Laravel's default welcome page, which this application redirects away from. RUN php artisan package:discover --ansi \ && php artisan filament:assets RUN chown -R www-data:www-data storage bootstrap/cache ENV SERVER_NAME=:80 EXPOSE 80 ENTRYPOINT ["entrypoint"] CMD ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile"]