自动拉起 Pingora shadow 发布服务
让 API deploy 在发布包包含 Pingora 时先校验 shadow systemd 和 env 安全边界 在 shadow 配置安全时自动启动或重启 genarrative-pingora-gateway.service 拒绝 direct-entry capability、公网监听 env,并在 current 切换前失败 补充 production-api-deploy 动态烟测、生产运维护栏和 Pingora 运维文档 在 dev 服务器真实验证 shadow inactive 场景可由发布脚本自动拉起
This commit is contained in:
@@ -11,7 +11,7 @@ usage() {
|
||||
进入维护模式,校验并发布 api-server 单文件,更新 current 链接,重启 systemd 服务并执行 readiness 检查。
|
||||
默认同时重启外部生成 worker controller 和已加载的 worker 实例;未启用 worker 单元时会自动跳过。
|
||||
若传入 --database,会在重启前把 GENARRATIVE_SPACETIME_DATABASE 写入 api-server 环境文件,避免服务继续读取旧库。
|
||||
若发布包包含 pingora-gateway,部署脚本会在 current 链接切换后仅对已 active 的 Pingora 影子服务执行 try-restart 并复核 active;未运行时不会主动拉起。
|
||||
若发布包包含 pingora-gateway,部署脚本会在 current 链接切换后先复核 systemd/env 仍是本机高端口 shadow 配置,再启动或重启 Pingora 影子服务并复核 active。
|
||||
失败时保留维护模式。
|
||||
EOF
|
||||
}
|
||||
@@ -235,18 +235,101 @@ ensure_runtime_env_and_dirs() {
|
||||
fi
|
||||
}
|
||||
|
||||
restart_pingora_if_active() {
|
||||
extract_pingora_env_files_from_unit() {
|
||||
local service_name="$1"
|
||||
local unit_content
|
||||
|
||||
if ! systemctl is-active --quiet "${service_name}"; then
|
||||
echo "[production-api-deploy] Pingora 影子服务未处于 active,跳过自动重启: ${service_name}"
|
||||
return
|
||||
if ! unit_content="$(systemctl cat "${service_name}")"; then
|
||||
echo "[production-api-deploy] 无法读取 Pingora systemd 最终配置: ${service_name}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[production-api-deploy] 发布包包含 Pingora,重启已运行的影子服务: ${service_name}"
|
||||
systemctl try-restart "${service_name}"
|
||||
if printf "%s\n" "${unit_content}" | grep -Eq '^[[:space:]]*(AmbientCapabilities|CapabilityBoundingSet)=.*CAP_NET_BIND_SERVICE'; then
|
||||
echo "[production-api-deploy] Pingora systemd 已包含 CAP_NET_BIND_SERVICE,疑似直连入口配置;API deploy 不会自动启动或重启直连服务: ${service_name}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf "%s\n" "${unit_content}" | while IFS= read -r raw_line; do
|
||||
local line value token env_file
|
||||
line="${raw_line#"${raw_line%%[![:space:]]*}"}"
|
||||
[[ "${line}" == EnvironmentFile=* ]] || continue
|
||||
value="${line#EnvironmentFile=}"
|
||||
for token in ${value}; do
|
||||
env_file="${token#-}"
|
||||
env_file="${env_file%\"}"
|
||||
env_file="${env_file#\"}"
|
||||
env_file="${env_file%\'}"
|
||||
env_file="${env_file#\'}"
|
||||
[[ -n "${env_file}" ]] && printf "%s\n" "${env_file}"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
find_pingora_gateway_env_file() {
|
||||
local service_name="$1"
|
||||
local env_file listen
|
||||
|
||||
while IFS= read -r env_file; do
|
||||
if [[ "${env_file}" != /* ]]; then
|
||||
echo "[production-api-deploy] Pingora EnvironmentFile 必须使用绝对路径: ${env_file}" >&2
|
||||
exit 1
|
||||
fi
|
||||
listen="$(read_env_value "${env_file}" "GENARRATIVE_PINGORA_GATEWAY_LISTEN")"
|
||||
if [[ -n "${listen}" ]]; then
|
||||
printf "%s\n" "${env_file}"
|
||||
return
|
||||
fi
|
||||
done < <(extract_pingora_env_files_from_unit "${service_name}")
|
||||
|
||||
echo "[production-api-deploy] Pingora systemd 配置缺少包含 GENARRATIVE_PINGORA_GATEWAY_LISTEN 的 EnvironmentFile: ${service_name}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_pingora_shadow_env() {
|
||||
local env_file="$1"
|
||||
local listen tls_listen redirect_listen
|
||||
|
||||
listen="$(read_env_value "${env_file}" "GENARRATIVE_PINGORA_GATEWAY_LISTEN")"
|
||||
tls_listen="$(read_env_value "${env_file}" "GENARRATIVE_PINGORA_GATEWAY_TLS_LISTEN")"
|
||||
redirect_listen="$(read_env_value "${env_file}" "GENARRATIVE_PINGORA_GATEWAY_HTTP_REDIRECT_LISTEN")"
|
||||
|
||||
if [[ "${listen}" != "127.0.0.1:18081" ]]; then
|
||||
echo "[production-api-deploy] Pingora 自动启动只允许 shadow 监听 127.0.0.1:18081,当前 GENARRATIVE_PINGORA_GATEWAY_LISTEN=${listen:-<empty>}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "${tls_listen}" ]]; then
|
||||
echo "[production-api-deploy] Pingora 自动启动不允许启用 TLS_LISTEN,当前 GENARRATIVE_PINGORA_GATEWAY_TLS_LISTEN=${tls_listen}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "${redirect_listen}" ]]; then
|
||||
echo "[production-api-deploy] Pingora 自动启动不允许启用 HTTP_REDIRECT_LISTEN,当前 GENARRATIVE_PINGORA_GATEWAY_HTTP_REDIRECT_LISTEN=${redirect_listen}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_pingora_shadow_service_config() {
|
||||
local service_name="$1"
|
||||
local env_file
|
||||
|
||||
env_file="$(find_pingora_gateway_env_file "${service_name}")"
|
||||
require_pingora_shadow_env "${env_file}"
|
||||
printf "%s\n" "${env_file}"
|
||||
}
|
||||
|
||||
ensure_pingora_shadow_service() {
|
||||
local service_name="$1"
|
||||
local env_file="${2:-}"
|
||||
|
||||
if [[ -z "${env_file}" ]]; then
|
||||
env_file="$(check_pingora_shadow_service_config "${service_name}")"
|
||||
else
|
||||
require_pingora_shadow_env "${env_file}"
|
||||
fi
|
||||
|
||||
echo "[production-api-deploy] 发布包包含 Pingora,启动或重启 shadow 影子服务: ${service_name} (${env_file})"
|
||||
systemctl restart "${service_name}"
|
||||
if ! systemctl is-active --quiet "${service_name}"; then
|
||||
echo "[production-api-deploy] Pingora 影子服务重启后不是 active: ${service_name}" >&2
|
||||
echo "[production-api-deploy] Pingora shadow 影子服务启动或重启后不是 active: ${service_name}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@@ -604,7 +687,7 @@ if [[ -f "${SOURCE_DIR}/pingora-gateway" ]]; then
|
||||
cp "${SOURCE_DIR}/pingora-gateway" "${RELEASE_CONTENT_DIR}/pingora-gateway"
|
||||
cp "${SOURCE_DIR}/pingora-gateway.sha256" "${RELEASE_CONTENT_DIR}/pingora-gateway.sha256"
|
||||
chmod +x "${RELEASE_CONTENT_DIR}/pingora-gateway"
|
||||
echo "[production-api-deploy] 已复制 Pingora 影子网关;current 链接切换后将复核并重启已运行的 ${PINGORA_SERVICE_NAME}"
|
||||
echo "[production-api-deploy] 已复制 Pingora 影子网关;current 链接切换后将复核 shadow 配置并启动或重启 ${PINGORA_SERVICE_NAME}"
|
||||
fi
|
||||
|
||||
BACKUP_SCRIPT_SOURCE="${SOURCE_DIR}/scripts/database-backup-to-oss.mjs"
|
||||
@@ -786,6 +869,8 @@ cp -R "${ENV_DEPLOY_DIR_SOURCE}" "${RELEASE_CONTENT_DIR}/deploy/env"
|
||||
|
||||
cp "${SOURCE_DIR}/release-manifest.json" "${RELEASE_CONTENT_DIR}/release-manifest.api-server.json"
|
||||
|
||||
PINGORA_SHADOW_ENV_FILE=""
|
||||
|
||||
if [[ -n "${DATABASE}" ]]; then
|
||||
echo "[production-api-deploy] 写入 api-server SpacetimeDB database: ${DATABASE} -> ${API_ENV_FILE}"
|
||||
write_env_value "${API_ENV_FILE}" "GENARRATIVE_SPACETIME_DATABASE" "${DATABASE}"
|
||||
@@ -798,6 +883,10 @@ fi
|
||||
|
||||
ensure_runtime_env_and_dirs "${API_ENV_FILE}"
|
||||
|
||||
if [[ "${PINGORA_INCLUDED}" -eq 1 ]]; then
|
||||
PINGORA_SHADOW_ENV_FILE="$(check_pingora_shadow_service_config "${PINGORA_SERVICE_NAME}")"
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${CURRENT_LINK}")"
|
||||
if [[ -e "${RELEASE_DIR}" ]]; then
|
||||
echo "[production-api-deploy] 目标 release 在发布过程中出现,拒绝合并 staging: ${RELEASE_DIR}" >&2
|
||||
@@ -808,7 +897,7 @@ STAGING_RELEASE_DIR=""
|
||||
ln -sfnT "${RELEASE_DIR}" "${CURRENT_LINK}"
|
||||
|
||||
if [[ "${PINGORA_INCLUDED}" -eq 1 ]]; then
|
||||
restart_pingora_if_active "${PINGORA_SERVICE_NAME}"
|
||||
ensure_pingora_shadow_service "${PINGORA_SERVICE_NAME}" "${PINGORA_SHADOW_ENV_FILE}"
|
||||
fi
|
||||
|
||||
echo "[production-api-deploy] 重启服务: ${SERVICE_NAME}"
|
||||
|
||||
Reference in New Issue
Block a user