feat: CoreDNS IPv4 上游、03-03 Tomcat 修复、HAProxy 与验证脚本

- Ansible: 部署时自动配置 CoreDNS forward 为 IPv4,避免 ACME 解析失败
- 01-01/01-07: 文档增加 CoreDNS 设置说明
- 03-03: Tomcat webapps.dist 复制、HTTP/HTTPS 双 Ingress、显式 Dashboard IngressRoute
- traefik-dashboard-acme: tomcat-acme.yaml、404 排查说明
- HAProxy: 健康检查与 PROXY 配置拆分,18080/18443 部署与验证脚本

Made-with: Cursor
This commit is contained in:
2026-03-22 19:02:46 +08:00
parent de1be1dbe5
commit 8a54cac61f
25 changed files with 924 additions and 113 deletions

View File

@@ -0,0 +1,211 @@
#!/usr/bin/env bash
# HAProxy 配置与后端验证OpenWrt 18080/18443第三方 onecloud curl
# 核心ansible/files/01-08-haproxy/*.cfg 语法正确;可选经 curl 验证运行时与后端
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CFG_DIR="${ROOT_DIR}/ansible/files/01-08-haproxy"
MATRIX_FILE="${ROOT_DIR}/docs/00-02-验证矩阵.md"
SSH_OPENWRT="${SSH_OPENWRT:-openwrt}"
VERIFY_HOST="${VERIFY_HOST:-onecloud}"
OPENWRT_IP="${OPENWRT_IP:-192.168.2.1}"
HTTP_PORT="${HTTP_PORT:-18080}"
HTTPS_PORT="${HTTPS_PORT:-18443}"
DEPLOY_MATRIX="${DEPLOY_MATRIX:-none}"
HTTPS_HOSTS="" # 逗号分隔,如 test01.jackadam.top,test02.jackadam.top
UPDATE_MATRIX=1
CFG_ONLY=0 # 仅 haproxy -c 校验本目录 cfg不跑 curl
usage() {
cat <<'EOF'
用法:
./scripts/01-08-verify-haproxy.sh [选项]
选项:
--cfg-only 仅校验 ansible/files/01-08-haproxy/*.cfg 语法OpenWrt 上 haproxy -c不跑 curl
--deploy-matrix <none|http|tls> 验证前一键部署矩阵(默认 none
--verify-host <name> curl 执行主机SSH 目标(默认 onecloud
--openwrt-ip <ip> OpenWrt/网关 IP默认 192.168.2.1
--http-port <port> HAProxy HTTP 端口(默认 18080
--https-port <port> HAProxy HTTPS 端口(默认 18443
--https-hosts <domain1,domain2> HTTPS 校验域名M1M4 对应(缺省时不校验 HTTPS
--update-matrix 验证通过后更新验证矩阵(默认启用)
--no-update-matrix 不更新验证矩阵
-h, --help 显示帮助
前置ssh openwrt 可用;完整验证还需 ssh onecloudOpenWrt HAProxy 已按 18080/18443 配置(运行时验证)
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--cfg-only) CFG_ONLY=1; shift ;;
--deploy-matrix) DEPLOY_MATRIX="${2:-none}"; shift 2 ;;
--verify-host) VERIFY_HOST="${2:-onecloud}"; shift 2 ;;
--openwrt-ip) OPENWRT_IP="${2:-192.168.2.1}"; shift 2 ;;
--http-port) HTTP_PORT="${2:-18080}"; shift 2 ;;
--https-port) HTTPS_PORT="${2:-18443}"; shift 2 ;;
--https-hosts) HTTPS_HOSTS="${2:-}"; shift 2 ;;
--update-matrix) UPDATE_MATRIX=1; shift ;;
--no-update-matrix) UPDATE_MATRIX=0; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "[ERR] 未知参数: $1"; usage; exit 1 ;;
esac
done
REMOTE_DIR="/tmp/haproxy-verify"
if [[ $CFG_ONLY -eq 1 ]]; then
echo "=== HAProxy cfg 语法校验(${SSH_OPENWRT}ansible/files/01-08-haproxy/*.cfg==="
else
echo "=== HAProxy 验证(${SSH_OPENWRT}${VERIFY_HOST} curl ${OPENWRT_IP}:${HTTP_PORT}/${HTTPS_PORT}==="
fi
# 0. 按需部署矩阵(--cfg-only 时不部署)
if [[ $CFG_ONLY -eq 1 ]]; then
:
elif [[ "$DEPLOY_MATRIX" == "http" ]]; then
echo "[0] 部署 02-05 nginx 矩阵http..."
(cd "$ROOT_DIR" && ansible-playbook -i ansible/inventory.ini ansible/playbooks/nginx-matrix-deploy.yml) || { echo "[ERR] nginx-matrix-deploy 失败" >&2; exit 1; }
echo " [OK] HTTP 矩阵已部署"
elif [[ "$DEPLOY_MATRIX" == "tls" ]]; then
echo "[0] 部署 nginx 矩阵 TLS 版..."
(cd "$ROOT_DIR" && ansible-playbook -i ansible/inventory.ini ansible/playbooks/nginx-matrix-tls-deploy.yml) || { echo "[ERR] nginx-matrix-tls-deploy 失败" >&2; exit 1; }
echo " [OK] TLS 矩阵已部署"
[[ -z "$HTTPS_HOSTS" ]] && HTTPS_HOSTS="test01.jackadam.top,test02.jackadam.top,test03.jackadam.top,test04.jackadam.top"
fi
if [[ ! -d "$CFG_DIR" ]]; then
echo "[ERR] cfg 目录不存在: $CFG_DIR" >&2
exit 1
fi
# 1. 拷贝 cfg 到 OpenWrt-O 强制旧 SCP 协议,兼容无 sftp-server 的 OpenWrt
echo "[1/4] 拷贝 cfg 到 ${SSH_OPENWRT}:${REMOTE_DIR}..."
ssh "$SSH_OPENWRT" "mkdir -p ${REMOTE_DIR}"
scp -q -O "${CFG_DIR}"/*.cfg "${SSH_OPENWRT}:${REMOTE_DIR}/" 2>/dev/null || {
echo " [INFO] scp -O 不可用,改用 ssh 管道传输..."
for f in "${CFG_DIR}"/*.cfg; do
bn=$(basename "$f")
ssh "$SSH_OPENWRT" "cat > ${REMOTE_DIR}/${bn}" < "$f"
done
}
# 2. 语法校验
echo "[2/4] 校验 cfg 语法..."
SYNTAX_FAIL=0
for cfg in haproxy-no-check haproxy-http haproxy-tls haproxy-proxy-http-tls; do
if ssh "$SSH_OPENWRT" "haproxy -c -f ${REMOTE_DIR}/${cfg}.cfg" 2>/dev/null; then
echo " [OK] ${cfg}.cfg"
else
echo " [FAIL] ${cfg}.cfg" >&2
SYNTAX_FAIL=1
fi
done
if ssh "$SSH_OPENWRT" "haproxy -c -f ${REMOTE_DIR}/haproxy-https.cfg" 2>/dev/null; then
echo " [OK] haproxy-https.cfg语法运行需 /etc/ssl/haproxy.pem"
else
echo " [SKIP] haproxy-https.cfg缺证书"
fi
if [[ $SYNTAX_FAIL -eq 1 ]]; then
echo "[ERR] 部分 cfg 语法校验失败" >&2
exit 1
fi
if [[ $CFG_ONLY -eq 1 ]]; then
echo
echo "[PASS] 本目录 HAProxy cfg 语法校验通过(见 ansible/files/01-08-haproxy/README.md"
exit 0
fi
# 3. SSH onecloud 执行 curl 验证
echo "[3/4] 经 ${VERIFY_HOST} 验证 HTTP${OPENWRT_IP}:${HTTP_PORT}..."
# HTTPTLS 矩阵(有 --https-hosts按 Host 验证;否则 02-05 路径 /demo-m1m4
if [[ -n "$HTTPS_HOSTS" ]]; then
# TLS 矩阵:按 Host 验证test01test04 对应 M1M4
IFS=',' read -ra HOSTS <<< "$HTTPS_HOSTS"
HTTP_FAIL=0
for i in "${!HOSTS[@]}"; do
host="${HOSTS[$i]}"
expect="M$((i+1))"
code=$(ssh "$VERIFY_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 5 'http://${host}:${HTTP_PORT}/' --resolve '${host}:${HTTP_PORT}:${OPENWRT_IP}' 2>/dev/null" || echo "000")
body=$(ssh "$VERIFY_HOST" "curl -s --max-time 5 'http://${host}:${HTTP_PORT}/' --resolve '${host}:${HTTP_PORT}:${OPENWRT_IP}' 2>/dev/null" || echo "")
if [[ "$code" != "200" ]]; then
echo " [FAIL] http://${host}:${HTTP_PORT}/ 返回 ${code}" >&2
HTTP_FAIL=1
elif [[ "$body" != *"$expect"* ]]; then
echo " [FAIL] http://${host}:${HTTP_PORT}/ body 不含 ${expect}" >&2
HTTP_FAIL=1
else
echo " [OK] http://${host}:${HTTP_PORT}/ 200 含 ${expect}"
fi
done
else
# 02-05 路径型
DEMO_PATHS=(demo-m1:M1 demo-m2:M2 demo-m3:M3 demo-m4:M4)
HTTP_FAIL=0
for item in "${DEMO_PATHS[@]}"; do
path="${item%%:*}"
expect="${item##*:}"
code=$(ssh "$VERIFY_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 5 'http://${OPENWRT_IP}:${HTTP_PORT}/${path}/' 2>/dev/null" || echo "000")
body=$(ssh "$VERIFY_HOST" "curl -s --max-time 5 'http://${OPENWRT_IP}:${HTTP_PORT}/${path}/' 2>/dev/null" || echo "")
if [[ "$code" != "200" ]]; then
echo " [FAIL] /${path}/ 返回 ${code}" >&2
HTTP_FAIL=1
elif [[ "$body" != *"$expect"* ]]; then
echo " [FAIL] /${path}/ body 不含 ${expect}" >&2
HTTP_FAIL=1
else
echo " [OK] /${path}/ 200 含 ${expect}"
fi
done
fi
if [[ $HTTP_FAIL -eq 1 ]]; then
echo "[ERR] HTTP 验证失败" >&2
exit 1
fi
# 4. HTTPS 验证(需 --https-hosts不带 -k 校验证书)
if [[ -n "$HTTPS_HOSTS" ]]; then
echo "[4/4] 经 ${VERIFY_HOST} 验证 HTTPS域名 :${HTTPS_PORT},校验 ACME 证书)..."
IFS=',' read -ra HOSTS <<< "$HTTPS_HOSTS"
HTTPS_FAIL=0
for i in "${!HOSTS[@]}"; do
host="${HOSTS[$i]}"
expect="M$((i+1))"
code=$(ssh "$VERIFY_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 10 'https://${host}:${HTTPS_PORT}/' --resolve '${host}:${HTTPS_PORT}:${OPENWRT_IP}' 2>/dev/null" || echo "000")
body=$(ssh "$VERIFY_HOST" "curl -s --max-time 10 'https://${host}:${HTTPS_PORT}/' --resolve '${host}:${HTTPS_PORT}:${OPENWRT_IP}' 2>/dev/null" || echo "")
if [[ "$code" != "200" ]]; then
echo " [FAIL] https://${host}:${HTTPS_PORT}/ 返回 ${code}" >&2
HTTPS_FAIL=1
elif [[ "$body" != *"$expect"* ]]; then
echo " [FAIL] https://${host}:${HTTPS_PORT}/ body 不含 ${expect}" >&2
HTTPS_FAIL=1
else
echo " [OK] https://${host}:${HTTPS_PORT}/ 200 含 ${expect}"
fi
done
if [[ $HTTPS_FAIL -eq 1 ]]; then
echo "[ERR] HTTPS 验证失败" >&2
exit 1
fi
else
echo "[4/4] 跳过 HTTPS未指定 --https-hosts"
fi
echo
echo "[PASS] HAProxy 验证通过"
# 5. 可选:更新验证矩阵
if [[ $UPDATE_MATRIX -eq 1 ]] && [[ -f "$MATRIX_FILE" ]]; then
TODAY=$(date +%Y-%m-%d)
echo "[INFO] 更新验证矩阵..."
if command -v python3 >/dev/null 2>&1; then
python3 "${ROOT_DIR}/scripts/01-08-update-verify-matrix.py" "$MATRIX_FILE" "$TODAY" || echo " [WARN] 验证矩阵未更新"
else
echo " [WARN] 未找到 python3请手动更新 docs/00-02-验证矩阵.md"
fi
fi