|
| 1 | +# ============================================================================= |
| 2 | +# TEAL Production Dockerfile |
| 3 | +# Multi-stage build: Node (frontend) → Composer (PHP deps) → FrankenPHP runtime |
| 4 | +# ============================================================================= |
| 5 | + |
| 6 | +# --------------------------------------------------------------------------- |
| 7 | +# Stage 1: Build frontend assets with Vite |
| 8 | +# --------------------------------------------------------------------------- |
| 9 | +FROM node:22-alpine AS node-builder |
| 10 | + |
| 11 | +WORKDIR /build |
| 12 | + |
| 13 | +# Copy dependency manifests first for layer caching |
| 14 | +COPY package.json package-lock.json ./ |
| 15 | +RUN npm ci --no-audit --no-fund \ |
| 16 | + && echo "[node-builder] npm dependencies installed" |
| 17 | + |
| 18 | +# Copy frontend source files needed for the build |
| 19 | +COPY vite.config.js tailwind.config.js postcss.config.js ./ |
| 20 | +COPY resources/ resources/ |
| 21 | + |
| 22 | +# Build production assets |
| 23 | +RUN npm run build \ |
| 24 | + && echo "[node-builder] Vite build complete" \ |
| 25 | + && ls -la public/build/ \ |
| 26 | + && echo "[node-builder] Manifest:" \ |
| 27 | + && cat public/build/manifest.json |
| 28 | + |
| 29 | +# --------------------------------------------------------------------------- |
| 30 | +# Stage 2: Install PHP dependencies with Composer |
| 31 | +# --------------------------------------------------------------------------- |
| 32 | +FROM composer:2 AS composer-builder |
| 33 | + |
| 34 | +WORKDIR /build |
| 35 | + |
| 36 | +# Copy dependency manifests |
| 37 | +COPY composer.json composer.lock ./ |
| 38 | + |
| 39 | +# Install production dependencies only (no scripts — avoids needing artisan) |
| 40 | +RUN composer install \ |
| 41 | + --no-dev \ |
| 42 | + --no-scripts \ |
| 43 | + --no-interaction \ |
| 44 | + --prefer-dist \ |
| 45 | + --optimize-autoloader \ |
| 46 | + && echo "[composer-builder] PHP dependencies installed" \ |
| 47 | + && echo "[composer-builder] Vendor size:" \ |
| 48 | + && du -sh vendor/ |
| 49 | + |
| 50 | +# --------------------------------------------------------------------------- |
| 51 | +# Stage 3: Production runtime image |
| 52 | +# --------------------------------------------------------------------------- |
| 53 | +FROM serversideup/php:8.4-frankenphp AS production |
| 54 | + |
| 55 | +LABEL maintainer="dotmavriq" \ |
| 56 | + app="TEAL" \ |
| 57 | + description="TEAL - Track Everything About Life" |
| 58 | + |
| 59 | +# ---- Install additional PHP extensions ---- |
| 60 | +# pgsql/pdo_pgsql: PostgreSQL |
| 61 | +# gd: Image processing (intervention/image) |
| 62 | +# intl: Unicode/i18n support |
| 63 | +# opcache: Production PHP performance |
| 64 | +# pcntl: Process control for Octane graceful shutdown |
| 65 | +# bcmath: Precision math (Laravel dependency) |
| 66 | +RUN install-php-extensions \ |
| 67 | + pdo_pgsql \ |
| 68 | + pgsql \ |
| 69 | + gd \ |
| 70 | + intl \ |
| 71 | + opcache \ |
| 72 | + pcntl \ |
| 73 | + bcmath \ |
| 74 | + && echo "[production] PHP extensions installed:" \ |
| 75 | + && php -m | sort |
| 76 | + |
| 77 | +# ---- Set environment defaults ---- |
| 78 | +ENV APP_ENV=production \ |
| 79 | + APP_DEBUG=false \ |
| 80 | + OCTANE_SERVER=frankenphp \ |
| 81 | + SERVER_NAME=":8080" \ |
| 82 | + LOG_CHANNEL=stderr \ |
| 83 | + LOG_LEVEL=warning \ |
| 84 | + AUTORUN_ENABLED=false |
| 85 | + |
| 86 | +# ---- Set working directory ---- |
| 87 | +WORKDIR /var/www/html |
| 88 | + |
| 89 | +# ---- Copy application source ---- |
| 90 | +COPY --chown=www-data:www-data . . |
| 91 | + |
| 92 | +# ---- Copy built vendor directory from composer stage ---- |
| 93 | +COPY --from=composer-builder --chown=www-data:www-data /build/vendor ./vendor |
| 94 | + |
| 95 | +# ---- Copy built frontend assets from node stage ---- |
| 96 | +COPY --from=node-builder --chown=www-data:www-data /build/public/build ./public/build |
| 97 | + |
| 98 | +# ---- Run composer post-install scripts (package discovery, etc.) ---- |
| 99 | +RUN composer dump-autoload --optimize --no-dev \ |
| 100 | + && echo "[production] Autoloader optimized" |
| 101 | + |
| 102 | +# ---- Ensure storage directories and permissions ---- |
| 103 | +RUN mkdir -p \ |
| 104 | + storage/app/public/covers \ |
| 105 | + storage/framework/cache/data \ |
| 106 | + storage/framework/sessions \ |
| 107 | + storage/framework/views \ |
| 108 | + storage/logs \ |
| 109 | + bootstrap/cache \ |
| 110 | + && chown -R www-data:www-data storage bootstrap/cache \ |
| 111 | + && chmod -R 775 storage bootstrap/cache \ |
| 112 | + && echo "[production] Storage directories created" |
| 113 | + |
| 114 | +# ---- Copy entrypoint scripts ---- |
| 115 | +COPY docker/entrypoint.sh /usr/local/bin/docker-entrypoint.sh |
| 116 | +COPY docker/queue-entrypoint.sh /usr/local/bin/docker-queue-entrypoint.sh |
| 117 | +RUN chmod +x /usr/local/bin/docker-entrypoint.sh /usr/local/bin/docker-queue-entrypoint.sh |
| 118 | + |
| 119 | +# ---- Healthcheck ---- |
| 120 | +HEALTHCHECK --interval=15s --timeout=5s --retries=3 --start-period=20s \ |
| 121 | + CMD php artisan octane:status --server=frankenphp || exit 1 |
| 122 | + |
| 123 | +EXPOSE 8080 |
| 124 | + |
| 125 | +ENTRYPOINT ["docker-entrypoint.sh"] |
0 commit comments