Une application SaaS éducative nécessite une séparation stricte des données entre établissements scolaires. L'architecture multi-tenant par sous-domaine (ecole-alpha.classeo.local) permet cette isolation tout en utilisant une base de code unique. Le choix d'une résolution basée sur les sous-domaines plutôt que sur des headers ou tokens facilite le routage au niveau infrastructure (reverse proxy) et offre une UX plus naturelle où chaque école accède à "son" URL dédiée.
143 lines
4.8 KiB
Docker
143 lines
4.8 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# =============================================================================
|
|
# PHP 8.5 + FrankenPHP - Backend Classeo
|
|
# =============================================================================
|
|
|
|
FROM dunglas/frankenphp:1-php8.5-alpine AS base
|
|
|
|
# Install system dependencies
|
|
RUN apk add --no-cache \
|
|
acl \
|
|
fcgi \
|
|
file \
|
|
gettext \
|
|
git \
|
|
icu-dev \
|
|
libzip-dev \
|
|
postgresql-dev \
|
|
rabbitmq-c-dev \
|
|
linux-headers \
|
|
$PHPIZE_DEPS
|
|
|
|
# Install PHP extensions (opcache is pre-installed in FrankenPHP)
|
|
RUN docker-php-ext-install intl pdo_pgsql zip sockets
|
|
|
|
# Install AMQP extension for RabbitMQ
|
|
RUN pecl install amqp && docker-php-ext-enable amqp
|
|
|
|
# Install Redis extension
|
|
RUN pecl install redis && docker-php-ext-enable redis
|
|
|
|
# Install Composer
|
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
|
|
|
# Set working directory
|
|
WORKDIR /app
|
|
|
|
# Configure PHP for production
|
|
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
|
|
|
# Custom PHP configuration
|
|
RUN echo "opcache.enable=1" >> "$PHP_INI_DIR/conf.d/opcache.ini" \
|
|
&& echo "opcache.memory_consumption=256" >> "$PHP_INI_DIR/conf.d/opcache.ini" \
|
|
&& echo "opcache.interned_strings_buffer=16" >> "$PHP_INI_DIR/conf.d/opcache.ini" \
|
|
&& echo "opcache.max_accelerated_files=20000" >> "$PHP_INI_DIR/conf.d/opcache.ini" \
|
|
&& echo "opcache.validate_timestamps=0" >> "$PHP_INI_DIR/conf.d/opcache.ini" \
|
|
&& echo "realpath_cache_size=4096K" >> "$PHP_INI_DIR/conf.d/opcache.ini" \
|
|
&& echo "realpath_cache_ttl=600" >> "$PHP_INI_DIR/conf.d/opcache.ini"
|
|
|
|
# =============================================================================
|
|
# Development stage
|
|
# =============================================================================
|
|
FROM base AS dev
|
|
|
|
# Install gosu for proper user switching
|
|
ENV GOSU_VERSION=1.17
|
|
RUN set -eux; \
|
|
apk add --no-cache --virtual .gosu-deps dpkg gnupg; \
|
|
dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
|
|
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
|
|
chmod +x /usr/local/bin/gosu; \
|
|
gosu --version; \
|
|
gosu nobody true; \
|
|
apk del --no-network .gosu-deps
|
|
|
|
# Enable opcache revalidation for dev (zz- prefix loads last alphabetically)
|
|
RUN echo "opcache.validate_timestamps=1" >> "$PHP_INI_DIR/conf.d/zz-opcache-dev.ini"
|
|
|
|
# Enable Xdebug for development
|
|
RUN pecl install xdebug && docker-php-ext-enable xdebug
|
|
RUN echo "xdebug.mode=develop,debug,coverage" >> "$PHP_INI_DIR/conf.d/xdebug.ini" \
|
|
&& echo "xdebug.client_host=host.docker.internal" >> "$PHP_INI_DIR/conf.d/xdebug.ini" \
|
|
&& echo "xdebug.start_with_request=trigger" >> "$PHP_INI_DIR/conf.d/xdebug.ini"
|
|
|
|
# Caddy config for FrankenPHP
|
|
ENV SERVER_NAME=:8000
|
|
ENV FRANKENPHP_CONFIG="worker ./public/index.php"
|
|
|
|
# Entrypoint: detect host UID/GID and run as matching user
|
|
# Uses gosu with UID:GID directly (no need to create user in Dockerfile)
|
|
COPY --chmod=755 <<'EOF' /usr/local/bin/docker-entrypoint.sh
|
|
#!/bin/sh
|
|
set -e
|
|
|
|
# Detect UID/GID from mounted /app directory
|
|
HOST_UID=$(stat -c %u /app)
|
|
HOST_GID=$(stat -c %g /app)
|
|
|
|
# If root owns /app, run as root (CI environment or volume not mounted)
|
|
if [ "$HOST_UID" = "0" ]; then
|
|
# Install dependencies if not present
|
|
if [ ! -f /app/vendor/autoload.php ]; then
|
|
echo "Installing Composer dependencies..."
|
|
composer install --prefer-dist --no-progress --no-interaction
|
|
fi
|
|
mkdir -p /app/var/cache /app/var/log
|
|
exec "$@"
|
|
fi
|
|
|
|
# Ensure directories exist with correct ownership
|
|
mkdir -p /app/var/cache /app/var/log /data /config
|
|
chown -R "$HOST_UID:$HOST_GID" /app/var /data /config 2>/dev/null || true
|
|
|
|
# Install Composer dependencies if not present (as host user)
|
|
if [ ! -f /app/vendor/autoload.php ]; then
|
|
echo "Installing Composer dependencies..."
|
|
gosu "$HOST_UID:$HOST_GID" composer install --prefer-dist --no-progress --no-interaction
|
|
fi
|
|
|
|
# Run command as host user via gosu (using UID:GID directly)
|
|
exec gosu "$HOST_UID:$HOST_GID" "$@"
|
|
EOF
|
|
|
|
EXPOSE 8000
|
|
|
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
|
CMD ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile"]
|
|
|
|
# =============================================================================
|
|
# Production stage
|
|
# =============================================================================
|
|
FROM base AS prod
|
|
|
|
ENV APP_ENV=prod
|
|
ENV SERVER_NAME=:8000
|
|
ENV FRANKENPHP_CONFIG="worker ./public/index.php"
|
|
|
|
# Copy application files
|
|
COPY . /app
|
|
|
|
# Install dependencies (prod only, optimized)
|
|
RUN composer install --no-dev --prefer-dist --no-progress --no-interaction --optimize-autoloader
|
|
|
|
# Warmup cache
|
|
RUN php bin/console cache:warmup
|
|
|
|
# Ensure var directory exists with proper permissions
|
|
RUN mkdir -p var/cache var/log && chmod -R 755 var
|
|
|
|
EXPOSE 8000
|
|
|
|
CMD ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile"]
|