add provisional docker files
This commit is contained in:
parent
daa2685ed9
commit
4e58f0b6a9
4 changed files with 467 additions and 0 deletions
122
Dockerfile
Normal file
122
Dockerfile
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
# Production Dockerfile with FrankenPHP
|
||||||
|
FROM dunglas/frankenphp:latest-php8.4-alpine
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
nodejs \
|
||||||
|
npm \
|
||||||
|
git \
|
||||||
|
mysql-client
|
||||||
|
|
||||||
|
# Install PHP extensions
|
||||||
|
RUN install-php-extensions \
|
||||||
|
pdo_mysql \
|
||||||
|
opcache \
|
||||||
|
zip \
|
||||||
|
gd \
|
||||||
|
intl
|
||||||
|
|
||||||
|
# Install Composer
|
||||||
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Set fixed production environment variables
|
||||||
|
ENV APP_ENV=production \
|
||||||
|
APP_DEBUG=false \
|
||||||
|
DB_CONNECTION=mysql \
|
||||||
|
DB_HOST=db \
|
||||||
|
DB_PORT=3306 \
|
||||||
|
SESSION_DRIVER=database \
|
||||||
|
CACHE_DRIVER=file \
|
||||||
|
QUEUE_CONNECTION=database \
|
||||||
|
LOG_CHANNEL=stack \
|
||||||
|
LOG_LEVEL=error \
|
||||||
|
MAIL_MAILER=smtp \
|
||||||
|
MAIL_ENCRYPTION=tls
|
||||||
|
|
||||||
|
# Copy application code first
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Install PHP dependencies (production only)
|
||||||
|
RUN composer install --no-dev --no-interaction --optimize-autoloader
|
||||||
|
|
||||||
|
# Install ALL Node dependencies (including dev for building)
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Build frontend assets
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Remove node_modules after build to save space
|
||||||
|
RUN rm -rf node_modules
|
||||||
|
|
||||||
|
# Laravel optimizations
|
||||||
|
RUN php artisan config:cache \
|
||||||
|
&& php artisan route:cache \
|
||||||
|
&& composer dump-autoload --optimize
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
RUN chown -R www-data:www-data /app/storage /app/bootstrap/cache
|
||||||
|
|
||||||
|
# Configure Caddy
|
||||||
|
RUN cat > /etc/caddy/Caddyfile <<EOF
|
||||||
|
{
|
||||||
|
frankenphp
|
||||||
|
order php_server before file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
:8000 {
|
||||||
|
root * /app/public
|
||||||
|
|
||||||
|
php_server {
|
||||||
|
index index.php
|
||||||
|
}
|
||||||
|
|
||||||
|
encode gzip
|
||||||
|
|
||||||
|
file_server
|
||||||
|
|
||||||
|
header {
|
||||||
|
X-Frame-Options "SAMEORIGIN"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-XSS-Protection "1; mode=block"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD curl -f http://localhost:8000/up || exit 1
|
||||||
|
|
||||||
|
# Create startup script for production
|
||||||
|
RUN cat > /start-prod.sh <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Wait for database to be ready
|
||||||
|
echo "Waiting for database..."
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if php artisan db:monitor --database=mysql 2>/dev/null | grep -q "OK"; then
|
||||||
|
echo "Database is ready!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "Waiting for database... ($i/30)"
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
# Run migrations
|
||||||
|
echo "Running migrations..."
|
||||||
|
php artisan migrate --force || echo "Migrations failed or already up-to-date"
|
||||||
|
|
||||||
|
# Start FrankenPHP
|
||||||
|
exec frankenphp run --config /etc/caddy/Caddyfile
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUN chmod +x /start-prod.sh
|
||||||
|
|
||||||
|
# Start with our script
|
||||||
|
CMD ["/start-prod.sh"]
|
||||||
127
Dockerfile.dev
Normal file
127
Dockerfile.dev
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
# Development Dockerfile with FrankenPHP
|
||||||
|
FROM dunglas/frankenphp:latest-php8.4-alpine
|
||||||
|
|
||||||
|
# Install system dependencies + development tools
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
nodejs \
|
||||||
|
npm \
|
||||||
|
git \
|
||||||
|
mysql-client \
|
||||||
|
vim \
|
||||||
|
bash \
|
||||||
|
nano
|
||||||
|
|
||||||
|
# Install PHP extensions including xdebug for development
|
||||||
|
RUN install-php-extensions \
|
||||||
|
pdo_mysql \
|
||||||
|
opcache \
|
||||||
|
zip \
|
||||||
|
gd \
|
||||||
|
intl \
|
||||||
|
xdebug
|
||||||
|
|
||||||
|
# Install Composer
|
||||||
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Configure PHP for development
|
||||||
|
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
|
||||||
|
|
||||||
|
# Configure Xdebug (disabled by default to reduce noise)
|
||||||
|
RUN echo "xdebug.mode=off" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
|
||||||
|
&& echo ";xdebug.mode=debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
|
||||||
|
&& echo ";xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
|
||||||
|
&& echo ";xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||||
|
|
||||||
|
# Configure Caddy for development (simpler, no worker mode)
|
||||||
|
RUN cat > /etc/caddy/Caddyfile <<EOF
|
||||||
|
{
|
||||||
|
frankenphp
|
||||||
|
order php_server before file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
:8000 {
|
||||||
|
root * /app/public
|
||||||
|
|
||||||
|
php_server {
|
||||||
|
index index.php
|
||||||
|
}
|
||||||
|
|
||||||
|
encode gzip
|
||||||
|
|
||||||
|
file_server
|
||||||
|
|
||||||
|
# Less strict headers for development
|
||||||
|
header {
|
||||||
|
X-Frame-Options "SAMEORIGIN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Install Node development dependencies globally
|
||||||
|
RUN npm install -g nodemon
|
||||||
|
|
||||||
|
# Create startup script for development (runs as host user)
|
||||||
|
RUN cat > /start.sh <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Create .env file if it doesn't exist
|
||||||
|
if [ ! -f ".env" ]; then
|
||||||
|
echo "Creating .env file from .env.example..."
|
||||||
|
cp .env.example .env
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install dependencies if volumes are empty
|
||||||
|
if [ ! -f "vendor/autoload.php" ]; then
|
||||||
|
echo "Installing composer dependencies..."
|
||||||
|
composer install
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle node_modules with care - clean install if having issues
|
||||||
|
if [ ! -f "node_modules/.bin/vite" ]; then
|
||||||
|
echo "Installing npm dependencies..."
|
||||||
|
# Clean any remnants first
|
||||||
|
rm -rf node_modules/.* 2>/dev/null || true
|
||||||
|
rm -rf /app/.npm 2>/dev/null || true
|
||||||
|
# Fresh install with cache in tmp to avoid permission issues
|
||||||
|
npm install --cache /tmp/.npm
|
||||||
|
else
|
||||||
|
echo "Node modules already installed, skipping npm install"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clear Laravel caches
|
||||||
|
php artisan config:clear || true
|
||||||
|
php artisan cache:clear || true
|
||||||
|
|
||||||
|
# Wait for database and run migrations
|
||||||
|
echo "Waiting for database..."
|
||||||
|
sleep 5
|
||||||
|
php artisan migrate --force || echo "Migration failed or not needed"
|
||||||
|
|
||||||
|
# Run development seeder (only in dev environment)
|
||||||
|
echo "Running development seeder..."
|
||||||
|
php artisan db:seed --class=DevelopmentSeeder --force || echo "Seeding skipped or already done"
|
||||||
|
|
||||||
|
# Generate app key if not set
|
||||||
|
if [ -z "$APP_KEY" ] || [ "$APP_KEY" = "base64:YOUR_KEY_HERE" ]; then
|
||||||
|
echo "Generating application key..."
|
||||||
|
php artisan key:generate
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start Vite dev server in background
|
||||||
|
npm run dev &
|
||||||
|
|
||||||
|
# Start FrankenPHP
|
||||||
|
exec frankenphp run --config /etc/caddy/Caddyfile
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUN chmod +x /start.sh
|
||||||
|
|
||||||
|
# Expose ports
|
||||||
|
EXPOSE 8000 5173
|
||||||
|
|
||||||
|
# Use the startup script
|
||||||
|
CMD ["/start.sh"]
|
||||||
99
docker-compose.prod.yml
Normal file
99
docker-compose.prod.yml
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
# Production Docker Compose
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: codeberg.org/lvl0/buckets:latest
|
||||||
|
container_name: buckets_app
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
environment:
|
||||||
|
# Required from user
|
||||||
|
APP_KEY: "${APP_KEY}" # Critical - must persist across deployments
|
||||||
|
APP_URL: "${APP_URL}"
|
||||||
|
DB_DATABASE: "${DB_DATABASE}"
|
||||||
|
DB_USERNAME: "${DB_USERNAME}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
|
|
||||||
|
# Optional email configuration
|
||||||
|
MAIL_HOST: "${MAIL_HOST:-}"
|
||||||
|
MAIL_PORT: "${MAIL_PORT:-587}"
|
||||||
|
MAIL_USERNAME: "${MAIL_USERNAME:-}"
|
||||||
|
MAIL_PASSWORD: "${MAIL_PASSWORD:-}"
|
||||||
|
MAIL_FROM_ADDRESS: "${MAIL_FROM_ADDRESS:-noreply@example.com}"
|
||||||
|
volumes:
|
||||||
|
# Only persist storage in production
|
||||||
|
- app_storage:/app/storage
|
||||||
|
- app_logs:/app/storage/logs
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
networks:
|
||||||
|
- buckets
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8000/up"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mariadb:11
|
||||||
|
container_name: buckets_db
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
MYSQL_DATABASE: "${DB_DATABASE}"
|
||||||
|
MYSQL_USER: "${DB_USERNAME}"
|
||||||
|
MYSQL_PASSWORD: "${DB_PASSWORD}"
|
||||||
|
MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}"
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
networks:
|
||||||
|
- buckets
|
||||||
|
|
||||||
|
# Optional: Redis for production caching/sessions
|
||||||
|
# redis:
|
||||||
|
# image: redis:7-alpine
|
||||||
|
# container_name: buckets_redis
|
||||||
|
# restart: always
|
||||||
|
# command: redis-server --requirepass ${REDIS_PASSWORD}
|
||||||
|
# volumes:
|
||||||
|
# - redis_data:/data
|
||||||
|
# networks:
|
||||||
|
# - buckets
|
||||||
|
# healthcheck:
|
||||||
|
# test: ["CMD", "redis-cli", "ping"]
|
||||||
|
# interval: 30s
|
||||||
|
# timeout: 10s
|
||||||
|
# retries: 3
|
||||||
|
|
||||||
|
# Optional: Backup service
|
||||||
|
# backup:
|
||||||
|
# image: mariadb:11
|
||||||
|
# container_name: buckets_backup
|
||||||
|
# restart: always
|
||||||
|
# environment:
|
||||||
|
# MYSQL_HOST: db
|
||||||
|
# MYSQL_USER: root
|
||||||
|
# MYSQL_PASSWORD: "${DB_ROOT_PASSWORD}"
|
||||||
|
# volumes:
|
||||||
|
# - ./database/backups:/backups
|
||||||
|
# - ./scripts/backup.sh:/backup.sh:ro
|
||||||
|
# entrypoint: ["/bin/sh"]
|
||||||
|
# command: ["-c", "while true; do /backup.sh; sleep 86400; done"]
|
||||||
|
# depends_on:
|
||||||
|
# - db
|
||||||
|
# networks:
|
||||||
|
# - buckets
|
||||||
|
|
||||||
|
networks:
|
||||||
|
buckets:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
|
driver: local
|
||||||
|
app_storage:
|
||||||
|
driver: local
|
||||||
|
app_logs:
|
||||||
|
driver: local
|
||||||
|
# redis_data:
|
||||||
|
# driver: local
|
||||||
119
docker-compose.yml
Normal file
119
docker-compose.yml
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
# Local Development Docker Compose
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
container_name: buckets_app
|
||||||
|
restart: unless-stopped
|
||||||
|
# Remove user directive to run as root in container
|
||||||
|
# The container will handle permissions internally
|
||||||
|
ports:
|
||||||
|
- "8000:8000" # Laravel app
|
||||||
|
- "5173:5173" # Vite dev server
|
||||||
|
environment:
|
||||||
|
# Laravel
|
||||||
|
APP_NAME: "${APP_NAME:-buckets}"
|
||||||
|
APP_ENV: "${APP_ENV:-local}"
|
||||||
|
APP_KEY: "${APP_KEY:-base64:YOUR_KEY_HERE}"
|
||||||
|
APP_DEBUG: "${APP_DEBUG:-true}"
|
||||||
|
APP_URL: "${APP_URL:-http://localhost:8000}"
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DB_CONNECTION: mysql
|
||||||
|
DB_HOST: db
|
||||||
|
DB_PORT: 3306
|
||||||
|
DB_DATABASE: "${DB_DATABASE:-buckets}"
|
||||||
|
DB_USERNAME: "${DB_USERNAME:-buckets}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD:-buckets}"
|
||||||
|
|
||||||
|
# Session & Cache
|
||||||
|
SESSION_DRIVER: "${SESSION_DRIVER:-file}"
|
||||||
|
CACHE_DRIVER: "${CACHE_DRIVER:-file}"
|
||||||
|
QUEUE_CONNECTION: "${QUEUE_CONNECTION:-sync}"
|
||||||
|
|
||||||
|
# Mail (for development)
|
||||||
|
MAIL_MAILER: "${MAIL_MAILER:-log}"
|
||||||
|
|
||||||
|
# Vite
|
||||||
|
VITE_HOST: "0.0.0.0"
|
||||||
|
volumes:
|
||||||
|
# Mount entire project for hot reload with SELinux context
|
||||||
|
- .:/app:Z
|
||||||
|
# Named volumes for performance and permission isolation
|
||||||
|
- app_vendor:/app/vendor
|
||||||
|
- app_node_modules:/app/node_modules
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
networks:
|
||||||
|
- buckets
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mariadb:11
|
||||||
|
container_name: buckets_db
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
environment:
|
||||||
|
MYSQL_DATABASE: "${DB_DATABASE:-buckets}"
|
||||||
|
MYSQL_USER: "${DB_USERNAME:-buckets}"
|
||||||
|
MYSQL_PASSWORD: "${DB_PASSWORD:-buckets}"
|
||||||
|
MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD:-root}"
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
# Initialize with SQL scripts
|
||||||
|
- ./docker/mysql-init:/docker-entrypoint-initdb.d
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
networks:
|
||||||
|
- buckets
|
||||||
|
|
||||||
|
# Optional: Mailhog for email testing
|
||||||
|
mailhog:
|
||||||
|
image: mailhog/mailhog
|
||||||
|
container_name: buckets_mailhog
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "1025:1025" # SMTP server
|
||||||
|
- "8025:8025" # Web UI
|
||||||
|
networks:
|
||||||
|
- buckets
|
||||||
|
|
||||||
|
# Selenium for E2E testing with Dusk
|
||||||
|
selenium:
|
||||||
|
image: selenium/standalone-chrome:latest
|
||||||
|
container_name: buckets_selenium
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "4444:4444" # Selenium server
|
||||||
|
- "7900:7900" # VNC server for debugging
|
||||||
|
volumes:
|
||||||
|
- /dev/shm:/dev/shm
|
||||||
|
networks:
|
||||||
|
- buckets
|
||||||
|
environment:
|
||||||
|
- SE_VNC_PASSWORD=secret
|
||||||
|
|
||||||
|
# Optional: Redis for caching/sessions
|
||||||
|
# redis:
|
||||||
|
# image: redis:alpine
|
||||||
|
# container_name: buckets_redis
|
||||||
|
# restart: unless-stopped
|
||||||
|
# ports:
|
||||||
|
# - "6379:6379"
|
||||||
|
# networks:
|
||||||
|
# - buckets
|
||||||
|
|
||||||
|
networks:
|
||||||
|
buckets:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
|
app_vendor:
|
||||||
|
app_node_modules:
|
||||||
Loading…
Reference in a new issue