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
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:
@@ -38,3 +38,65 @@ jobs:
|
||||
tags: |
|
||||
repo.anhonesthost.net/cloud-hosting-platform/cac:php${{ matrix.phpver }}
|
||||
${{ matrix.phpver == '85' && 'repo.anhonesthost.net/cloud-hosting-platform/cac:latest' || '' }}
|
||||
|
||||
Build-FPM-Images:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
phpver: [74, 80, 81, 82, 83, 84, 85]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Gitea
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: repo.anhonesthost.net
|
||||
username: ${{ secrets.CI_USER }}
|
||||
password: ${{ secrets.CI_TOKEN }}
|
||||
|
||||
- name: Build and Push FPM Image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: ./Dockerfile.fpm
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
build-args: |
|
||||
PHPVER=${{ matrix.phpver }}
|
||||
tags: |
|
||||
repo.anhonesthost.net/cloud-hosting-platform/cac-fpm:php${{ matrix.phpver }}
|
||||
${{ matrix.phpver == '85' && 'repo.anhonesthost.net/cloud-hosting-platform/cac-fpm:latest' || '' }}
|
||||
|
||||
Build-Shared-httpd:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Gitea
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: repo.anhonesthost.net
|
||||
username: ${{ secrets.CI_USER }}
|
||||
password: ${{ secrets.CI_TOKEN }}
|
||||
|
||||
- name: Build and Push Shared httpd Image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: ./Dockerfile.shared-httpd
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: |
|
||||
repo.anhonesthost.net/cloud-hosting-platform/shared-httpd:latest
|
||||
|
||||
43
Dockerfile.fpm
Normal file
43
Dockerfile.fpm
Normal file
@@ -0,0 +1,43 @@
|
||||
FROM almalinux/9-base
|
||||
ARG PHPVER=83
|
||||
|
||||
# Install repos, update, install only needed packages (no httpd/mod_ssl), clean up in one layer
|
||||
RUN dnf install -y \
|
||||
https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm \
|
||||
https://rpms.remirepo.net/enterprise/remi-release-9.rpm && \
|
||||
dnf update -y && \
|
||||
dnf install -y wget procps cronie iproute postgresql-devel microdnf less git \
|
||||
nano rsync unzip zip mariadb bind-utils jq patch nc tree dos2unix fcgi && \
|
||||
dnf clean all && \
|
||||
rm -rf /var/cache/dnf /usr/share/doc /usr/share/man /usr/share/locale/*
|
||||
|
||||
# Copy scripts into the image and set permissions
|
||||
COPY ./scripts/ /scripts/
|
||||
RUN chmod +x /scripts/*
|
||||
|
||||
# Create needed dirs, install PHP, clean up (no SSL cert, no httpd)
|
||||
RUN mkdir -p /run/php-fpm/ && \
|
||||
/scripts/install-php$PHPVER.sh && \
|
||||
rm -rf /tmp/*
|
||||
|
||||
# Download and install wp-cli
|
||||
RUN curl -L -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
|
||||
chmod +x /usr/local/bin/wp
|
||||
|
||||
# Download and install Composer
|
||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \
|
||||
chmod +x /usr/local/bin/composer
|
||||
|
||||
# Copy configs (PHP only, no Apache configs)
|
||||
COPY ./configs/prod-php.ini /etc/php.ini
|
||||
COPY ./configs/mariadb.repo /etc/yum.repos.d/
|
||||
|
||||
# Set up cron job for log rotation
|
||||
RUN echo "15 */12 * * * root /scripts/log-rotate.sh" >> /etc/crontab
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
|
||||
CMD SCRIPT_FILENAME=/fpm-ping SCRIPT_NAME=/fpm-ping REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000 | grep -q pong || exit 1
|
||||
|
||||
ENTRYPOINT [ "/scripts/entrypoint-fpm.sh" ]
|
||||
40
Dockerfile.shared-httpd
Normal file
40
Dockerfile.shared-httpd
Normal file
@@ -0,0 +1,40 @@
|
||||
FROM almalinux/9-base
|
||||
|
||||
# Install Apache and minimal dependencies (no PHP at all)
|
||||
RUN dnf install -y \
|
||||
https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm && \
|
||||
dnf update -y && \
|
||||
dnf install -y httpd mod_ssl iproute cronie procps curl && \
|
||||
dnf clean all && \
|
||||
rm -rf /var/cache/dnf /usr/share/doc /usr/share/man /usr/share/locale/*
|
||||
|
||||
# Copy scripts and set permissions
|
||||
COPY ./scripts/detect-memory.sh /scripts/detect-memory.sh
|
||||
COPY ./scripts/create-apache-mpm-config.sh /scripts/create-apache-mpm-config.sh
|
||||
COPY ./scripts/log-rotate.sh /scripts/log-rotate.sh
|
||||
COPY ./scripts/entrypoint-shared-httpd.sh /scripts/entrypoint-shared-httpd.sh
|
||||
COPY ./scripts/tune-mpm.sh /scripts/tune-mpm.sh
|
||||
RUN chmod +x /scripts/*
|
||||
|
||||
# Generate self-signed SSL cert (same as main CAC image)
|
||||
RUN openssl req -newkey rsa:2048 -nodes \
|
||||
-keyout /etc/pki/tls/private/localhost.key \
|
||||
-x509 -days 3650 -subj "/CN=localhost" \
|
||||
-out /etc/pki/tls/certs/localhost.crt
|
||||
|
||||
# Copy Apache configs
|
||||
COPY ./configs/remote_ip.conf /etc/httpd/conf.d/
|
||||
COPY ./configs/default-index.conf /etc/httpd/conf.d/
|
||||
|
||||
# Create vhosts directory (will be volume-mounted from host)
|
||||
RUN mkdir -p /etc/httpd/conf.d/vhosts
|
||||
|
||||
# Set up cron job for log rotation
|
||||
RUN echo "15 */12 * * * root /scripts/log-rotate.sh" >> /etc/crontab
|
||||
|
||||
EXPOSE 80 443
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
|
||||
CMD curl -sfk https://localhost/ping || exit 1
|
||||
|
||||
ENTRYPOINT [ "/scripts/entrypoint-shared-httpd.sh" ]
|
||||
39
configs/shared-vhost-template.tpl
Normal file
39
configs/shared-vhost-template.tpl
Normal file
@@ -0,0 +1,39 @@
|
||||
<Directory "/mnt/users/~~user~~/~~domain~~">
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Directory "/mnt/users/~~user~~/~~domain~~/public_html">
|
||||
Options All MultiViews
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName "~~domain~~"
|
||||
~~alias_block~~
|
||||
DocumentRoot "/mnt/users/~~user~~/~~domain~~/public_html"
|
||||
RewriteEngine on
|
||||
RewriteCond %{SERVER_NAME} =~~domain~~
|
||||
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
|
||||
</VirtualHost>
|
||||
|
||||
<IfModule mod_ssl.c>
|
||||
<VirtualHost *:443>
|
||||
ServerName "~~domain~~"
|
||||
~~alias_block~~
|
||||
DocumentRoot "/mnt/users/~~user~~/~~domain~~/public_html"
|
||||
|
||||
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
|
||||
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
|
||||
|
||||
<FilesMatch \.php$>
|
||||
SetHandler "proxy:fcgi://~~fpm_host~~:~~fpm_port~~"
|
||||
</FilesMatch>
|
||||
|
||||
DirectoryIndex index.php index.html index.htm
|
||||
|
||||
ErrorLog "/var/log/httpd/~~domain~~-error.log"
|
||||
CustomLog "/var/log/httpd/~~domain~~-access.log" combined
|
||||
</VirtualHost>
|
||||
</IfModule>
|
||||
@@ -2,15 +2,28 @@
|
||||
|
||||
rm /etc/php-fpm.d/www.conf
|
||||
|
||||
FPM_LISTEN=${FPM_LISTEN:-/run/php-fpm/www.sock}
|
||||
|
||||
# Determine listen directive and ownership based on socket vs TCP
|
||||
if echo "$FPM_LISTEN" | grep -q '/'; then
|
||||
# Unix socket mode
|
||||
listen_directive="$FPM_LISTEN"
|
||||
listen_owner_block="listen.owner = apache
|
||||
listen.group = apache"
|
||||
else
|
||||
# TCP port mode
|
||||
listen_directive="0.0.0.0:${FPM_LISTEN}"
|
||||
listen_owner_block=""
|
||||
fi
|
||||
|
||||
cat <<EOF > /etc/php-fpm.d/$user.conf
|
||||
|
||||
[$user]
|
||||
|
||||
user = $user
|
||||
group = $user
|
||||
listen = /run/php-fpm/www.sock
|
||||
listen.owner = apache
|
||||
listen.group = apache
|
||||
listen = ${listen_directive}
|
||||
${listen_owner_block}
|
||||
|
||||
pm = ${PHP_FPM_PM}
|
||||
pm.max_children = ${PHP_FPM_MAX_CHILDREN}
|
||||
@@ -22,7 +35,12 @@ pm.start_servers = ${PHP_FPM_START_SERVERS}
|
||||
pm.min_spare_servers = ${PHP_FPM_MIN_SPARE}
|
||||
pm.max_spare_servers = ${PHP_FPM_MAX_SPARE}
|
||||
|
||||
slowlog = /etc/httpd/logs/error_log
|
||||
; Health check endpoints
|
||||
ping.path = /fpm-ping
|
||||
ping.response = pong
|
||||
pm.status_path = /fpm-status
|
||||
|
||||
slowlog = /home/$user/logs/php-fpm/slowlog
|
||||
request_slowlog_timeout = 3s
|
||||
|
||||
php_admin_value[error_log] = /home/$user/logs/php-fpm/error.log
|
||||
|
||||
@@ -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
|
||||
|
||||
86
scripts/entrypoint-fpm.sh
Executable file
86
scripts/entrypoint-fpm.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "$PHPVER" ]; then
|
||||
PHPVER="83";
|
||||
fi
|
||||
|
||||
if [ -z "$environment" ]; then
|
||||
environment="PROD"
|
||||
fi
|
||||
|
||||
# Default to FPM-only role
|
||||
export CONTAINER_ROLE="fpm_only"
|
||||
export FPM_LISTEN=${FPM_LISTEN:-9000}
|
||||
|
||||
adduser -u $uid $user
|
||||
|
||||
mkdir -p /home/$user/public_html
|
||||
mkdir -p /home/$user/logs/php-fpm
|
||||
|
||||
ln -sf /home/$user/logs/php-fpm /var/log/php-fpm
|
||||
|
||||
source /scripts/detect-memory.sh
|
||||
echo "Container memory: ${CONTAINER_MEMORY_MB}MB | PHP-FPM pm=${PHP_FPM_PM} max_children=${PHP_FPM_MAX_CHILDREN} | Listen=${FPM_LISTEN}"
|
||||
|
||||
/scripts/create-php-config.sh
|
||||
|
||||
mkdir -p /run/php-fpm/
|
||||
/usr/sbin/php-fpm -y /etc/php-fpm.conf
|
||||
chown -R $user:$user /home/$user
|
||||
chmod -R 755 /home/$user
|
||||
|
||||
if [[ $environment == 'DEV' ]]; then
|
||||
echo "Starting Dev Deployment (FPM-only mode)"
|
||||
mkdir -p /home/$user/_db_backups
|
||||
if ! command -v microdnf &> /dev/null; then
|
||||
echo "microdnf not found, installing with dnf..."
|
||||
dnf install -y microdnf && dnf clean all
|
||||
fi
|
||||
microdnf install -y MariaDB-server MariaDB-client memcached
|
||||
sed -r -i 's/session.save_path="memcache:11211/session.save_path="localhost:11211/' /etc/php.ini
|
||||
nohup mysqld -umysql &
|
||||
if [ ! -f /home/$user/mysql_creds ]; then
|
||||
echo "Give MySQL a chance to finish starting..."
|
||||
sleep 10
|
||||
mysql_user=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13 ; echo '')
|
||||
mysql_password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 18 ; echo '')
|
||||
mysql_db=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 6 ; echo '')
|
||||
mysql -e "CREATE DATABASE devdb_"$mysql_db";"
|
||||
mysql -e "CREATE USER '"$mysql_user"'@'localhost' IDENTIFIED BY '"$mysql_password"';"
|
||||
mysql -e "GRANT ALL PRIVILEGES ON *.* TO '"$mysql_user"'@'localhost' WITH GRANT OPTION;"
|
||||
mysql -e "FLUSH PRIVILEGES;"
|
||||
echo "# User crontab for $user" > /home/$user/crontab
|
||||
echo "*/15 * * * * /scripts/mysql-backup.sh $user devdb_$mysql_db" >> /home/$user/crontab
|
||||
chown $user:$user /home/$user/crontab
|
||||
echo "MySQL User: "$mysql_user > /home/$user/mysql_creds
|
||||
echo "MySQL Password: "$mysql_password >> /home/$user/mysql_creds
|
||||
echo "MySQL Database: devdb_"$mysql_db >> /home/$user/mysql_creds
|
||||
cat /home/$user/mysql_creds
|
||||
fi
|
||||
/usr/bin/memcached -d -u $user
|
||||
fi
|
||||
|
||||
if [[ $environment == 'PROD' ]]; then
|
||||
if [ -f /etc/php.d/50-memcached.ini ]; then
|
||||
sed -r -i 's/;session.save_path="localhost:11211/session.save_path="memcache:11211/' /etc/php.d/50-memcached.ini
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set up user crontab
|
||||
if [ ! -f /home/$user/crontab ]; then
|
||||
echo "# User crontab for $user" > /home/$user/crontab
|
||||
echo "# Add your cron jobs here" >> /home/$user/crontab
|
||||
echo "# Example: */5 * * * * /home/$user/scripts/my-script.sh" >> /home/$user/crontab
|
||||
chown $user:$user /home/$user/crontab
|
||||
fi
|
||||
|
||||
# Load user crontab
|
||||
crontab -u $user /home/$user/crontab
|
||||
|
||||
/usr/sbin/crond
|
||||
|
||||
# Tail PHP-FPM logs (becomes PID 1 process)
|
||||
touch /home/$user/logs/php-fpm/error.log
|
||||
tail -f /home/$user/logs/php-fpm/*
|
||||
|
||||
exit 0
|
||||
66
scripts/entrypoint-shared-httpd.sh
Executable file
66
scripts/entrypoint-shared-httpd.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
export CONTAINER_ROLE="httpd_only"
|
||||
|
||||
if [ -z "$environment" ]; then
|
||||
environment="PROD"
|
||||
fi
|
||||
|
||||
# Generate self-signed SSL cert if not already present
|
||||
if [ ! -f /etc/pki/tls/certs/localhost.crt ]; then
|
||||
openssl req -newkey rsa:2048 -nodes \
|
||||
-keyout /etc/pki/tls/private/localhost.key \
|
||||
-x509 -days 3650 -subj "/CN=localhost" \
|
||||
-out /etc/pki/tls/certs/localhost.crt
|
||||
fi
|
||||
|
||||
# Create log directory
|
||||
mkdir -p /var/log/httpd
|
||||
|
||||
# Remove default configs that conflict
|
||||
rm -f /etc/httpd/conf.d/userdir.conf
|
||||
|
||||
# Configure RemoteIP for Docker network
|
||||
docker_network=$(ip addr show | grep eth0 | grep inet | awk -F " " '{print $2}')
|
||||
if [ -n "$docker_network" ]; then
|
||||
echo "RemoteIPInternalProxy $docker_network" >> /etc/httpd/conf.d/remoteip.conf
|
||||
fi
|
||||
|
||||
# Detect memory and calculate Apache MPM tuning
|
||||
source /scripts/detect-memory.sh
|
||||
echo "Container memory: ${CONTAINER_MEMORY_MB}MB | Apache workers=${APACHE_MAX_REQUEST_WORKERS} | Role=${CONTAINER_ROLE}"
|
||||
|
||||
# Generate MPM tuning config
|
||||
/scripts/create-apache-mpm-config.sh
|
||||
|
||||
# Write SSL global config (matches standalone CAC behavior)
|
||||
cat <<'EOF' > /etc/httpd/conf.d/ssl-global.conf
|
||||
Listen 443 https
|
||||
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
|
||||
SSLSessionCache shmcb:/run/httpd/sslcache(512000)
|
||||
SSLSessionCacheTimeout 300
|
||||
SSLCryptoDevice builtin
|
||||
EOF
|
||||
|
||||
# Disable the default ssl.conf if present (we use per-vhost SSL)
|
||||
if [ -f /etc/httpd/conf.d/ssl.conf ]; then
|
||||
mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.bak
|
||||
fi
|
||||
|
||||
# Ensure vhosts directory exists and is included
|
||||
mkdir -p /etc/httpd/conf.d/vhosts
|
||||
if ! grep -q 'IncludeOptional conf.d/vhosts/' /etc/httpd/conf/httpd.conf; then
|
||||
echo 'IncludeOptional conf.d/vhosts/*.conf' >> /etc/httpd/conf/httpd.conf
|
||||
fi
|
||||
|
||||
# Start Apache
|
||||
/usr/sbin/httpd -k start
|
||||
|
||||
# Start cron for log rotation
|
||||
/usr/sbin/crond
|
||||
|
||||
# Tail Apache logs (becomes PID 1 process)
|
||||
touch /var/log/httpd/error_log
|
||||
tail -f /var/log/httpd/*
|
||||
|
||||
exit 0
|
||||
79
scripts/tune-mpm.sh
Executable file
79
scripts/tune-mpm.sh
Executable file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
# Hot-adjust Apache MPM Event settings and graceful reload.
|
||||
# Usage: tune-mpm.sh [--max-workers N] [--server-limit N] [--start-servers N]
|
||||
# [--min-spare-threads N] [--max-spare-threads N]
|
||||
# [--max-connections-per-child N]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Read current values from the config as defaults
|
||||
CONFIG_FILE="/etc/httpd/conf.d/mpm-tuning.conf"
|
||||
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo "Error: $CONFIG_FILE not found. Run detect-memory.sh first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse current values from config
|
||||
current_start=$(grep -oP 'StartServers\s+\K\d+' "$CONFIG_FILE" 2>/dev/null || echo "1")
|
||||
current_min_spare=$(grep -oP 'MinSpareThreads\s+\K\d+' "$CONFIG_FILE" 2>/dev/null || echo "5")
|
||||
current_max_spare=$(grep -oP 'MaxSpareThreads\s+\K\d+' "$CONFIG_FILE" 2>/dev/null || echo "15")
|
||||
current_max_workers=$(grep -oP 'MaxRequestWorkers\s+\K\d+' "$CONFIG_FILE" 2>/dev/null || echo "50")
|
||||
current_server_limit=$(grep -oP 'ServerLimit\s+\K\d+' "$CONFIG_FILE" 2>/dev/null || echo "2")
|
||||
current_max_conn=$(grep -oP 'MaxConnectionsPerChild\s+\K\d+' "$CONFIG_FILE" 2>/dev/null || echo "3000")
|
||||
|
||||
# Parse arguments
|
||||
START_SERVERS=$current_start
|
||||
MIN_SPARE_THREADS=$current_min_spare
|
||||
MAX_SPARE_THREADS=$current_max_spare
|
||||
MAX_REQUEST_WORKERS=$current_max_workers
|
||||
SERVER_LIMIT=$current_server_limit
|
||||
MAX_CONNECTIONS_PER_CHILD=$current_max_conn
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--max-workers) MAX_REQUEST_WORKERS="$2"; shift 2 ;;
|
||||
--server-limit) SERVER_LIMIT="$2"; shift 2 ;;
|
||||
--start-servers) START_SERVERS="$2"; shift 2 ;;
|
||||
--min-spare-threads) MIN_SPARE_THREADS="$2"; shift 2 ;;
|
||||
--max-spare-threads) MAX_SPARE_THREADS="$2"; shift 2 ;;
|
||||
--max-connections-per-child) MAX_CONNECTIONS_PER_CHILD="$2"; shift 2 ;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [--max-workers N] [--server-limit N] [--start-servers N]"
|
||||
echo " [--min-spare-threads N] [--max-spare-threads N]"
|
||||
echo " [--max-connections-per-child N]"
|
||||
echo ""
|
||||
echo "Current values:"
|
||||
echo " StartServers: $current_start"
|
||||
echo " MinSpareThreads: $current_min_spare"
|
||||
echo " MaxSpareThreads: $current_max_spare"
|
||||
echo " MaxRequestWorkers: $current_max_workers"
|
||||
echo " ServerLimit: $current_server_limit"
|
||||
echo " MaxConnectionsPerChild: $current_max_conn"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Write updated config
|
||||
cat <<EOF > "$CONFIG_FILE"
|
||||
<IfModule mpm_event_module>
|
||||
StartServers ${START_SERVERS}
|
||||
MinSpareThreads ${MIN_SPARE_THREADS}
|
||||
MaxSpareThreads ${MAX_SPARE_THREADS}
|
||||
ThreadLimit 64
|
||||
ThreadsPerChild 25
|
||||
MaxRequestWorkers ${MAX_REQUEST_WORKERS}
|
||||
ServerLimit ${SERVER_LIMIT}
|
||||
MaxConnectionsPerChild ${MAX_CONNECTIONS_PER_CHILD}
|
||||
</IfModule>
|
||||
EOF
|
||||
|
||||
echo "MPM config updated:"
|
||||
echo " StartServers=$START_SERVERS ServerLimit=$SERVER_LIMIT MaxRequestWorkers=$MAX_REQUEST_WORKERS"
|
||||
echo " MinSpareThreads=$MIN_SPARE_THREADS MaxSpareThreads=$MAX_SPARE_THREADS MaxConnectionsPerChild=$MAX_CONNECTIONS_PER_CHILD"
|
||||
|
||||
# Graceful reload
|
||||
/usr/sbin/httpd -k graceful
|
||||
echo "Apache graceful reload triggered."
|
||||
Reference in New Issue
Block a user