Enhance Docker Configuration and Health Checks (#761)

* Enhance Docker Configuration and Health Checks

- Added PHP configuration settings in `docker-compose.dev.yml` and `docker-compose.yml` to improve memory management and execution limits, ensuring better performance for PHP applications.
- Introduced health checks for various services including `api`, `api-worker`, `api-scheduler`, `ui`, `redis`, and `db` to ensure service availability and reliability.
- Updated environment variables in `.env.docker` and `client/.env.docker` to include new keys for H-Captcha and reCAPTCHA, enhancing security features.
- Refactored the PHP-FPM entrypoint script to apply PHP configurations dynamically based on environment variables, improving flexibility in deployment.
- Removed outdated PHP configuration files to streamline the Docker setup.

These changes aim to enhance the overall stability, performance, and security of the application in a Dockerized environment.

* Refactor Dockerfile for Improved Build Process

- Changed the Dockerfile to utilize a multi-stage build approach, separating the build and runtime environments for better efficiency.
- Introduced a builder stage using the PHP CLI image to install dependencies and extensions, optimizing the final image size.
- Removed unnecessary installation steps and combined related commands to streamline the Dockerfile, enhancing readability and maintainability.
- Updated the runtime stage to use the PHP FPM Alpine image, ensuring a smaller and more secure production environment.

These changes aim to improve the build process, reduce image size, and enhance the overall performance of the Dockerized application.
This commit is contained in:
Julien Nahum
2025-05-20 19:20:44 +02:00
committed by GitHub
parent b2b04d7f2a
commit ae21cae8cd
16 changed files with 320 additions and 164 deletions

View File

@@ -1,54 +1,64 @@
FROM php:8.3-fpm
# Build stage - using PHP CLI image with extensions
FROM php:8.3-cli AS builder
# Install system dependencies
# Install composer and extensions needed for dependency installation
RUN apt-get update && apt-get install -y \
libzip-dev \
libpng-dev \
postgresql-client \
libpq-dev \
unzip \
gcc \
make \
autoconf \
libc-dev \
pkg-config \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
git \
&& docker-php-ext-install -j$(nproc) \
bcmath \
gd \
zip \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Install composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
ENV COMPOSER_ALLOW_SUPERUSER=1
WORKDIR /app
# Install PHP extensions
ENV CFLAGS="-O1 -D_GNU_SOURCE" \
CXXFLAGS="-O1 -D_GNU_SOURCE"
# Copy the entire source code for proper installation
COPY api/ .
# Install basic extensions first
RUN set -eux; \
docker-php-ext-install -j$(nproc) pdo zip && \
php -m | grep -E 'pdo|zip'
# Install dependencies including dev dependencies
RUN composer install --optimize-autoloader --no-interaction \
--ignore-platform-req=php \
--ignore-platform-req=ext-bcmath \
--ignore-platform-req=ext-gd
# Install GD
RUN set -eux; \
docker-php-ext-install -j$(nproc) gd && \
php -m | grep -E 'gd'
# Final stage - smaller runtime image
FROM php:8.3-fpm-alpine
# Install PostgreSQL related extensions
RUN set -eux; \
docker-php-ext-configure pgsql && \
docker-php-ext-install -j$(nproc) pgsql pdo_pgsql && \
php -m | grep -E 'pgsql|pdo_pgsql'
# Install runtime dependencies
RUN apk add --no-cache \
libzip \
libpng \
postgresql-client \
libpq \
procps \
unzip \
bash \
icu-libs \
&& rm -rf /var/cache/apk/*
# Install bcmath with optimization flags for stability
RUN set -eux; \
docker-php-ext-install -j1 bcmath && \
php -m | grep -E 'bcmath'
# Install Redis extension
RUN set -eux; \
pecl install -f --configureoptions 'enable-redis-igbinary="no" enable-redis-lzf="no" enable-redis-zstd="no" enable-redis-msgpack="no" enable-redis-lz4="no"' redis && \
docker-php-ext-enable redis && \
php -m | grep -E 'redis'
# Install build dependencies and PHP extensions
RUN apk add --no-cache --virtual .build-deps \
$PHPIZE_DEPS \
libzip-dev \
libpng-dev \
postgresql-dev \
oniguruma-dev \
icu-dev \
&& docker-php-ext-configure pgsql \
&& docker-php-ext-configure gd \
&& docker-php-ext-install -j$(nproc) \
pdo \
zip \
gd \
pgsql \
pdo_pgsql \
bcmath \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& apk del .build-deps
WORKDIR /usr/share/nginx/html/
@@ -62,26 +72,8 @@ RUN mkdir -p storage/framework/sessions \
&& chown -R www-data:www-data storage bootstrap/cache \
&& chmod -R 775 storage bootstrap/cache
# Copy composer files and helpers.php first
COPY api/composer.json api/composer.lock ./
COPY api/app/helpers.php ./app/helpers.php
# Default to production settings unless overridden during build
ARG APP_ENV=production
ARG COMPOSER_FLAGS=--no-dev --optimize-autoloader --no-interaction
# Install dependencies without running scripts
RUN composer install ${COMPOSER_FLAGS} --no-scripts --ignore-platform-req=php
# Copy the rest of the application
COPY api/ .
# Run composer scripts and clear cache
RUN composer dump-autoload -o \
&& php artisan package:discover --ansi \
&& composer clear-cache \
&& chmod -R 775 storage \
&& chown -R www-data:www-data storage
# Copy the entire application from the builder stage
COPY --from=builder /app/ ./
# Setup entrypoint
COPY docker/php-fpm-entrypoint /usr/local/bin/opnform-entrypoint

View File

@@ -20,8 +20,15 @@ RUN npm cache clean --force && \
# RUN npm install esbuild@0.21.5
ADD ./client/ /app/
# Increase Node memory limit to prevent out of memory error during build
RUN NODE_OPTIONS="--max-old-space-size=4096" npm run build
# Optimize memory usage during build
ENV NODE_OPTIONS="--max-old-space-size=4096"
# Set production mode to reduce memory usage
ENV NODE_ENV=production
# Disable source maps to reduce memory usage
ENV GENERATE_SOURCEMAP=false
# Run the build
RUN npm run build
FROM node:20-alpine
WORKDIR /app

View File

@@ -7,6 +7,7 @@ server {
listen 80;
server_name opnform;
root /usr/share/nginx/html/public;
client_max_body_size ${NGINX_MAX_BODY_SIZE};
access_log /dev/stdout;
error_log /dev/stderr error;

View File

@@ -7,6 +7,7 @@ server {
listen 80;
server_name localhost;
root /usr/share/nginx/html/public;
client_max_body_size ${NGINX_MAX_BODY_SIZE};
access_log /dev/stdout;
error_log /dev/stderr error;

View File

@@ -3,42 +3,82 @@
main() {
if [ "$IS_API_WORKER" = "true" ]; then
# This is the API worker, skip setup and just run the command
apply_php_configuration
exec "$@"
else
# This is the API service, run full setup
# This is the API service or scheduler, run full setup
apply_php_configuration
prep_file_permissions
prep_storage
wait_for_db
apply_db_migrations
run_init_project
optimize_application
if [ "$CONTAINER_ROLE" = "scheduler" ]; then
echo "Initializing scheduler status for first run (entrypoint)"
./artisan app:scheduler-status --mode=record
fi
run_server "$@"
fi
}
apply_php_configuration() {
echo "Applying PHP configuration from environment variables"
# Create custom PHP config file
PHP_CUSTOM_CONFIG_FILE="/usr/local/etc/php/conf.d/99-custom.ini"
# Apply memory limit if provided
if [ -n "$PHP_MEMORY_LIMIT" ]; then
echo "memory_limit = $PHP_MEMORY_LIMIT" >> $PHP_CUSTOM_CONFIG_FILE
fi
# Apply max execution time if provided
if [ -n "$PHP_MAX_EXECUTION_TIME" ]; then
echo "max_execution_time = $PHP_MAX_EXECUTION_TIME" >> $PHP_CUSTOM_CONFIG_FILE
fi
# Apply upload max filesize if provided
if [ -n "$PHP_UPLOAD_MAX_FILESIZE" ]; then
echo "upload_max_filesize = $PHP_UPLOAD_MAX_FILESIZE" >> $PHP_CUSTOM_CONFIG_FILE
fi
# Apply post max size if provided
if [ -n "$PHP_POST_MAX_SIZE" ]; then
echo "post_max_size = $PHP_POST_MAX_SIZE" >> $PHP_CUSTOM_CONFIG_FILE
fi
# Log applied configuration
echo "Applied PHP configuration:"
cat $PHP_CUSTOM_CONFIG_FILE
}
prep_file_permissions() {
chmod a+x ./artisan
}
prep_storage() {
# Create Laravel-specific directories
mkdir -p /persist/storage/framework/cache/data
mkdir -p /persist/storage/framework/sessions
mkdir -p /persist/storage/framework/views
local app_storage_path="/usr/share/nginx/html/storage"
# Create Laravel-specific directories directly in the mounted volume
mkdir -p "$app_storage_path/app/public"
mkdir -p "$app_storage_path/framework/cache/data"
mkdir -p "$app_storage_path/framework/sessions"
mkdir -p "$app_storage_path/framework/views"
mkdir -p "$app_storage_path/logs"
# Set permissions for the entire storage directory
chown -R www-data:www-data /persist/storage
chmod -R 775 /persist/storage
# Create symlink to the correct storage location
ln -sf /persist/storage /usr/share/nginx/html/storage
chown -R www-data:www-data "$app_storage_path"
chmod -R 775 "$app_storage_path"
touch /var/log/opnform.log
chown www-data /var/log/opnform.log
# Ensure proper permissions for the storage directory
chown -R www-data:www-data /usr/share/nginx/html/storage
chmod -R 775 /usr/share/nginx/html/storage
# Run Laravel's storage link command (ensure script is run from app root or adjust path to artisan)
echo "Creating public storage symlink"
./artisan storage:link
}
wait_for_db() {

View File

@@ -1,15 +0,0 @@
[www]
user = www-data
group = www-data
listen = 9000
pm = dynamic
pm.max_children = 20
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 1000
clear_env = no
catch_workers_output = yes
decorate_workers_output = no

View File

@@ -1,27 +0,0 @@
; PHP Configuration
memory_limit = 512M
max_execution_time = 60
upload_max_filesize = 64M
post_max_size = 64M
max_input_vars = 3000
; Error reporting
error_reporting = E_ALL
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /dev/stderr
; Date
date.timezone = UTC
; Session
session.save_handler = redis
session.save_path = "tcp://redis:6379"
; OpCache
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=0