fix and update
This commit is contained in:
@@ -1,52 +1,72 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# После recreate api-gateway Docker выдаёт новый IP; без reload nginx шлёт на старый адрес → 502.
|
# После recreate edge-сервисов Docker выдаёт новый IP; без reload nginx шлёт на старый адрес → 502.
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
GW_HOST="${IDP_API_GATEWAY_HOST:-lendry-id-api-gateway}"
|
|
||||||
GW_PORT="${IDP_API_GATEWAY_PORT:-3000}"
|
|
||||||
WATCH_INTERVAL="${IDP_NGINX_WATCH_INTERVAL:-5}"
|
WATCH_INTERVAL="${IDP_NGINX_WATCH_INTERVAL:-5}"
|
||||||
|
|
||||||
|
WATCH_HOSTS="${IDP_NGINX_WATCH_HOSTS:-lendry-id-api-gateway:3000/health lendry-id-frontend:3000/}"
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
echo "[idp-nginx-watch] $*"
|
echo "[idp-nginx-watch] $*"
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_for_gateway() {
|
probe_url() {
|
||||||
|
target="$1"
|
||||||
|
host="${target%%:*}"
|
||||||
|
rest="${target#*:}"
|
||||||
|
port="${rest%%/*}"
|
||||||
|
path="/${rest#*/}"
|
||||||
|
[ "$path" = "/${rest}" ] && path="/"
|
||||||
|
wget -qO- --timeout=3 "http://${host}:${port}${path}" 2>/dev/null | head -c 64 | grep -q .
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_upstreams() {
|
||||||
attempt=0
|
attempt=0
|
||||||
while [ "$attempt" -lt 120 ]; do
|
while [ "$attempt" -lt 120 ]; do
|
||||||
if wget -qO- --timeout=3 "http://${GW_HOST}:${GW_PORT}/health" 2>/dev/null | grep -q '"status"'; then
|
ok=1
|
||||||
log "api-gateway доступен (${GW_HOST}:${GW_PORT})"
|
for target in $WATCH_HOSTS; do
|
||||||
|
if ! probe_url "$target"; then
|
||||||
|
ok=0
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$ok" -eq 1 ]; then
|
||||||
|
log "upstream-ы доступны"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
attempt=$((attempt + 1))
|
attempt=$((attempt + 1))
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
log "WARN: api-gateway не ответил за 120с — nginx стартует без ожидания"
|
log "WARN: не все upstream-ы ответили за 120с — nginx стартует без ожидания"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
watch_gateway() {
|
watch_upstreams() {
|
||||||
last_ip=""
|
last_ips=""
|
||||||
while true; do
|
while true; do
|
||||||
sleep "$WATCH_INTERVAL"
|
sleep "$WATCH_INTERVAL"
|
||||||
current_ip="$(getent hosts "$GW_HOST" 2>/dev/null | awk '{print $1}' | head -n1 || true)"
|
reload=0
|
||||||
healthy=0
|
current_ips=""
|
||||||
if wget -qO- --timeout=3 "http://${GW_HOST}:${GW_PORT}/health" 2>/dev/null | grep -q '"status"'; then
|
for target in $WATCH_HOSTS; do
|
||||||
healthy=1
|
host="${target%%:*}"
|
||||||
|
ip="$(getent hosts "$host" 2>/dev/null | awk '{print $1}' | head -n1 || true)"
|
||||||
|
current_ips="${current_ips}${host}=${ip};"
|
||||||
|
if ! probe_url "$target"; then
|
||||||
|
log "${host} недоступен — reload nginx"
|
||||||
|
reload=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$reload" -eq 0 ] && [ -n "$last_ips" ] && [ "$current_ips" != "$last_ips" ]; then
|
||||||
|
log "IP upstream изменился — reload nginx"
|
||||||
|
reload=1
|
||||||
fi
|
fi
|
||||||
if [ "$healthy" -eq 0 ]; then
|
if [ "$reload" -eq 1 ]; then
|
||||||
log "api-gateway недоступен — reload nginx"
|
|
||||||
nginx -s reload 2>/dev/null || true
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ -n "$current_ip" ] && [ -n "$last_ip" ] && [ "$current_ip" != "$last_ip" ]; then
|
|
||||||
log "IP ${GW_HOST} изменился (${last_ip} → ${current_ip}) — reload nginx"
|
|
||||||
nginx -s reload 2>/dev/null || true
|
nginx -s reload 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
if [ -n "$current_ip" ]; then
|
last_ips="$current_ips"
|
||||||
last_ip="$current_ip"
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_for_gateway
|
wait_for_upstreams
|
||||||
watch_gateway &
|
watch_upstreams &
|
||||||
|
|||||||
132
install.sh
132
install.sh
@@ -426,6 +426,20 @@ sync_nginx_after_api_gateway_restart() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# После recreate frontend/docs nginx должен перерезолвить lendry-id-frontend — иначе 502 на / (корень SSO).
|
||||||
|
sync_nginx_after_edge_restart() {
|
||||||
|
docker_nginx_container_running || return 0
|
||||||
|
log "Синхронизация Docker Nginx с frontend после пересборки..."
|
||||||
|
wait_for_service "frontend" 120 || warn "frontend не стал healthy в срок"
|
||||||
|
sleep 2
|
||||||
|
reload_docker_nginx
|
||||||
|
if ! verify_nginx_reaches_frontend 12 3; then
|
||||||
|
warn "Nginx → frontend: reload не помог — пересоздаём lendry-id-nginx..."
|
||||||
|
recreate_docker_nginx
|
||||||
|
verify_nginx_reaches_frontend 12 3 || warn "Nginx → frontend: проверка не прошла, см. docker compose logs nginx frontend"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
recreate_docker_nginx() {
|
recreate_docker_nginx() {
|
||||||
compose_uses_proxy_profile || return 0
|
compose_uses_proxy_profile || return 0
|
||||||
ensure_nginx_gateway_watch_script
|
ensure_nginx_gateway_watch_script
|
||||||
@@ -483,11 +497,19 @@ post_deploy_proxy_verify() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
verify_nginx_reaches_media_ws || true
|
verify_nginx_reaches_media_ws || true
|
||||||
|
verify_nginx_reaches_frontend 12 3 || {
|
||||||
|
[[ "$strict" -eq 1 ]] && fail "Docker Nginx не проксирует / на frontend — см. docker compose logs nginx frontend"
|
||||||
|
warn "Nginx → frontend: проверка не прошла"
|
||||||
|
}
|
||||||
if [[ "$(env_get USE_NGINX_SSL false)" == "true" ]]; then
|
if [[ "$(env_get USE_NGINX_SSL false)" == "true" ]]; then
|
||||||
check_sso_idp_api_proxy || {
|
check_sso_idp_api_proxy || {
|
||||||
[[ "$strict" -eq 1 ]] && fail "SSO /idp-api/health → 502. Выполните: ./install.sh --fix-all"
|
[[ "$strict" -eq 1 ]] && fail "SSO /idp-api/health → 502. Выполните: ./install.sh --fix-all"
|
||||||
warn "SSO /idp-api/health не прошёл — выполните ./install.sh --fix-all"
|
warn "SSO /idp-api/health не прошёл — выполните ./install.sh --fix-all"
|
||||||
}
|
}
|
||||||
|
check_sso_frontend_root || {
|
||||||
|
[[ "$strict" -eq 1 ]] && fail "SSO / → 502. Nginx не проксирует главную на frontend. Выполните: ./install.sh --fix-all"
|
||||||
|
warn "SSO / (главная) не прошла — выполните ./install.sh --fix-all"
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,6 +866,10 @@ compose_build_and_up() {
|
|||||||
for svc in "${services[@]}"; do
|
for svc in "${services[@]}"; do
|
||||||
case "$svc" in
|
case "$svc" in
|
||||||
api-gateway) sync_nginx_after_api_gateway_restart ;;
|
api-gateway) sync_nginx_after_api_gateway_restart ;;
|
||||||
|
frontend|docs)
|
||||||
|
wait_for_service "$svc" 90
|
||||||
|
sync_nginx_after_edge_restart
|
||||||
|
;;
|
||||||
media-ws)
|
media-ws)
|
||||||
wait_for_service "media-ws" 60
|
wait_for_service "media-ws" 60
|
||||||
reload_docker_nginx
|
reload_docker_nginx
|
||||||
@@ -2716,6 +2742,96 @@ verify_nginx_idp_api_location() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verify_nginx_reaches_frontend() {
|
||||||
|
docker_nginx_container_running || return 0
|
||||||
|
build_compose_stack_cmd
|
||||||
|
load_env
|
||||||
|
local max_attempts="${1:-1}"
|
||||||
|
local delay_sec="${2:-0}"
|
||||||
|
local attempt=0
|
||||||
|
local body fe_ip frontend_domain code
|
||||||
|
|
||||||
|
frontend_domain="$(env_get DOMAIN_FRONTEND "")"
|
||||||
|
|
||||||
|
while [[ $attempt -lt $max_attempts ]]; do
|
||||||
|
fe_ip="$(docker_cmd inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' lendry-id-frontend 2>/dev/null || true)"
|
||||||
|
body="$(docker_cmd "${COMPOSE_STACK_CMD[@]}" exec -T nginx \
|
||||||
|
wget -qO- --timeout=6 http://lendry-id-frontend:3000/ 2>/dev/null | head -c 256 || true)"
|
||||||
|
if [[ -n "$body" ]]; then
|
||||||
|
ok "Docker Nginx → lendry-id-frontend:3000/ OK (IP frontend: ${fe_ip:-?})"
|
||||||
|
if [[ -n "$frontend_domain" ]]; then
|
||||||
|
verify_nginx_frontend_root_location "$frontend_domain" || return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
if [[ $attempt -lt $max_attempts ]]; then
|
||||||
|
[[ "$delay_sec" -gt 0 ]] && sleep "$delay_sec"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
warn "Docker Nginx не достучался до lendry-id-frontend:3000/ (IP: ${fe_ip:-?}, попыток: ${max_attempts})"
|
||||||
|
warn "Проверьте: docker compose --env-file .env --profile proxy logs --tail=40 frontend nginx"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# location / → frontend (путь браузера на https://sso.../)
|
||||||
|
verify_nginx_frontend_root_location() {
|
||||||
|
local frontend_domain="$1"
|
||||||
|
local body code ssl_type
|
||||||
|
ssl_type="$(env_get SSL_TYPE none)"
|
||||||
|
|
||||||
|
body="$(docker_cmd "${COMPOSE_STACK_CMD[@]}" exec -T nginx \
|
||||||
|
wget -qO- --timeout=8 --no-check-certificate \
|
||||||
|
--header="Host: ${frontend_domain}" \
|
||||||
|
"https://127.0.0.1/" 2>/dev/null | head -c 256 || true)"
|
||||||
|
if [[ -n "$body" ]]; then
|
||||||
|
ok "Docker Nginx location / → frontend OK (Host: ${frontend_domain})"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$(env_get USE_NGINX_SSL false)" == "true" || "$ssl_type" != "none" ]]; then
|
||||||
|
code="$(curl -sk --max-time 8 -o /dev/null -w '%{http_code}' "https://${frontend_domain}/" 2>/dev/null || echo 000)"
|
||||||
|
else
|
||||||
|
code="$(curl -fsS --max-time 8 -o /dev/null -w '%{http_code}' "http://${frontend_domain}/" 2>/dev/null || echo 000)"
|
||||||
|
fi
|
||||||
|
if [[ "$code" == "200" || "$code" == "304" ]]; then
|
||||||
|
ok "SSO / → HTTP ${code} (проверка с хоста)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
warn "Nginx location / не проксирует на frontend (Host: ${frontend_domain}, HTTP ${code:-?})"
|
||||||
|
warn "Проверьте: curl -sk -o /dev/null -w '%{http_code}' https://${frontend_domain}/"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_sso_frontend_root() {
|
||||||
|
load_env
|
||||||
|
local frontend_domain code ssl_type
|
||||||
|
frontend_domain="$(env_get DOMAIN_FRONTEND "")"
|
||||||
|
[[ -n "$frontend_domain" ]] || return 0
|
||||||
|
ssl_type="$(env_get SSL_TYPE none)"
|
||||||
|
|
||||||
|
if [[ "$(env_get USE_NGINX_SSL false)" == "true" || "$ssl_type" != "none" ]]; then
|
||||||
|
code="$(curl -sk --max-time 8 -o /dev/null -w '%{http_code}' "https://${frontend_domain}/" 2>/dev/null || echo 000)"
|
||||||
|
else
|
||||||
|
code="$(curl -fsS --max-time 8 -o /dev/null -w '%{http_code}' "http://${frontend_domain}/" 2>/dev/null || echo 000)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$code" == "200" || "$code" == "304" ]]; then
|
||||||
|
echo -e " ${GREEN}✔${NC} SSO / → ${code} (главная страница SPA)"
|
||||||
|
return 0
|
||||||
|
elif [[ "$code" == "502" ]]; then
|
||||||
|
echo -e " ${RED}✘${NC} SSO / → 502 — Nginx не проксирует / на frontend (502 Bad Gateway в браузере)"
|
||||||
|
echo " Проверьте: docker compose --env-file .env --profile proxy exec nginx wget -qO- http://lendry-id-frontend:3000/"
|
||||||
|
echo " Решение: docker compose --env-file .env --profile proxy restart nginx frontend"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
echo -e " ${YELLOW}!${NC} SSO / → HTTP ${code} (ожидалось 200)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
verify_nginx_reaches_media_ws() {
|
verify_nginx_reaches_media_ws() {
|
||||||
docker_nginx_container_running || return 0
|
docker_nginx_container_running || return 0
|
||||||
build_compose_stack_cmd
|
build_compose_stack_cmd
|
||||||
@@ -3205,10 +3321,14 @@ diagnose_common_issues() {
|
|||||||
echo -e " ${RED}✘${NC} Конфликт: системный Nginx на 80/443 и lendry-id-nginx одновременно — браузер может ходить не туда (502)"
|
echo -e " ${RED}✘${NC} Конфликт: системный Nginx на 80/443 и lendry-id-nginx одновременно — браузер может ходить не туда (502)"
|
||||||
echo " Решение: sudo systemctl stop nginx && ./install.sh --fix-all"
|
echo " Решение: sudo systemctl stop nginx && ./install.sh --fix-all"
|
||||||
issues=$((issues + 1))
|
issues=$((issues + 1))
|
||||||
elif [[ "$(env_get NGINX_MODE docker)" == "host" ]] \
|
elif [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then
|
||||||
|| port_in_use "${NGINX_HTTP_PORT:-80}" \
|
echo -e " ${RED}✘${NC} Конфликт: NGINX_MODE=host, но запущен lendry-id-nginx"
|
||||||
|| port_in_use "${NGINX_HTTPS_PORT:-443}"; then
|
echo " Решение: ./install.sh --fix-all"
|
||||||
echo -e " ${RED}✘${NC} Конфликт: контейнер lendry-id-nginx запущен при занятых портах 80/443 или NGINX_MODE=host"
|
issues=$((issues + 1))
|
||||||
|
elif [[ "$(env_get NGINX_MODE docker)" == "docker" ]] \
|
||||||
|
&& ! docker_nginx_container_running \
|
||||||
|
&& ( port_in_use "${NGINX_HTTP_PORT:-80}" || port_in_use "${NGINX_HTTPS_PORT:-443}" ); then
|
||||||
|
echo -e " ${RED}✘${NC} Порты 80/443 заняты, но lendry-id-nginx не запущен"
|
||||||
echo " Решение: ./install.sh --fix-all"
|
echo " Решение: ./install.sh --fix-all"
|
||||||
issues=$((issues + 1))
|
issues=$((issues + 1))
|
||||||
else
|
else
|
||||||
@@ -3299,6 +3419,7 @@ diagnose_common_issues() {
|
|||||||
&& [[ -n "$(env_get DOMAIN_API "")" && -n "$(env_get DOMAIN_FRONTEND "")" ]]; then
|
&& [[ -n "$(env_get DOMAIN_API "")" && -n "$(env_get DOMAIN_FRONTEND "")" ]]; then
|
||||||
check_https_api_with_origin || issues=$((issues + 1))
|
check_https_api_with_origin || issues=$((issues + 1))
|
||||||
check_sso_idp_api_proxy || issues=$((issues + 1))
|
check_sso_idp_api_proxy || issues=$((issues + 1))
|
||||||
|
check_sso_frontend_root || issues=$((issues + 1))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local api_domain frontend_domain public_api
|
local api_domain frontend_domain public_api
|
||||||
@@ -3677,12 +3798,15 @@ action_fix_all_errors() {
|
|||||||
apply_intranet_selfsigned_runtime
|
apply_intranet_selfsigned_runtime
|
||||||
recreate_docker_nginx
|
recreate_docker_nginx
|
||||||
sync_nginx_after_api_gateway_restart
|
sync_nginx_after_api_gateway_restart
|
||||||
|
sync_nginx_after_edge_restart
|
||||||
verify_nginx_reaches_api_gateway 24 5 || compose_build_and_up api-gateway
|
verify_nginx_reaches_api_gateway 24 5 || compose_build_and_up api-gateway
|
||||||
sync_nginx_after_api_gateway_restart
|
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
|
||||||
reload_docker_nginx
|
reload_docker_nginx
|
||||||
verify_nginx_reaches_api_gateway 24 5 || 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"
|
||||||
|
verify_nginx_reaches_frontend 12 3 || fail "Nginx не проксирует / на frontend — см. docker compose logs nginx frontend"
|
||||||
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"
|
||||||
|
check_sso_frontend_root || fail "SSO / → 502 — главная страница недоступна (502 Bad Gateway в браузере)"
|
||||||
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"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user