mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-05 02:41:49 +00:00
fix(web): refresh API proxy DNS after backend redeploy (#900)
* fix(web): refresh API proxy DNS after backend redeploy Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * test(web): stabilize DNS replacement coverage Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * test(web): allow early resolver refresh after DNS change Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> * test(web): use dynamic ports for nginx smoke Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --------- Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
parent
ed2ff97d00
commit
e8fad5962e
5 changed files with 128 additions and 19 deletions
|
|
@ -70,6 +70,7 @@ services:
|
|||
- ./web/dist:/usr/share/nginx/html:ro
|
||||
- ./web/nginx.conf.template:/etc/nginx/templates/default.conf.template:ro
|
||||
environment:
|
||||
NGINX_ENTRYPOINT_LOCAL_RESOLVERS: "1"
|
||||
SKILLHUB_API_UPSTREAM: http://server:8080
|
||||
SKILLHUB_WEB_API_BASE_URL: ""
|
||||
SKILLHUB_PUBLIC_BASE_URL: ""
|
||||
|
|
|
|||
|
|
@ -39,13 +39,25 @@ wait_for_nginx() {
|
|||
fail "$container did not become healthy"
|
||||
}
|
||||
|
||||
create_test_network() {
|
||||
local subnet
|
||||
for subnet in 172.29.0.0/24 172.30.0.0/24 192.168.252.0/24 10.254.0.0/24; do
|
||||
if docker network create --driver bridge --subnet "$subnet" "$NETWORK" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
fail "could not create a test network with an explicit subnet"
|
||||
}
|
||||
|
||||
start_proxy() {
|
||||
local container="$1"
|
||||
local trust_forwarded_proto="$2"
|
||||
local backend_name="${3:-$BACKEND}"
|
||||
docker run --detach \
|
||||
--name "$container" \
|
||||
--network "$NETWORK" \
|
||||
--env "SKILLHUB_API_UPSTREAM=http://$BACKEND:8080" \
|
||||
--env "NGINX_ENTRYPOINT_LOCAL_RESOLVERS=1" \
|
||||
--env "SKILLHUB_API_UPSTREAM=http://$backend_name:8080" \
|
||||
--env "SKILLHUB_TRUST_FORWARDED_PROTO=$trust_forwarded_proto" \
|
||||
--volume "$TEMPLATE:/etc/nginx/templates/default.conf.template:ro" \
|
||||
"$NGINX_IMAGE" >/dev/null
|
||||
|
|
@ -80,7 +92,7 @@ server {
|
|||
}
|
||||
EOF
|
||||
|
||||
docker network create "$NETWORK" >/dev/null
|
||||
create_test_network
|
||||
docker run --detach \
|
||||
--name "$BACKEND" \
|
||||
--network "$NETWORK" \
|
||||
|
|
@ -98,4 +110,89 @@ done
|
|||
assert_proto "$TRUSTED_PROXY" http
|
||||
assert_proto "$TRUSTED_PROXY" http "https,http"
|
||||
|
||||
echo "nginx-forwarded-proto-test passed"
|
||||
DNS_BACKEND="${TEST_ID}-dns-backend"
|
||||
DNS_OLD_BACKEND="${TEST_ID}-dns-old"
|
||||
DNS_NEW_BACKEND="${TEST_ID}-dns-new"
|
||||
DNS_STALE_BACKEND="${TEST_ID}-dns-stale"
|
||||
DNS_PROXY="${TEST_ID}-dns-proxy"
|
||||
|
||||
start_dns_backend() {
|
||||
local container="$1"
|
||||
local response="$2"
|
||||
local alias="${3:-}"
|
||||
local static_ip="${4:-}"
|
||||
local config="$TMP_DIR/$container.conf"
|
||||
cat >"$config" <<EOF
|
||||
server {
|
||||
listen 8080;
|
||||
location / {
|
||||
default_type text/plain;
|
||||
return 200 "$response";
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
local alias_args=()
|
||||
local ip_args=()
|
||||
if [[ -n "$alias" ]]; then
|
||||
alias_args+=(--network-alias "$alias")
|
||||
fi
|
||||
if [[ -n "$static_ip" ]]; then
|
||||
ip_args+=(--ip "$static_ip")
|
||||
fi
|
||||
|
||||
docker run --detach \
|
||||
--name "$container" \
|
||||
--network "$NETWORK" \
|
||||
"${alias_args[@]}" \
|
||||
"${ip_args[@]}" \
|
||||
--volume "$config:/etc/nginx/conf.d/default.conf:ro" \
|
||||
"$NGINX_IMAGE" >/dev/null
|
||||
CONTAINERS+=("$container")
|
||||
}
|
||||
|
||||
container_ip() {
|
||||
docker inspect --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" "$1"
|
||||
}
|
||||
|
||||
start_dns_backend "$DNS_OLD_BACKEND" first "$DNS_BACKEND"
|
||||
start_proxy "$DNS_PROXY" false "$DNS_BACKEND"
|
||||
assert_dns_response() {
|
||||
local expected="$1"
|
||||
local actual
|
||||
actual="$(docker exec "$DNS_PROXY" wget -qO- http://127.0.0.1/api/dns)" \
|
||||
|| fail "DNS proxy request failed; expected '$expected'"
|
||||
[[ "$actual" == "$expected" ]] \
|
||||
|| fail "DNS proxy returned '$actual', expected '$expected'"
|
||||
}
|
||||
assert_dns_response first
|
||||
|
||||
old_ip="$(container_ip "$DNS_OLD_BACKEND")"
|
||||
docker rm -f "$DNS_OLD_BACKEND" >/dev/null
|
||||
start_dns_backend "$DNS_STALE_BACKEND" stale "" "$old_ip"
|
||||
start_dns_backend "$DNS_NEW_BACKEND" second "$DNS_BACKEND"
|
||||
new_ip="$(container_ip "$DNS_NEW_BACKEND")"
|
||||
[[ "$old_ip" != "$new_ip" ]] || fail "replacement backend reused old IP $old_ip"
|
||||
|
||||
refreshed=false
|
||||
saw_stale_response=false
|
||||
refresh_started=$SECONDS
|
||||
for attempt in {1..36}; do
|
||||
if actual="$(docker exec "$DNS_PROXY" wget -qO- http://127.0.0.1/api/dns 2>/dev/null)"; then
|
||||
if [[ "$actual" == second ]]; then
|
||||
refreshed=true
|
||||
break
|
||||
fi
|
||||
[[ "$actual" == stale ]] \
|
||||
|| fail "DNS proxy returned unexpected backend marker '$actual'"
|
||||
saw_stale_response=true
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
[[ "$refreshed" == true ]] \
|
||||
|| { docker logs "$DNS_PROXY" >&2 || true; fail "unchanged proxy did not reach replacement backend $new_ip"; }
|
||||
refresh_elapsed=$((SECONDS - refresh_started))
|
||||
((refresh_elapsed <= 12)) \
|
||||
|| fail "DNS refresh took ${refresh_elapsed}s, exceeding the 12s test boundary"
|
||||
|
||||
echo "nginx-forwarded-proto-test passed, including DNS refresh ($old_ip -> $new_ip) in ${refresh_elapsed}s; stale cache observed=$saw_stale_response"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ fi
|
|||
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)
|
||||
NGINX_IMAGE="${NGINX_SMOKE_IMAGE:-nginx:alpine}"
|
||||
name="skillhub-base-path-smoke-$$"
|
||||
port=18080
|
||||
|
||||
tmp=$(mktemp -d)
|
||||
cleanup() {
|
||||
|
|
@ -24,6 +23,10 @@ cleanup() {
|
|||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
published_port() {
|
||||
docker inspect --format '{{(index (index .NetworkSettings.Ports "80/tcp") 0).HostPort}}' "$1"
|
||||
}
|
||||
|
||||
html="$tmp/html"
|
||||
mkdir -p "$html/assets" "$html/registry"
|
||||
printf '%s\n' 'INDEX_HTML_MARKER' >"$html/index.html"
|
||||
|
|
@ -40,7 +43,8 @@ cp "$ROOT_DIR/web/docker-entrypoint.d/30-runtime-config.sh" "$entrypoint_d/30-ru
|
|||
chmod +x "$entrypoint_d/20-base-path.sh" "$entrypoint_d/30-runtime-config.sh"
|
||||
|
||||
if ! docker run -d --name "$name" \
|
||||
-p "$port:80" \
|
||||
-p 127.0.0.1::80 \
|
||||
-e NGINX_ENTRYPOINT_LOCAL_RESOLVERS=1 \
|
||||
-e SKILLHUB_API_UPSTREAM=http://127.0.0.1:9 \
|
||||
-e SKILLHUB_TRUST_FORWARDED_PROTO=false \
|
||||
-e SKILLHUB_WEB_BASE_PATH=/skillhub/ \
|
||||
|
|
@ -49,11 +53,12 @@ if ! docker run -d --name "$name" \
|
|||
-v "$ROOT_DIR/web/nginx.conf.template:/etc/nginx/templates/default.conf.template:ro" \
|
||||
-v "$entrypoint_d/20-base-path.sh:/docker-entrypoint.d/20-base-path.sh:ro" \
|
||||
-v "$entrypoint_d/30-runtime-config.sh:/docker-entrypoint.d/30-runtime-config.sh:ro" \
|
||||
"$NGINX_IMAGE" >/dev/null 2>&1; then
|
||||
printf '%s\n' 'web-base-path-nginx-smoke-test skipped (docker run failed, e.g. no image/network)'
|
||||
exit 0
|
||||
"$NGINX_IMAGE" >/dev/null; then
|
||||
echo 'nginx container failed to start' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
port=$(published_port "$name")
|
||||
base="http://127.0.0.1:$port"
|
||||
ready=0
|
||||
i=0
|
||||
|
|
@ -151,9 +156,9 @@ printf '%s\n' 'INDEX_HTML_MARKER' >"$default_html/index.html"
|
|||
cp "$ROOT_DIR/web/src/docs/skill.md.template" "$default_html/registry/skill.md.template"
|
||||
cp "$ROOT_DIR/web/runtime-config.js.template" "$default_html/runtime-config.js.template"
|
||||
name_default="$name-default"
|
||||
port_default=18082
|
||||
docker run -d --name "$name_default" \
|
||||
-p "$port_default:80" \
|
||||
-p 127.0.0.1::80 \
|
||||
-e NGINX_ENTRYPOINT_LOCAL_RESOLVERS=1 \
|
||||
-e SKILLHUB_API_UPSTREAM=http://127.0.0.1:9 \
|
||||
-e SKILLHUB_TRUST_FORWARDED_PROTO=false \
|
||||
-e SKILLHUB_WEB_BASE_PATH=/skillhub/ \
|
||||
|
|
@ -163,6 +168,7 @@ docker run -d --name "$name_default" \
|
|||
-v "$entrypoint_d/30-runtime-config.sh:/docker-entrypoint.d/30-runtime-config.sh:ro" \
|
||||
"$NGINX_IMAGE" >/dev/null
|
||||
|
||||
port_default=$(published_port "$name_default")
|
||||
default_base="http://127.0.0.1:$port_default"
|
||||
i=0
|
||||
until curl -fsS -o /dev/null "$default_base/nginx-health" 2>/dev/null; do
|
||||
|
|
@ -203,9 +209,9 @@ printf '%s\n' 'INDEX_HTML_MARKER' >"$trusted_html/index.html"
|
|||
cp "$ROOT_DIR/web/src/docs/skill.md.template" "$trusted_html/registry/skill.md.template"
|
||||
cp "$ROOT_DIR/web/runtime-config.js.template" "$trusted_html/runtime-config.js.template"
|
||||
name_trusted="$name-trusted"
|
||||
port_trusted=18083
|
||||
docker run -d --name "$name_trusted" \
|
||||
-p "$port_trusted:80" \
|
||||
-p 127.0.0.1::80 \
|
||||
-e NGINX_ENTRYPOINT_LOCAL_RESOLVERS=1 \
|
||||
-e SKILLHUB_API_UPSTREAM=http://127.0.0.1:9 \
|
||||
-e SKILLHUB_TRUST_FORWARDED_PROTO=true \
|
||||
-e SKILLHUB_WEB_BASE_PATH=/skillhub/ \
|
||||
|
|
@ -214,6 +220,7 @@ docker run -d --name "$name_trusted" \
|
|||
-v "$entrypoint_d/20-base-path.sh:/docker-entrypoint.d/20-base-path.sh:ro" \
|
||||
-v "$entrypoint_d/30-runtime-config.sh:/docker-entrypoint.d/30-runtime-config.sh:ro" \
|
||||
"$NGINX_IMAGE" >/dev/null
|
||||
port_trusted=$(published_port "$name_trusted")
|
||||
trusted_base="http://127.0.0.1:$port_trusted"
|
||||
i=0
|
||||
until curl -fsS -o /dev/null "$trusted_base/nginx-health" 2>/dev/null; do
|
||||
|
|
@ -242,10 +249,10 @@ printf '%s\n' 'FIXED_APP_JS_MARKER' >"$fixed_html/assets/app.js"
|
|||
baked_file="$tmp/baked-base-path"
|
||||
printf '%s' '/fixed/' >"$baked_file"
|
||||
fixed_name="$name-fixed"
|
||||
fixed_port=18081
|
||||
|
||||
docker run -d --name "$fixed_name" \
|
||||
-p "$fixed_port:80" \
|
||||
-p 127.0.0.1::80 \
|
||||
-e NGINX_ENTRYPOINT_LOCAL_RESOLVERS=1 \
|
||||
-e SKILLHUB_API_UPSTREAM=http://127.0.0.1:9 \
|
||||
-e SKILLHUB_TRUST_FORWARDED_PROTO=false \
|
||||
-e SKILLHUB_WEB_BASE_PATH= \
|
||||
|
|
@ -254,8 +261,9 @@ docker run -d --name "$fixed_name" \
|
|||
-v "$baked_file:/etc/skillhub/baked-base-path:ro" \
|
||||
-v "$ROOT_DIR/web/nginx.conf.template:/etc/nginx/templates/default.conf.template:ro" \
|
||||
-v "$entrypoint_d/20-base-path.sh:/docker-entrypoint.d/20-base-path.sh:ro" \
|
||||
"$NGINX_IMAGE" >/dev/null 2>&1
|
||||
"$NGINX_IMAGE" >/dev/null
|
||||
|
||||
fixed_port=$(published_port "$fixed_name")
|
||||
fixed_base="http://127.0.0.1:$fixed_port"
|
||||
ready=0
|
||||
i=0
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ RUN pnpm build
|
|||
|
||||
FROM nginx:alpine
|
||||
ENV SKILLHUB_TRUST_FORWARDED_PROTO=false
|
||||
ENV NGINX_ENTRYPOINT_LOCAL_RESOLVERS=1
|
||||
# Record a fixed build-time base so the entrypoint defaults SKILLHUB_WEB_BASE_PATH
|
||||
# to it and generates matching Nginx routing without repeating the value at runtime.
|
||||
# Placeholder builds (the default) intentionally write no file and default to '/'.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ server_tokens off;
|
|||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
resolver ${NGINX_LOCAL_RESOLVERS} valid=10s;
|
||||
set $skillhub_api_upstream "${SKILLHUB_API_UPSTREAM}";
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
|
|
@ -34,7 +36,7 @@ server {
|
|||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass ${SKILLHUB_API_UPSTREAM};
|
||||
proxy_pass $skillhub_api_upstream;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
|
@ -43,7 +45,7 @@ server {
|
|||
}
|
||||
|
||||
location /oauth2/ {
|
||||
proxy_pass ${SKILLHUB_API_UPSTREAM};
|
||||
proxy_pass $skillhub_api_upstream;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
|
@ -52,7 +54,7 @@ server {
|
|||
}
|
||||
|
||||
location /login/oauth2/ {
|
||||
proxy_pass ${SKILLHUB_API_UPSTREAM};
|
||||
proxy_pass $skillhub_api_upstream;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
|
@ -61,7 +63,7 @@ server {
|
|||
}
|
||||
|
||||
location /.well-known/ {
|
||||
proxy_pass ${SKILLHUB_API_UPSTREAM};
|
||||
proxy_pass $skillhub_api_upstream;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue