%20nach%20dem%20Start%20von%20PHP-FPM%20in%20einem%20einzelnen%20Container%3F.png)
Ich habe Probleme, Nginx+PHP-FPM in einem einzigen Container auf Cloud Run auszuführen. Mein Container basiert auf Alpine und verwaltet den Start von Nginx und PHP-FPM per Supervisor. Insgesamt funktioniert es gut, aber es gibt eine kurze Zeitspanne zwischen dem Zeitpunkt, an dem Nginx beginnt, einen HTTP-Port abzuhören, und dem Zeitpunkt, an dem PHP-FPM hochfährt. Dies führt zum Auftreten von 502-HTTP-Fehlern mit der folgenden Protokollmeldung:
6#6: *3 connect() failed (111: Connection refused) while connecting to upstream, client: 169.254.8.129, server: _, request: "POST / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000"
Das Problem hierbei ist, dass Cloud Run entscheidet, dass der Container bereit ist, Anfragen zu verarbeiten, wenn er den Port 8080 öffnet. Unmittelbar nach dem Öffnen des Ports sendet Cloud Run eine Anfrage, die beim ersten Versuch immer fehlschlägt, da FPM noch nicht bereit ist. Die Protokollnachricht NOTICE: fpm is running, pid 4
wird angezeigt, nachdem die erste Anfrage eingetroffen und fehlgeschlagen ist.
Wie kann man Nginx so verwalten, dass sein Port nur geöffnet wird, wenn PHP-FPM bereit ist?
Supervisor-Konfiguration:
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
[program:php-fpm]
command=php-fpm -F
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=false
startretries=0
[program:nginx]
command=nginx -g 'daemon off;'
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=false
startretries=0
Nginx-Konfiguration:
# Write temporary files to /tmp so they can be created as a non-privileged user
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
access_log /dev/stdout;
error_log /dev/stderr notice;
server {
listen 8080 default_server;
index index.php;
keepalive_requests 10;
keepalive_timeout 60 60;
root /var/www/html/app/public;
charset utf-8;
server_name _;
# Deny hidden files (.htaccess, .htpasswd, .DS_Store).
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
########################
# mappings #
########################
location ~ \.(js|css|png|jpg|ico) {
expires 5d;
try_files $uri $uri/ =404;
return 404;
}
# Allow fpm ping and status from localhost
location ~ ^/(fpm-status|fpm-ping)$ {
access_log off;
allow 127.0.0.1;
deny all;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
}
location / {
client_max_body_size 100m;
try_files $uri @fpm;
}
location @fpm {
# worker may take long time to finish (max 1 hour)
fastcgi_read_timeout 3600s;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param HTTP_PROXY "";
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html/app/public/index.php;
fastcgi_param SCRIPT_NAME index.php;
}
}
Ich habe FPM-Ping-/Statusseiten aktiviert. Kann ich sie verwenden, um das Öffnen des Nginx-Ports auszulösen?
Aktualisierung 1:
Ich habe versucht, die Supervisor-Prioritäten und Startsekunden anzupassen:
...
[program:php-fpm]
...
priority=100
startsecs=3
[program:nginx]
...
priority=200
Aber ohne Erfolg:
[18-Dec-2020 00:31:04] NOTICE: ready to handle connections
[18-Dec-2020 00:31:04] NOTICE: fpm is running, pid 3
2020-12-18 00:30:30,689 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 3 seconds (startsecs)
2020-12-18 00:30:28,388 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
Error POST 502 549 B 3.286 s Google-Cloud-Scheduler https://***.run.app/
169.254.8.129 - - [18/Dec/2020:00:30:27 +0000] "POST / HTTP/1.1" 502 150 "-" "Google-Cloud-Scheduler"
169.254.8.129 - - [18/Dec/2020:00:30:27 +0000] "POST / HTTP/1.1" 502 150 "-" "Google-Cloud-Scheduler" "35.187.131.214"
2020/12/18 00:30:27 [error] 6#6: *3 connect() failed (111: Connection refused) while connecting to upstream, client: 169.254.8.129, server: _, request: "POST / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "***.run.app"
2020-12-18 00:30:26,937 INFO spawned: 'nginx' with pid 4
2020-12-18 00:30:26,829 INFO spawned: 'php-fpm' with pid 3
2020-12-18 00:30:25,730 INFO supervisord started with pid 1
2020-12-18 00:30:25,704 CRIT Supervisor is running as root. Privileges were not dropped because no user
Beide Apps werden immer noch gleichzeitig von Supervisord gestartet und nginx wird zuerst initialisiert. Der RUNNING
Status, den Supervisord auf Apps anwendet, hat für Cloud Run keine Bedeutung.
Antwort1
Vorerst bin ich beim folgenden Entrypoint-Skript gelandet, das sicherstellt, dass PHP-FPM ausgeführt wird, bevor nginx gestartet wird:
#!/usr/bin/env sh
set -e
# Start PHP-FPM as a daemon in the background
php-fpm -D
# Wait until PHP-FPM is up and accepts connections. Fail if not started in 10 secs.
for run in $(seq 20)
do
if [ "$run" -gt "1" ]; then
echo "Retrying..."
fi
RESPONSE=$(
SCRIPT_NAME=/fpm-ping \
SCRIPT_FILENAME=/fpm-ping \
REQUEST_METHOD=GET \
cgi-fcgi -bind -connect 127.0.0.1:9000 || true)
case $RESPONSE in
*"pong"*)
echo "FPM is running and ready. Starting nginx."
# Run nginx without exiting to keep the container running
nginx -g 'daemon off;'
exit 0
;;
esac
sleep .5
done
echo "FPM has failed to start on-time, exiting"
exit 1
Der apk add fcgi
Befehl ist erforderlich (wie für Alpine Linux).
Ich gehe auch davon aus, dass der php-fpm -D
Befehl immer beendet wird, nachdem FPM bereit ist, sodass keine Schleifen erforderlich sind, sondern die Befehle einfach nacheinander ausgeführt werden. Aber ich habe es nicht getestet.
Antwort2
Supervisor könnte wirklich eine startdelay
Option gebrauchen, hat aber derzeit keine. Um den Start von nginx zu verzögern, ändern Sie stattdessen den angegebenen Befehl in Supervisor (Verwandter Thread):
Führen Sie eine Shell aus, um den Ruhezustand zu versetzen, und starten Sie dann nginx direkt:
[program:nginx] command=bash -c "sleep 5 && exec nginx -g 'daemon off;'" ...
Führen Sie ein Skript aus, das vor dem Starten von nginx in den Ruhezustand wechselt:
[program:nginx] command=delayed-nginx.sh ...
delayed-nginx.sh
:#!/bin/bash sleep 5 exec nginx -g 'daemon off;'
Ursprüngliche Antwort
Ich habe Supervisor nicht speziell verwendet, aberdiese Antwortkönnte für Sie funktionieren. Dadurch startet Supervisor nginx nur, wenn php-fpm
es ausgeführt wird.
[program:php-fpm]
command=php-fpm -F
...
priority=100
[program:nginx]
command=nginx -g 'daemon off;'
...
priority=200
Sie müssen möglicherweise auch startsecs
einen höheren Wert (als den Standardwert von 1 Sekunde) einstellen, damit Supervisor erst php-fpm
dann als gestartet gilt, wenn er bereits für eine längere Zeit ausgeführt wurde, z. B. 5 Sekunden:
[program:php-fpm]
command=php-fpm -F
...
priority=100
startsecs=5
Weitere Informationen finden Sie in der Supervisor-Dokumentation.