Add shared httpd + PHP-FPM-only container architecture
Some checks failed
Cloud Apache Container / Build-and-Push (74) (push) Successful in 2m22s
Cloud Apache Container / Build-and-Push (80) (push) Successful in 3m14s
Cloud Apache Container / Build-and-Push (82) (push) Has been cancelled
Cloud Apache Container / Build-and-Push (83) (push) Has been cancelled
Cloud Apache Container / Build-and-Push (84) (push) Has been cancelled
Cloud Apache Container / Build-and-Push (85) (push) Has been cancelled
Cloud Apache Container / Build-FPM-Images (74) (push) Has been cancelled
Cloud Apache Container / Build-FPM-Images (80) (push) Has been cancelled
Cloud Apache Container / Build-FPM-Images (81) (push) Has been cancelled
Cloud Apache Container / Build-FPM-Images (82) (push) Has been cancelled
Cloud Apache Container / Build-FPM-Images (83) (push) Has been cancelled
Cloud Apache Container / Build-FPM-Images (84) (push) Has been cancelled
Cloud Apache Container / Build-FPM-Images (85) (push) Has been cancelled
Cloud Apache Container / Build-Shared-httpd (push) Has been cancelled
Cloud Apache Container / Build-and-Push (81) (push) Has been cancelled

Separate Apache and PHP-FPM into distinct container roles to reduce
per-customer memory overhead on shared servers. Adds three new images:
- Dockerfile.fpm: PHP-FPM only (no Apache), listens on TCP port 9000
- Dockerfile.shared-httpd: Apache only (no PHP), with SSL and proxy_fcgi
- Existing Dockerfile unchanged for standalone mode

Key changes:
- detect-memory.sh: CONTAINER_ROLE env var (combined/fpm_only/httpd_only)
  controls the memory budget split
- create-php-config.sh: FPM_LISTEN env var for TCP port vs Unix socket,
  added /fpm-ping and /fpm-status health endpoints
- New entrypoints for each container role
- tune-mpm.sh for hot-adjusting Apache MPM settings
- shared-vhost-template.tpl with proxy_fcgi and SSL on port 443
- CI/CD builds all three image types in parallel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 10:08:00 -07:00
parent 87c4f2befc
commit c78167871c
9 changed files with 510 additions and 55 deletions

View File

@@ -38,6 +38,8 @@ fi
CONTAINER_MEMORY_MB=$((CONTAINER_MEMORY_BYTES / 1024 / 1024))
# --- Budget calculation ---
CONTAINER_ROLE=${CONTAINER_ROLE:-combined} # combined | fpm_only | httpd_only
OS_RESERVE_MB=50
FIXED_PROCESS_MB=50
DEV_OVERHEAD_MB=0
@@ -50,63 +52,83 @@ if [ "$AVAILABLE_MB" -lt 60 ]; then
AVAILABLE_MB=60
fi
PHP_BUDGET_MB=$((AVAILABLE_MB * 80 / 100))
APACHE_BUDGET_MB=$((AVAILABLE_MB * 20 / 100))
case "$CONTAINER_ROLE" in
fpm_only)
PHP_BUDGET_MB=$AVAILABLE_MB
APACHE_BUDGET_MB=0
;;
httpd_only)
PHP_BUDGET_MB=0
APACHE_BUDGET_MB=$AVAILABLE_MB
;;
*)
PHP_BUDGET_MB=$((AVAILABLE_MB * 80 / 100))
APACHE_BUDGET_MB=$((AVAILABLE_MB * 20 / 100))
;;
esac
# --- PHP-FPM parameters ---
PHP_WORKER_ESTIMATE_MB=${PHP_WORKER_ESTIMATE_MB:-60}
# --- PHP-FPM parameters (skipped for httpd_only) ---
if [ "$CONTAINER_ROLE" != "httpd_only" ]; then
PHP_WORKER_ESTIMATE_MB=${PHP_WORKER_ESTIMATE_MB:-60}
calc_max_children=$((PHP_BUDGET_MB / PHP_WORKER_ESTIMATE_MB))
# Floor at 2, cap at 50
if [ "$calc_max_children" -lt 2 ]; then
calc_max_children=2
fi
if [ "$calc_max_children" -gt 50 ]; then
calc_max_children=50
calc_max_children=$((PHP_BUDGET_MB / PHP_WORKER_ESTIMATE_MB))
# Floor at 2, cap at 50
if [ "$calc_max_children" -lt 2 ]; then
calc_max_children=2
fi
if [ "$calc_max_children" -gt 50 ]; then
calc_max_children=50
fi
PHP_FPM_PM=${FPM_PM:-ondemand}
PHP_FPM_MAX_CHILDREN=${FPM_MAX_CHILDREN:-$calc_max_children}
PHP_FPM_PROCESS_IDLE_TIMEOUT=${FPM_PROCESS_IDLE_TIMEOUT:-10s}
PHP_FPM_MAX_REQUESTS=${FPM_MAX_REQUESTS:-500}
# Dynamic mode fallbacks (used if user overrides FPM_PM=dynamic)
PHP_FPM_START_SERVERS=${FPM_START_SERVERS:-2}
PHP_FPM_MIN_SPARE=${FPM_MIN_SPARE_SERVERS:-1}
PHP_FPM_MAX_SPARE=${FPM_MAX_SPARE_SERVERS:-3}
fi
PHP_FPM_PM=${FPM_PM:-ondemand}
PHP_FPM_MAX_CHILDREN=${FPM_MAX_CHILDREN:-$calc_max_children}
PHP_FPM_PROCESS_IDLE_TIMEOUT=${FPM_PROCESS_IDLE_TIMEOUT:-10s}
PHP_FPM_MAX_REQUESTS=${FPM_MAX_REQUESTS:-500}
# --- Apache MPM parameters (skipped for fpm_only) ---
if [ "$CONTAINER_ROLE" != "fpm_only" ]; then
# ServerLimit: roughly 1 process per ~25 workers, floor 2, cap 16
calc_server_limit=$((APACHE_BUDGET_MB / 30))
if [ "$calc_server_limit" -lt 2 ]; then
calc_server_limit=2
fi
if [ "$calc_server_limit" -gt 16 ]; then
calc_server_limit=16
fi
# Dynamic mode fallbacks (used if user overrides FPM_PM=dynamic)
PHP_FPM_START_SERVERS=${FPM_START_SERVERS:-2}
PHP_FPM_MIN_SPARE=${FPM_MIN_SPARE_SERVERS:-1}
PHP_FPM_MAX_SPARE=${FPM_MAX_SPARE_SERVERS:-3}
# MaxRequestWorkers: ServerLimit * ThreadsPerChild (25)
calc_max_request_workers=$((calc_server_limit * 25))
if [ "$calc_max_request_workers" -gt 400 ]; then
calc_max_request_workers=400
fi
# --- Apache MPM parameters ---
# ServerLimit: roughly 1 process per ~25 workers, floor 2, cap 16
calc_server_limit=$((APACHE_BUDGET_MB / 30))
if [ "$calc_server_limit" -lt 2 ]; then
calc_server_limit=2
# StartServers: 1 for ≤1GB, 2 for larger
calc_start_servers=1
if [ "$CONTAINER_MEMORY_MB" -gt 1024 ]; then
calc_start_servers=2
fi
APACHE_START_SERVERS=${APACHE_START_SERVERS:-$calc_start_servers}
APACHE_SERVER_LIMIT=${APACHE_SERVER_LIMIT:-$calc_server_limit}
APACHE_MAX_REQUEST_WORKERS=${APACHE_MAX_REQUEST_WORKERS:-$calc_max_request_workers}
APACHE_MIN_SPARE_THREADS=${APACHE_MIN_SPARE_THREADS:-5}
APACHE_MAX_SPARE_THREADS=${APACHE_MAX_SPARE_THREADS:-15}
APACHE_MAX_CONNECTIONS_PER_CHILD=${APACHE_MAX_CONNECTIONS_PER_CHILD:-3000}
fi
if [ "$calc_server_limit" -gt 16 ]; then
calc_server_limit=16
fi
# MaxRequestWorkers: ServerLimit * ThreadsPerChild (25)
calc_max_request_workers=$((calc_server_limit * 25))
if [ "$calc_max_request_workers" -gt 400 ]; then
calc_max_request_workers=400
fi
# StartServers: 1 for ≤1GB, 2 for larger
calc_start_servers=1
if [ "$CONTAINER_MEMORY_MB" -gt 1024 ]; then
calc_start_servers=2
fi
APACHE_START_SERVERS=${APACHE_START_SERVERS:-$calc_start_servers}
APACHE_SERVER_LIMIT=${APACHE_SERVER_LIMIT:-$calc_server_limit}
APACHE_MAX_REQUEST_WORKERS=${APACHE_MAX_REQUEST_WORKERS:-$calc_max_request_workers}
APACHE_MIN_SPARE_THREADS=${APACHE_MIN_SPARE_THREADS:-5}
APACHE_MAX_SPARE_THREADS=${APACHE_MAX_SPARE_THREADS:-15}
APACHE_MAX_CONNECTIONS_PER_CHILD=${APACHE_MAX_CONNECTIONS_PER_CHILD:-3000}
# --- Export all variables ---
export CONTAINER_MEMORY_MB
export PHP_FPM_PM PHP_FPM_MAX_CHILDREN PHP_FPM_PROCESS_IDLE_TIMEOUT PHP_FPM_MAX_REQUESTS
export PHP_FPM_START_SERVERS PHP_FPM_MIN_SPARE PHP_FPM_MAX_SPARE
export APACHE_START_SERVERS APACHE_SERVER_LIMIT APACHE_MAX_REQUEST_WORKERS
export APACHE_MIN_SPARE_THREADS APACHE_MAX_SPARE_THREADS APACHE_MAX_CONNECTIONS_PER_CHILD
export CONTAINER_ROLE CONTAINER_MEMORY_MB
if [ "$CONTAINER_ROLE" != "httpd_only" ]; then
export PHP_FPM_PM PHP_FPM_MAX_CHILDREN PHP_FPM_PROCESS_IDLE_TIMEOUT PHP_FPM_MAX_REQUESTS
export PHP_FPM_START_SERVERS PHP_FPM_MIN_SPARE PHP_FPM_MAX_SPARE
fi
if [ "$CONTAINER_ROLE" != "fpm_only" ]; then
export APACHE_START_SERVERS APACHE_SERVER_LIMIT APACHE_MAX_REQUEST_WORKERS
export APACHE_MIN_SPARE_THREADS APACHE_MAX_SPARE_THREADS APACHE_MAX_CONNECTIONS_PER_CHILD
fi