%20despu%C3%A9s%20del%20inicio%20de%20PHP-FPM%20en%20un%20solo%20contenedor%3F.png)
Tengo problemas al ejecutar Nginx+PHP-FPM en un solo contenedor en Cloud Run. Mi contenedor está basado en Alpine y gestiona el inicio de Nginx y PHP-FPM mediante Supervisor. En general, funciona bien, pero hay un corto período de tiempo entre el momento en que Nginx comienza a escuchar un puerto HTTP y el momento en que PHP-FPM se activa. Esto lleva a la aparición de errores HTTP 502 con el siguiente mensaje de registro:
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"
El problema aquí es que Cloud Run decide que el contenedor está listo para manejar solicitudes cuando abre el puerto 8080. Inmediatamente después de la apertura del puerto, Cloud Run envía una solicitud que siempre falla en el primer intento porque FPM aún no está listo. El mensaje de registro NOTICE: fpm is running, pid 4
aparece después de que la primera solicitud llega y falla.
¿Cómo administrar Nginx para que abra su puerto solo cuando PHP-FPM esté listo?
Configuración del supervisor:
[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
Configuración de Nginx:
# 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;
}
}
He habilitado las páginas de estado/ping de FPM. ¿Puedo usarlos para activar la apertura del puerto Nginx?
Actualización 1:
Intenté ajustar las prioridades del supervisor y comenzar en segundo lugar:
...
[program:php-fpm]
...
priority=100
startsecs=3
[program:nginx]
...
priority=200
Pero sin éxito:
[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
Supervisord aún inicia ambas aplicaciones simultáneamente y nginx se inicializa primero. El RUNNING
estado que aplica Supervisord a las aplicaciones no significa nada para Cloud Run.
Respuesta1
Por ahora, terminé con el siguiente script de punto de entrada que garantiza que PHP-FPM se esté ejecutando antes de iniciar nginx:
#!/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
El apk add fcgi
comando es obligatorio (como para Alpine Linux).
También supongo que el php-fpm -D
comando siempre sale después de que FPM esté listo, por lo que no se requieren bucles, simplemente ejecute los comandos uno tras otro. Pero no lo he probado.
Respuesta2
Al supervisor realmente le vendría bien una startdelay
opción, pero actualmente no la tiene. Para retrasar el inicio de nginx, cambie el comando especificado a Supervisor (hilo relacionado):
Ejecute un shell para dormir y luego inicie nginx directamente:
[program:nginx] command=bash -c "sleep 5 && exec nginx -g 'daemon off;'" ...
Ejecute un script que duerme antes de iniciar nginx:
[program:nginx] command=delayed-nginx.sh ...
delayed-nginx.sh
:#!/bin/bash sleep 5 exec nginx -g 'daemon off;'
Respuesta original
No he usado Supervisor específicamente, peroesta respuestapodría funcionar para usted. Esto hará que Supervisor inicie nginx solo una vez php-fpm
que se esté ejecutando.
[program:php-fpm]
command=php-fpm -F
...
priority=100
[program:nginx]
command=nginx -g 'daemon off;'
...
priority=200
También es posible que deba establecer startsecs
un valor más alto (que el valor predeterminado de 1 segundo) para que Supervisor solo considere php-fpm
que se inició después de haber estado ejecutándose durante un tiempo más largo, por ejemplo, 5 segundos:
[program:php-fpm]
command=php-fpm -F
...
priority=100
startsecs=5