1 - Add production Dockerfile
This commit is contained in:
parent
fa85decccb
commit
f0a8bdc1de
3 changed files with 179 additions and 3 deletions
49
.dockerignore
Normal file
49
.dockerignore
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Version control
|
||||
.git
|
||||
.gitignore
|
||||
.gitattributes
|
||||
|
||||
# Dev environment
|
||||
shell.nix
|
||||
Dockerfile.dev
|
||||
docker/
|
||||
|
||||
# Tests (not needed in prod image)
|
||||
tests/
|
||||
phpunit.xml
|
||||
.phpunit.result.cache
|
||||
phpstan.neon
|
||||
|
||||
# Dependencies (rebuilt during image build)
|
||||
node_modules/
|
||||
vendor/
|
||||
|
||||
# Build artifacts (frontend stage produces these)
|
||||
public/build/
|
||||
public/hot
|
||||
|
||||
# Editor / OS
|
||||
.editorconfig
|
||||
.idea/
|
||||
.vscode/
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Env / secrets
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Logs and runtime caches
|
||||
storage/logs/*.log
|
||||
storage/framework/cache/data/
|
||||
storage/framework/sessions/
|
||||
storage/framework/views/
|
||||
|
||||
# CI
|
||||
.forgejo/
|
||||
|
||||
# Docs / project meta
|
||||
README.md
|
||||
LICENSE
|
||||
|
|
@ -5,8 +5,7 @@ on:
|
|||
branches: [main]
|
||||
tags: ['v*']
|
||||
paths:
|
||||
- 'Dockerfile'
|
||||
- 'docker/**'
|
||||
- 'docker/prod/Dockerfile'
|
||||
- 'app/**'
|
||||
- 'bootstrap/**'
|
||||
- 'config/**'
|
||||
|
|
@ -51,6 +50,6 @@ jobs:
|
|||
uses: https://data.forgejo.org/docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
file: docker/prod/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
|
|
|
|||
128
docker/prod/Dockerfile
Normal file
128
docker/prod/Dockerfile
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# ============================================================
|
||||
# Stage 1: Build frontend assets
|
||||
# ============================================================
|
||||
FROM node:20-alpine AS frontend
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json package-lock.json vite.config.js ./
|
||||
COPY resources/ resources/
|
||||
|
||||
RUN npm ci --no-audit --no-fund
|
||||
RUN npm run build
|
||||
|
||||
# ============================================================
|
||||
# Stage 2: Runtime (FrankenPHP)
|
||||
# ============================================================
|
||||
FROM dunglas/frankenphp:1.1-php8.3-alpine AS runtime
|
||||
|
||||
RUN apk add --no-cache \
|
||||
git \
|
||||
postgresql-client \
|
||||
curl
|
||||
|
||||
RUN install-php-extensions \
|
||||
pdo_pgsql \
|
||||
redis \
|
||||
opcache \
|
||||
zip \
|
||||
gd \
|
||||
intl
|
||||
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV APP_ENV=production \
|
||||
APP_DEBUG=false \
|
||||
LOG_CHANNEL=stack \
|
||||
LOG_LEVEL=warning \
|
||||
DB_CONNECTION=pgsql \
|
||||
DB_HOST=db \
|
||||
DB_PORT=5432 \
|
||||
REDIS_HOST=redis \
|
||||
REDIS_PORT=6379 \
|
||||
CACHE_STORE=redis \
|
||||
QUEUE_CONNECTION=redis \
|
||||
SESSION_DRIVER=redis \
|
||||
BROADCAST_CONNECTION=log \
|
||||
MAIL_MAILER=log
|
||||
|
||||
# Copy only the files composer needs before install, so the composer layer stays
|
||||
# cached when application source changes. packages/ is required because composer.json
|
||||
# declares it as a path repository.
|
||||
COPY composer.json composer.lock ./
|
||||
COPY packages/ packages/
|
||||
|
||||
# Skip post-autoload scripts (package:discover) during build — they need a runtime
|
||||
# Laravel boot which fails without proper env. Discovery happens at runtime via
|
||||
# start-prod.sh. --classmap-authoritative implies --optimize-autoloader.
|
||||
RUN composer install --no-dev --no-interaction --prefer-dist --classmap-authoritative --no-scripts
|
||||
|
||||
COPY . .
|
||||
COPY --from=frontend /app/public/build /app/public/build
|
||||
|
||||
RUN chown -R www-data:www-data /app/storage /app/bootstrap/cache
|
||||
|
||||
RUN cat > /etc/caddy/Caddyfile <<'EOF'
|
||||
{
|
||||
frankenphp
|
||||
order php_server before file_server
|
||||
}
|
||||
|
||||
:8000 {
|
||||
root * /app/public
|
||||
|
||||
php_server {
|
||||
index index.php
|
||||
}
|
||||
|
||||
encode gzip zstd
|
||||
|
||||
file_server
|
||||
|
||||
header {
|
||||
X-Frame-Options "SAMEORIGIN"
|
||||
X-Content-Type-Options "nosniff"
|
||||
Referrer-Policy "strict-origin-when-cross-origin"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||
CMD curl -fsS http://localhost:8000/up || exit 1
|
||||
|
||||
RUN cat > /start-prod.sh <<'EOF'
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "Waiting for PostgreSQL at ${DB_HOST}:${DB_PORT}..."
|
||||
for i in $(seq 1 60); do
|
||||
if pg_isready -h "${DB_HOST}" -p "${DB_PORT}" -q; then
|
||||
echo "PostgreSQL is ready."
|
||||
break
|
||||
fi
|
||||
if [ "$i" = "60" ]; then
|
||||
echo "Timed out waiting for PostgreSQL after 60s." >&2
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
php artisan package:discover --ansi
|
||||
php artisan config:cache
|
||||
php artisan route:cache
|
||||
php artisan view:cache
|
||||
|
||||
php artisan migrate --force
|
||||
|
||||
exec frankenphp run --config /etc/caddy/Caddyfile
|
||||
EOF
|
||||
|
||||
RUN chmod +x /start-prod.sh
|
||||
|
||||
CMD ["/start-prod.sh"]
|
||||
Loading…
Reference in a new issue