fix and update

This commit is contained in:
lendry
2026-06-30 10:05:57 +03:00
parent 4e98f6bfab
commit a76997986a

View File

@@ -373,6 +373,31 @@ reload_docker_nginx() {
fi fi
} }
# Ждёт HTTP /health на опубликованном порту api-gateway (127.0.0.1:3000).
wait_for_api_gateway_http() {
local max_attempts="${1:-60}"
local attempt=0
while [[ $attempt -lt $max_attempts ]]; do
if curl -fsS --max-time 3 http://127.0.0.1:3000/health 2>/dev/null | grep -q '"status"'; then
return 0
fi
attempt=$((attempt + 1))
sleep 2
done
return 1
}
# После recreate api-gateway nginx должен сбросить DNS/keepalive — иначе 502 на старый IP.
sync_nginx_after_api_gateway_restart() {
docker_nginx_container_running || return 0
log "Синхронизация Docker Nginx с api-gateway после пересборки..."
wait_for_service "api-gateway" 120 || warn "api-gateway не стал healthy в срок"
wait_for_api_gateway_http 90 || warn "api-gateway /health на :3000 не отвечает"
sleep 2
reload_docker_nginx
verify_nginx_reaches_api_gateway 24 5 || warn "Nginx → api-gateway: проверка не прошла, см. docker compose logs nginx api-gateway"
}
recreate_docker_nginx() { recreate_docker_nginx() {
compose_uses_proxy_profile || return 0 compose_uses_proxy_profile || return 0
build_compose_stack_cmd build_compose_stack_cmd
@@ -702,6 +727,17 @@ compose_build_and_up() {
if [[ "${SKIP_DOCKER_PRUNE:-0}" -ne 1 ]]; then if [[ "${SKIP_DOCKER_PRUNE:-0}" -ne 1 ]]; then
docker_prune_after_rebuild docker_prune_after_rebuild
fi fi
local svc
for svc in "${services[@]}"; do
case "$svc" in
api-gateway) sync_nginx_after_api_gateway_restart ;;
media-ws)
wait_for_service "media-ws" 60
reload_docker_nginx
;;
esac
done
} }
action_docker_prune() { action_docker_prune() {
@@ -1944,10 +1980,12 @@ nginx_proxy_headers=" proxy_set_header Host \$host;
proxy_read_timeout 300s; proxy_read_timeout 300s;
proxy_connect_timeout 75s;" proxy_connect_timeout 75s;"
# Встроенный DNS Docker. В docker-режиме nginx обязан перерезолвлять имена # Встроенный DNS Docker. valid=5s + resolver_timeout — баланс между свежим IP и
# бэкенд-контейнеров на каждый запрос — иначе после пересборки контейнера # «Server failure» при кратковременном дауне контейнера во время recreate.
# (новый IP) остаётся закешированный старый адрес и все ответы становятся 502. NGINX_DOCKER_RESOLVER=" resolver 127.0.0.11 ipv6=off valid=5s;
NGINX_DOCKER_RESOLVER=" resolver 127.0.0.11 ipv6=off valid=1s;" resolver_timeout 5s;"
NGINX_DOCKER_SERVER_DNS=" resolver 127.0.0.11 ipv6=off valid=5s;
resolver_timeout 5s;"
# Имя nginx-переменной из ключа апстрима (только [A-Za-z0-9_]). # Имя nginx-переменной из ключа апстрима (только [A-Za-z0-9_]).
nginx_upstream_var() { nginx_upstream_var() {
@@ -2214,14 +2252,19 @@ ${nginx_proxy_headers}
EOF EOF
} }
nginx_docker_server_dns_block() {
[[ "$NGINX_MODE" == "docker" ]] && echo "$NGINX_DOCKER_SERVER_DNS" || true
}
write_nginx_site_frontend() { write_nginx_site_frontend() {
local domain="$1" local domain="$1"
local ssl_type="${2:-none}" local ssl_type="${2:-none}"
local conf http_preamble ssl_block idp_api_block proxy_root local conf http_preamble ssl_block idp_api_block proxy_root server_dns
conf="$(nginx_conf_target frontend)" conf="$(nginx_conf_target frontend)"
proxy_root="$(render_proxy_root frontend)" proxy_root="$(render_proxy_root frontend)"
http_preamble="$(nginx_http_server_preamble "$domain" "$ssl_type")" http_preamble="$(nginx_http_server_preamble "$domain" "$ssl_type")"
idp_api_block="$(build_nginx_idp_api_proxy_block)" idp_api_block="$(build_nginx_idp_api_proxy_block)"
server_dns="$(nginx_docker_server_dns_block)"
if [[ "$ssl_type" == "none" ]]; then if [[ "$ssl_type" == "none" ]]; then
nginx_write_conf "$conf" <<EOF nginx_write_conf "$conf" <<EOF
@@ -2229,6 +2272,7 @@ server {
listen 80; listen 80;
listen [::]:80; listen [::]:80;
server_name ${domain}; server_name ${domain};
${server_dns}
${idp_api_block} ${idp_api_block}
location / { location / {
${proxy_root} ${proxy_root}
@@ -2246,6 +2290,7 @@ ${http_preamble}server {
server_name ${domain}; server_name ${domain};
${ssl_block} ${ssl_block}
client_max_body_size 50m; client_max_body_size 50m;
${server_dns}
${idp_api_block} ${idp_api_block}
location / { location / {
${proxy_root} ${proxy_root}
@@ -2266,11 +2311,12 @@ EOF
write_nginx_site_fedcm_apex() { write_nginx_site_fedcm_apex() {
local domain="$1" local domain="$1"
local ssl_type="${2:-none}" local ssl_type="${2:-none}"
local conf http_preamble ssl_block idp_api_block proxy_root local conf http_preamble ssl_block idp_api_block proxy_root server_dns
conf="$(nginx_conf_target fedcm-apex)" conf="$(nginx_conf_target fedcm-apex)"
proxy_root="$(render_proxy_root frontend)" proxy_root="$(render_proxy_root frontend)"
http_preamble="$(nginx_http_server_preamble "$domain" "$ssl_type")" http_preamble="$(nginx_http_server_preamble "$domain" "$ssl_type")"
idp_api_block="$(build_nginx_idp_api_proxy_block)" idp_api_block="$(build_nginx_idp_api_proxy_block)"
server_dns="$(nginx_docker_server_dns_block)"
if [[ "$ssl_type" == "none" ]]; then if [[ "$ssl_type" == "none" ]]; then
nginx_write_conf "$conf" <<EOF nginx_write_conf "$conf" <<EOF
@@ -2279,6 +2325,7 @@ server {
listen [::]:80; listen [::]:80;
server_name ${domain}; server_name ${domain};
client_max_body_size 50m; client_max_body_size 50m;
${server_dns}
${idp_api_block} ${idp_api_block}
location / { location / {
${proxy_root} ${proxy_root}
@@ -2296,6 +2343,7 @@ ${http_preamble}server {
server_name ${domain}; server_name ${domain};
${ssl_block} ${ssl_block}
client_max_body_size 50m; client_max_body_size 50m;
${server_dns}
${idp_api_block} ${idp_api_block}
location / { location / {
${proxy_root} ${proxy_root}
@@ -2516,7 +2564,12 @@ validate_docker_frontend_nginx_config() {
verify_nginx_reaches_api_gateway() { verify_nginx_reaches_api_gateway() {
docker_nginx_container_running || return 0 docker_nginx_container_running || return 0
build_compose_stack_cmd build_compose_stack_cmd
local max_attempts="${1:-1}"
local delay_sec="${2:-0}"
local attempt=0
local body gw_ip local body gw_ip
while [[ $attempt -lt $max_attempts ]]; do
gw_ip="$(docker_cmd inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' lendry-id-api-gateway 2>/dev/null || true)" gw_ip="$(docker_cmd inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' lendry-id-api-gateway 2>/dev/null || true)"
body="$(docker_cmd "${COMPOSE_STACK_CMD[@]}" exec -T nginx \ body="$(docker_cmd "${COMPOSE_STACK_CMD[@]}" exec -T nginx \
wget -qO- --timeout=5 http://lendry-id-api-gateway:3000/health 2>/dev/null || true)" wget -qO- --timeout=5 http://lendry-id-api-gateway:3000/health 2>/dev/null || true)"
@@ -2524,7 +2577,13 @@ verify_nginx_reaches_api_gateway() {
ok "Docker Nginx → lendry-id-api-gateway:3000/health OK (IP api-gateway: ${gw_ip:-?})" ok "Docker Nginx → lendry-id-api-gateway:3000/health OK (IP api-gateway: ${gw_ip:-?})"
return 0 return 0
fi fi
warn "Docker Nginx не достучался до lendry-id-api-gateway:3000 (IP: ${gw_ip:-?})" attempt=$((attempt + 1))
if [[ $attempt -lt $max_attempts ]]; then
[[ "$delay_sec" -gt 0 ]] && sleep "$delay_sec"
fi
done
warn "Docker Nginx не достучался до lendry-id-api-gateway:3000 (IP: ${gw_ip:-?}, попыток: ${max_attempts})"
warn "Проверьте: docker compose ps api-gateway && docker compose logs --tail=40 api-gateway" warn "Проверьте: docker compose ps api-gateway && docker compose logs --tail=40 api-gateway"
return 1 return 1
} }
@@ -2786,6 +2845,7 @@ deploy_stack() {
wait_for_service "sso-core" 120 wait_for_service "sso-core" 120
wait_for_service "api-gateway" 90 wait_for_service "api-gateway" 90
sync_nginx_after_api_gateway_restart
wait_for_service "frontend" 60 wait_for_service "frontend" 60
wait_for_service "docs" 60 wait_for_service "docs" 60
if compose_uses_proxy_profile; then if compose_uses_proxy_profile; then
@@ -3345,6 +3405,7 @@ action_fix_host_proxy() {
compose_build_and_up api-gateway compose_build_and_up api-gateway
wait_for_service "api-gateway" 90 wait_for_service "api-gateway" 90
wait_for_api_grpc_ready 60 || true wait_for_api_grpc_ready 60 || true
sync_nginx_after_api_gateway_restart
ok "Прокси исправлен — проверьте: curl -I http://127.0.0.1:3002" ok "Прокси исправлен — проверьте: curl -I http://127.0.0.1:3002"
diagnose_common_issues || true diagnose_common_issues || true
@@ -3379,6 +3440,7 @@ action_fix_all_errors() {
compose_build_and_up api-gateway compose_build_and_up api-gateway
wait_for_service "api-gateway" 90 wait_for_service "api-gateway" 90
wait_for_api_grpc_ready 90 || compose_build_and_up api-gateway wait_for_api_grpc_ready 90 || compose_build_and_up api-gateway
sync_nginx_after_api_gateway_restart
log "Шаг 4/6: пересборка frontend (same-origin /idp-api), docs, media-ws..." log "Шаг 4/6: пересборка frontend (same-origin /idp-api), docs, media-ws..."
compose_build_and_up frontend docs media-ws compose_build_and_up frontend docs media-ws
@@ -3407,10 +3469,12 @@ action_fix_all_errors() {
esac esac
apply_intranet_selfsigned_runtime apply_intranet_selfsigned_runtime
recreate_docker_nginx recreate_docker_nginx
verify_nginx_reaches_api_gateway || compose_build_and_up api-gateway sync_nginx_after_api_gateway_restart
verify_nginx_reaches_api_gateway 24 5 || compose_build_and_up api-gateway
sync_nginx_after_api_gateway_restart
verify_nginx_reaches_media_ws || compose_build_and_up media-ws verify_nginx_reaches_media_ws || compose_build_and_up media-ws
recreate_docker_nginx reload_docker_nginx
verify_nginx_reaches_api_gateway || fail "Nginx не проксирует на api-gateway — см. docker compose logs nginx api-gateway" verify_nginx_reaches_api_gateway 24 5 || fail "Nginx не проксирует на api-gateway — см. docker compose logs nginx api-gateway"
check_sso_idp_api_proxy || fail "SSO /idp-api/health недоступен — см. nginx/conf.d/${NGINX_PREFIX}-frontend.conf" check_sso_idp_api_proxy || fail "SSO /idp-api/health недоступен — см. nginx/conf.d/${NGINX_PREFIX}-frontend.conf"
if ! docker_nginx_container_running; then if ! docker_nginx_container_running; then
fail "Контейнер lendry-id-nginx не запущен. Проверьте: docker compose --profile proxy logs nginx" fail "Контейнер lendry-id-nginx не запущен. Проверьте: docker compose --profile proxy logs nginx"