#!/usr/bin/env bash # detect-memory.sh — Detect container memory and calculate tuning parameters. # Must be sourced (not executed) so variables are available to the caller. # --- Memory detection (cgroups v2 → v1 → /proc/meminfo → fallback) --- CONTAINER_MEMORY_BYTES="" # cgroups v2 if [ -f /sys/fs/cgroup/memory.max ]; then val=$(cat /sys/fs/cgroup/memory.max 2>/dev/null) if [ "$val" != "max" ] && [ -n "$val" ]; then CONTAINER_MEMORY_BYTES=$val fi fi # cgroups v1 if [ -z "$CONTAINER_MEMORY_BYTES" ] && [ -f /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then val=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes 2>/dev/null) # Values near page-aligned max (like 9223372036854771712) mean "no limit" if [ -n "$val" ] && [ "$val" -lt 8589934592000 ] 2>/dev/null; then CONTAINER_MEMORY_BYTES=$val fi fi # /proc/meminfo (host memory — used when no cgroup limit is set) if [ -z "$CONTAINER_MEMORY_BYTES" ] && [ -f /proc/meminfo ]; then mem_kb=$(awk '/^MemTotal:/ {print $2}' /proc/meminfo) if [ -n "$mem_kb" ]; then CONTAINER_MEMORY_BYTES=$((mem_kb * 1024)) fi fi # Fallback if [ -z "$CONTAINER_MEMORY_BYTES" ]; then CONTAINER_MEMORY_BYTES=$((512 * 1024 * 1024)) fi CONTAINER_MEMORY_MB=$((CONTAINER_MEMORY_BYTES / 1024 / 1024)) # --- Budget calculation --- OS_RESERVE_MB=50 FIXED_PROCESS_MB=50 DEV_OVERHEAD_MB=0 if [ "$environment" = "DEV" ]; then DEV_OVERHEAD_MB=125 fi AVAILABLE_MB=$((CONTAINER_MEMORY_MB - OS_RESERVE_MB - FIXED_PROCESS_MB - DEV_OVERHEAD_MB)) if [ "$AVAILABLE_MB" -lt 60 ]; then AVAILABLE_MB=60 fi PHP_BUDGET_MB=$((AVAILABLE_MB * 80 / 100)) APACHE_BUDGET_MB=$((AVAILABLE_MB * 20 / 100)) # --- PHP-FPM parameters --- 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 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} # --- 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 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