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:
49
scripts/01-08-deploy-nginx-tls-via-ylc61.sh
Normal file
49
scripts/01-08-deploy-nginx-tls-via-ylc61.sh
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# 经 ssh ylc61 在控制节点上一键部署 nginx TLS 矩阵(M1~M4,test01~04.jackadam.top)
|
||||
# 用法:./scripts/01-08-deploy-nginx-tls-via-ylc61.sh
|
||||
# 前置:本机可 ssh 到 ylc61;脚本会同步 ansible + SSH 密钥到 ylc61 后执行 playbook
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
REMOTE_HOST="${REMOTE_HOST:-ylc61}"
|
||||
REMOTE_USER="${REMOTE_USER:-root}"
|
||||
REMOTE_REPO="${REMOTE_REPO:-/root/实验室建设}"
|
||||
SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=10"
|
||||
SSH_KEY="${ROOT_DIR}/.ssh/id_ed25519_k3s_192.168.2.61"
|
||||
[[ -f "$SSH_KEY" ]] && SSH_OPTS="$SSH_OPTS -i $SSH_KEY"
|
||||
SSH_CMD="ssh $SSH_OPTS ${REMOTE_USER}@${REMOTE_HOST}"
|
||||
|
||||
echo "=== 经 ${REMOTE_HOST} 部署 nginx TLS 矩阵 ==="
|
||||
|
||||
# 1. 同步 SSH 密钥到 ylc61(ansible 连接各节点需此)
|
||||
if [[ -d "${ROOT_DIR}/.ssh" ]]; then
|
||||
echo "[1/3] 同步 SSH 密钥到 ${REMOTE_HOST}:~/.ssh/..."
|
||||
$SSH_CMD "mkdir -p /root/.ssh && chmod 700 /root/.ssh"
|
||||
for k in "${ROOT_DIR}"/.ssh/id_ed25519_k3s_192.168.2.61 "${ROOT_DIR}"/.ssh/id_ed25519_k3s_192.168.2.62 \
|
||||
"${ROOT_DIR}"/.ssh/id_ed25519_k3s_192.168.2.63 "${ROOT_DIR}"/.ssh/id_ed25519_k3s_192.168.2.64; do
|
||||
[[ -f "$k" ]] || continue
|
||||
scp -q $SSH_OPTS "$k" "${k}.pub" "${REMOTE_USER}@${REMOTE_HOST}:/root/.ssh/" 2>/dev/null || true
|
||||
done
|
||||
$SSH_CMD "chmod 600 /root/.ssh/id_ed25519_k3s_* 2>/dev/null || true"
|
||||
fi
|
||||
|
||||
# 2. 同步 ansible 到远程
|
||||
if [[ -d "${ROOT_DIR}/ansible" ]]; then
|
||||
echo "[2/3] 同步 ansible 到 ${REMOTE_HOST}:${REMOTE_REPO}..."
|
||||
rsync -az -e "ssh $SSH_OPTS" --delete \
|
||||
--exclude='.git' \
|
||||
"${ROOT_DIR}/ansible/" \
|
||||
"${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_REPO}/ansible/" 2>/dev/null || {
|
||||
echo " [INFO] rsync 不可用,改用 scp..."
|
||||
$SSH_CMD "mkdir -p ${REMOTE_REPO}/ansible"
|
||||
scp -r $SSH_OPTS "${ROOT_DIR}/ansible/"* "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_REPO}/ansible/"
|
||||
}
|
||||
else
|
||||
echo "[2/3] 假定 ${REMOTE_HOST} 上已有 ${REMOTE_REPO}"
|
||||
fi
|
||||
|
||||
echo "[3/3] 在 ${REMOTE_HOST} 上执行 ansible-playbook..."
|
||||
$SSH_CMD "cd ${REMOTE_REPO} && ansible-playbook -i ansible/inventory.ini ansible/playbooks/nginx-matrix-tls-deploy.yml"
|
||||
|
||||
echo ""
|
||||
echo "[OK] nginx TLS 矩阵已部署。验证:./scripts/01-08-verify-haproxy-openwrt.sh --https-hosts 'test01.jackadam.top,test02.jackadam.top,test03.jackadam.top,test04.jackadam.top'"
|
||||
61
scripts/01-08-deploy-openwrt-haproxy.sh
Normal file
61
scripts/01-08-deploy-openwrt-haproxy.sh
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
# OpenWrt:uhttpd 改回 80/443(IPv4+IPv6),HAProxy 部署到 18080/18443
|
||||
# 用法:./scripts/01-08-deploy-openwrt-haproxy.sh [haproxy-cfg-name]
|
||||
# cfg-name 默认 haproxy-tls(可选 haproxy-no-check, haproxy-http, haproxy-tls, haproxy-proxy-http-tls)
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
CFG_DIR="${ROOT_DIR}/ansible/files/01-08-haproxy"
|
||||
SSH_OPENWRT="${SSH_OPENWRT:-openwrt}"
|
||||
HAPROXY_CFG_NAME="${1:-haproxy-tls}"
|
||||
HAPROXY_CFG_PATH="${HAPROXY_CFG_PATH:-/etc/haproxy.cfg}"
|
||||
|
||||
echo "=== OpenWrt 部署:uhttpd 80/443 + HAProxy 18080/18443(${HAPROXY_CFG_NAME})==="
|
||||
|
||||
# 1. uhttpd 恢复 80/443(IPv4 + IPv6)
|
||||
echo "[1/4] 配置 uhttpd 监听 0.0.0.0:80、[::]:80、0.0.0.0:443、[::]:443..."
|
||||
ssh "$SSH_OPENWRT" "bash -s" <<'UHTTPD'
|
||||
set -e
|
||||
# 清除旧 listen 并设置新的
|
||||
uci delete uhttpd.main.listen_http 2>/dev/null || true
|
||||
uci delete uhttpd.main.listen_https 2>/dev/null || true
|
||||
uci add_list uhttpd.main.listen_http='0.0.0.0:80'
|
||||
uci add_list uhttpd.main.listen_http='[::]:80'
|
||||
uci add_list uhttpd.main.listen_https='0.0.0.0:443'
|
||||
uci add_list uhttpd.main.listen_https='[::]:443'
|
||||
uci commit uhttpd
|
||||
/etc/init.d/uhttpd restart
|
||||
echo " uhttpd 已重启"
|
||||
UHTTPD
|
||||
|
||||
# 2. 停止 HAProxy(释放 80/443,避免与 uhttpd 冲突)
|
||||
echo "[2/4] 停止 HAProxy..."
|
||||
ssh "$SSH_OPENWRT" "/etc/init.d/haproxy stop 2>/dev/null || true"
|
||||
|
||||
# 3. 拷贝 HAProxy cfg 并校验
|
||||
SRC_CFG="${CFG_DIR}/${HAPROXY_CFG_NAME}.cfg"
|
||||
if [[ ! -f "$SRC_CFG" ]]; then
|
||||
echo "[ERR] 配置文件不存在: $SRC_CFG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[3/4] 拷贝 ${HAPROXY_CFG_NAME}.cfg 到 ${SSH_OPENWRT}:${HAPROXY_CFG_PATH}..."
|
||||
scp -q -O "$SRC_CFG" "${SSH_OPENWRT}:/tmp/haproxy-new.cfg" 2>/dev/null || {
|
||||
scp -q "$SRC_CFG" "${SSH_OPENWRT}:/tmp/haproxy-new.cfg"
|
||||
}
|
||||
|
||||
ssh "$SSH_OPENWRT" "haproxy -c -f /tmp/haproxy-new.cfg" || {
|
||||
echo "[ERR] HAProxy 配置语法校验失败" >&2
|
||||
exit 1
|
||||
}
|
||||
ssh "$SSH_OPENWRT" "mv /tmp/haproxy-new.cfg ${HAPROXY_CFG_PATH}"
|
||||
|
||||
# 4. 启动 HAProxy
|
||||
echo "[4/4] 启动 HAProxy..."
|
||||
ssh "$SSH_OPENWRT" "/etc/init.d/haproxy start"
|
||||
ssh "$SSH_OPENWRT" "/etc/init.d/haproxy enable"
|
||||
|
||||
echo ""
|
||||
echo "[OK] 部署完成。验证:./scripts/01-08-verify-haproxy-openwrt.sh"
|
||||
echo " - uhttpd: 80/443(IPv4+IPv6)"
|
||||
echo " - HAProxy: 18080/18443"
|
||||
32
scripts/01-08-update-verify-matrix.py
Normal file
32
scripts/01-08-update-verify-matrix.py
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python3
|
||||
"""仅更新 docs/00-02-验证矩阵.md 中 01-08-openwrt-haproxy 条目(避免 sed 范围误伤)。"""
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
def main() -> int:
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
matrix = root / "docs" / "00-02-验证矩阵.md"
|
||||
if len(sys.argv) > 1:
|
||||
matrix = Path(sys.argv[1])
|
||||
today = sys.argv[2] if len(sys.argv) > 2 else __import__("datetime").date.today().isoformat()
|
||||
|
||||
text = matrix.read_text(encoding="utf-8")
|
||||
pattern = re.compile(
|
||||
r"(- `01-08-openwrt-haproxy\.md`\s*\n\s+- )状态:[^\n]+(\s*\n\s+- )备注:[^\n]+",
|
||||
re.MULTILINE,
|
||||
)
|
||||
repl = (
|
||||
rf"\1状态:✅ 已验证\2备注:ImmortalWrt + HAProxy 18080/18443;经 `scripts/01-08-verify-haproxy.sh` "
|
||||
rf"(ssh onecloud 第三方 curl)验证;cfg 语法、HTTP/HTTPS 后端正确;可选 `--deploy-matrix http|tls` 一键部署矩阵({today})。"
|
||||
)
|
||||
new_text, n = pattern.subn(repl, text, count=1)
|
||||
if n != 1:
|
||||
print("[WARN] 未找到 01-08 条目或格式已变,跳过更新", file=sys.stderr)
|
||||
return 1
|
||||
matrix.write_text(new_text, encoding="utf-8", newline="\n")
|
||||
print(f"[OK] 已更新 {matrix}")
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
11
scripts/01-08-verify-haproxy-openwrt.sh
Normal file
11
scripts/01-08-verify-haproxy-openwrt.sh
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
# 调用 01-08-verify-haproxy.sh,传入家庭私网默认参数(18080/18443、onecloud 第三方验证)
|
||||
# 不部署、不改端口;需 OpenWrt HAProxy 已按 18080/18443 配置
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
exec "$ROOT/scripts/01-08-verify-haproxy.sh" \
|
||||
--verify-host onecloud \
|
||||
--openwrt-ip 192.168.2.1 \
|
||||
--http-port 18080 \
|
||||
--https-port 18443 \
|
||||
"$@"
|
||||
211
scripts/01-08-verify-haproxy.sh
Normal file
211
scripts/01-08-verify-haproxy.sh
Normal 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 校验域名,M1~M4 对应(缺省时不校验 HTTPS)
|
||||
--update-matrix 验证通过后更新验证矩阵(默认启用)
|
||||
--no-update-matrix 不更新验证矩阵
|
||||
-h, --help 显示帮助
|
||||
|
||||
前置:ssh openwrt 可用;完整验证还需 ssh onecloud;OpenWrt 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})..."
|
||||
|
||||
# HTTP:TLS 矩阵(有 --https-hosts)按 Host 验证;否则 02-05 路径 /demo-m1~m4
|
||||
if [[ -n "$HTTPS_HOSTS" ]]; then
|
||||
# TLS 矩阵:按 Host 验证,test01~test04 对应 M1~M4
|
||||
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
|
||||
106
scripts/02-verify-nginx-matrix-individual.sh
Normal file
106
scripts/02-verify-nginx-matrix-individual.sh
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env bash
|
||||
# 02 系列逐个验证:清理 → 逐个部署 02-01~02-04 → TLS 矩阵 → onecloud 验证
|
||||
# 用法:./scripts/02-verify-nginx-matrix-individual.sh
|
||||
# 前置:ssh ylc61、ssh onecloud 可用;OpenWrt HAProxy 18080/18443 已部署
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
REMOTE_HOST="${REMOTE_HOST:-ylc61}"
|
||||
REMOTE_USER="${REMOTE_USER:-root}"
|
||||
REMOTE_REPO="${REMOTE_REPO:-/root/实验室建设}"
|
||||
VERIFY_HOST="${VERIFY_HOST:-onecloud}"
|
||||
OPENWRT_IP="${OPENWRT_IP:-192.168.2.1}"
|
||||
HTTP_PORT="${HTTP_PORT:-18080}"
|
||||
HTTPS_PORT="${HTTPS_PORT:-18443}"
|
||||
KUBECONFIG="${KUBECONFIG:-/etc/rancher/k3s/k3s.yaml}"
|
||||
|
||||
SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=10"
|
||||
SSH_KEY="${ROOT_DIR}/.ssh/id_ed25519_k3s_192.168.2.61"
|
||||
[[ -f "$SSH_KEY" ]] && SSH_OPTS="$SSH_OPTS -i $SSH_KEY"
|
||||
SSH_YLC="ssh $SSH_OPTS ${REMOTE_USER}@${REMOTE_HOST}"
|
||||
|
||||
echo "=== 02 系列 nginx 矩阵逐个验证(${REMOTE_HOST} + ${VERIFY_HOST})==="
|
||||
|
||||
# 1. 同步 SSH 密钥与 nginx-matrix 到 ylc61
|
||||
echo "[0] 同步 SSH 密钥与 ansible 到 ${REMOTE_HOST}..."
|
||||
if [[ -d "${ROOT_DIR}/.ssh" ]]; then
|
||||
$SSH_YLC "mkdir -p /root/.ssh && chmod 700 /root/.ssh"
|
||||
for k in "${ROOT_DIR}"/.ssh/id_ed25519_k3s_192.168.2.61 "${ROOT_DIR}"/.ssh/id_ed25519_k3s_192.168.2.62 \
|
||||
"${ROOT_DIR}"/.ssh/id_ed25519_k3s_192.168.2.63 "${ROOT_DIR}"/.ssh/id_ed25519_k3s_192.168.2.64; do
|
||||
[[ -f "$k" ]] || continue
|
||||
scp -q $SSH_OPTS "$k" "${k}.pub" "${REMOTE_USER}@${REMOTE_HOST}:/root/.ssh/" 2>/dev/null || true
|
||||
done
|
||||
$SSH_YLC "chmod 600 /root/.ssh/id_ed25519_k3s_* 2>/dev/null || true"
|
||||
fi
|
||||
|
||||
$SSH_YLC "mkdir -p ${REMOTE_REPO}/ansible/files"
|
||||
rsync -az -e "ssh $SSH_OPTS" --delete "${ROOT_DIR}/ansible/files/nginx-matrix/" \
|
||||
"${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_REPO}/ansible/files/nginx-matrix/" 2>/dev/null || {
|
||||
scp -r $SSH_OPTS "${ROOT_DIR}/ansible/files/nginx-matrix/"* \
|
||||
"${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_REPO}/ansible/files/nginx-matrix/"
|
||||
}
|
||||
|
||||
# 2. 清理所有 nginx 相关资源
|
||||
echo "[1] 清理 nginx 矩阵(path-based + TLS)..."
|
||||
$SSH_YLC "KUBECONFIG=${KUBECONFIG} kubectl delete deployment,svc -n default nginx-m1 nginx-m2 nginx-m3 nginx-m4 --ignore-not-found=true"
|
||||
$SSH_YLC "KUBECONFIG=${KUBECONFIG} kubectl delete ingress -n default nginx-m1 nginx-m3 nginx-m1-http nginx-m3-http --ignore-not-found=true"
|
||||
$SSH_YLC "KUBECONFIG=${KUBECONFIG} kubectl delete ingressroute -n default nginx-m2 nginx-m4 nginx-m2-http nginx-m4-http --ignore-not-found=true"
|
||||
$SSH_YLC "KUBECONFIG=${KUBECONFIG} kubectl delete middleware -n default stripprefix-m1 stripprefix-m2 stripprefix-m3 stripprefix-m4 --ignore-not-found=true"
|
||||
$SSH_YLC "KUBECONFIG=${KUBECONFIG} kubectl delete configmap -n default nginx-m1-html nginx-m2-html nginx-m3-html nginx-m4-html --ignore-not-found=true"
|
||||
sleep 2
|
||||
|
||||
# 3. 逐个部署 02-01~02-04 并验证
|
||||
MATRIX=(
|
||||
"01-control-ingress.yaml:demo-m1:M1"
|
||||
"02-control-ingressroute.yaml:demo-m2:M2"
|
||||
"03-worker-ingress.yaml:demo-m3:M3"
|
||||
"04-worker-ingressroute.yaml:demo-m4:M4"
|
||||
)
|
||||
|
||||
for item in "${MATRIX[@]}"; do
|
||||
file="${item%%:*}"
|
||||
rest="${item#*:}"
|
||||
path="${rest%%:*}"
|
||||
expect="${rest##*:}"
|
||||
echo "[2] 部署 ${file}(${path} → ${expect})..."
|
||||
$SSH_YLC "KUBECONFIG=${KUBECONFIG} kubectl apply -f ${REMOTE_REPO}/ansible/files/nginx-matrix/${file}"
|
||||
$SSH_YLC "KUBECONFIG=${KUBECONFIG} kubectl wait --for=condition=ready pod -l app=nginx-m${expect#M} -n default --timeout=120s"
|
||||
code=$(ssh $SSH_OPTS "$VERIFY_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 10 'http://${OPENWRT_IP}:${HTTP_PORT}/${path}/' 2>/dev/null" || echo "000")
|
||||
body=$(ssh $SSH_OPTS "$VERIFY_HOST" "curl -s --max-time 10 'http://${OPENWRT_IP}:${HTTP_PORT}/${path}/' 2>/dev/null" || echo "")
|
||||
if [[ "$code" != "200" ]]; then
|
||||
echo " [FAIL] /${path}/ 返回 ${code}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$body" != *"$expect"* ]]; then
|
||||
echo " [FAIL] /${path}/ body 不含 ${expect}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " [OK] /${path}/ 200 含 ${expect}"
|
||||
done
|
||||
|
||||
# 4. 部署 TLS 矩阵
|
||||
echo "[3] 部署 nginx TLS 矩阵..."
|
||||
"${ROOT_DIR}/scripts/01-08-deploy-nginx-tls-via-ylc61.sh"
|
||||
|
||||
# 5. 验证 HTTPS(test01~04)
|
||||
echo "[4] 经 ${VERIFY_HOST} 验证 HTTPS(test01~04.jackadam.top:${HTTPS_PORT})..."
|
||||
HTTPS_HOSTS="test01.jackadam.top,test02.jackadam.top,test03.jackadam.top,test04.jackadam.top"
|
||||
IFS=',' read -ra HOSTS <<< "$HTTPS_HOSTS"
|
||||
for i in "${!HOSTS[@]}"; do
|
||||
host="${HOSTS[$i]}"
|
||||
expect="M$((i+1))"
|
||||
code=$(ssh $SSH_OPTS "$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 $SSH_OPTS "$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
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$body" != *"$expect"* ]]; then
|
||||
echo " [FAIL] https://${host}:${HTTPS_PORT}/ body 不含 ${expect}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " [OK] https://${host}:${HTTPS_PORT}/ 200 含 ${expect}"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "[PASS] 02 系列 nginx 矩阵逐个验证通过(02-01~02-04 HTTP path + TLS domain)"
|
||||
57
scripts/03-verify-traefik-dashboard-acme.sh
Normal file
57
scripts/03-verify-traefik-dashboard-acme.sh
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
# 03-03 Traefik Dashboard + ACME 合并配置验证
|
||||
# 用法:./scripts/03-verify-traefik-dashboard-acme.sh [--apply]
|
||||
# 默认:仅核对模板与当前集群状态;加 --apply 时尝试应用 traefik-dashboard-acme 并验证(可能触发 Traefik 重启,新 Pod 需重新获取证书)
|
||||
# 前置:03-02 ACME 已部署(含 cloudflare-api-token);ssh ylc61 可用
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
REMOTE_HOST="${REMOTE_HOST:-ylc61}"
|
||||
REMOTE_USER="${REMOTE_USER:-root}"
|
||||
CFG_SRC="${ROOT_DIR}/ansible/files/traefik-dashboard-acme/traefik-dashboard-acme.yaml"
|
||||
ENTRY_IP="${ENTRY_IP:-192.168.2.61}"
|
||||
OPENWRT_IP="${OPENWRT_IP:-192.168.2.1}"
|
||||
HTTPS_PORT="${HTTPS_PORT:-18443}"
|
||||
DO_APPLY=0
|
||||
[[ "${1:-}" == "--apply" ]] && DO_APPLY=1
|
||||
|
||||
SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=10"
|
||||
SSH_KEY="${ROOT_DIR}/.ssh/id_ed25519_k3s_192.168.2.61"
|
||||
[[ -f "$SSH_KEY" ]] && SSH_OPTS="$SSH_OPTS -i $SSH_KEY"
|
||||
SSH_CMD="ssh $SSH_OPTS ${REMOTE_USER}@${REMOTE_HOST}"
|
||||
KUBECONFIG="/etc/rancher/k3s/k3s.yaml"
|
||||
|
||||
echo "=== 03-03 Traefik Dashboard + ACME 验证 ==="
|
||||
|
||||
# 1. 核对 traefik-dashboard-acme 模板包含 03-01 + 03-02 要素
|
||||
echo "[1/3] 核对模板(dashboard + ACME + ping + PROXY)..."
|
||||
grep -q "api.dashboard=true" "$CFG_SRC" && grep -q "api.insecure=true" "$CFG_SRC" || { echo " [FAIL] 缺少 dashboard 参数"; exit 1; }
|
||||
grep -q "certificatesresolvers.cloudflare" "$CFG_SRC" && grep -q "acme.dnschallenge" "$CFG_SRC" || { echo " [FAIL] 缺少 ACME 参数"; exit 1; }
|
||||
grep -q "ping.entryPoint=websecure" "$CFG_SRC" && grep -q "proxyProtocol.trustedIPs" "$CFG_SRC" || { echo " [FAIL] 缺少 ping/PROXY 参数"; exit 1; }
|
||||
grep -q "ingressRoute:" "$CFG_SRC" && grep -q "dashboard:" "$CFG_SRC" || true
|
||||
echo " [OK] 模板包含 03-01 + 03-02 合并要素"
|
||||
|
||||
# 2. 当前集群 ACME 状态
|
||||
echo "[2/3] 当前集群 ACME(test01.jackadam.top)..."
|
||||
CODE=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 10 "https://test01.jackadam.top/" --resolve "test01.jackadam.top:443:${ENTRY_IP}" 2>/dev/null || echo "000")
|
||||
[[ "$CODE" != "200" ]] && CODE=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 10 "https://test01.jackadam.top:${HTTPS_PORT}/" --resolve "test01.jackadam.top:${HTTPS_PORT}:${OPENWRT_IP}" 2>/dev/null || echo "000")
|
||||
[[ "$CODE" == "200" ]] && echo " [OK] ACME TLS 200" || echo " [WARN] ACME 返回 ${CODE}"
|
||||
|
||||
# 3. 可选 apply
|
||||
if [[ $DO_APPLY -eq 1 ]]; then
|
||||
echo "[3/3] 应用 traefik-dashboard-acme(会触发 Traefik 重启)..."
|
||||
EMAIL=$($SSH_CMD "KUBECONFIG=${KUBECONFIG} kubectl get helmchartconfig traefik -n kube-system -o jsonpath='{.spec.valuesContent}' 2>/dev/null" | grep -oE 'acme\.email=[^[:space:]\"'"'"']+' | cut -d= -f2 | head -1)
|
||||
[[ -z "$EMAIL" ]] && EMAIL="<YOUR_REAL_EMAIL>"
|
||||
$SSH_CMD "mkdir -p /tmp/traefik-verify"
|
||||
scp -q $SSH_OPTS "$CFG_SRC" "${REMOTE_USER}@${REMOTE_HOST}:/tmp/traefik-verify/traefik-dashboard-acme.yaml"
|
||||
$SSH_CMD "sed -i 's|<YOUR_REAL_EMAIL>|'"$EMAIL"'|g' /tmp/traefik-verify/traefik-dashboard-acme.yaml"
|
||||
$SSH_CMD "KUBECONFIG=${KUBECONFIG} kubectl apply -f /tmp/traefik-verify/traefik-dashboard-acme.yaml"
|
||||
$SSH_CMD "KUBECONFIG=${KUBECONFIG} kubectl -n kube-system rollout status deploy/traefik --timeout=180s" || echo " [WARN] rollout 超时,可检查 Pod 与 ACME 日志"
|
||||
CODE=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "http://${ENTRY_IP}/dashboard/" 2>/dev/null || echo "000")
|
||||
[[ "$CODE" == "200" || "$CODE" == "307" ]] && echo " [OK] Dashboard 返回 ${CODE}" || echo " [WARN] Dashboard 返回 ${CODE}"
|
||||
else
|
||||
echo "[3/3] 跳过 apply(加 --apply 可尝试应用并验证 Dashboard)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[PASS] 03-03 验证完成"
|
||||
@@ -3,6 +3,18 @@
|
||||
本目录集中维护 K3s 排障与恢复脚本。统一约定:**在仓库根目录执行**,使用 `./scripts/...` 路径调用。
|
||||
|
||||
## 目录
|
||||
- `scripts/01-08-deploy-openwrt-haproxy.sh`
|
||||
- 一键部署:uhttpd 改回 80/443(IPv4+IPv6),HAProxy 部署到 18080/18443(默认 haproxy-tls)
|
||||
- `scripts/01-08-deploy-nginx-tls-via-ylc61.sh`
|
||||
- 经 ssh ylc61 在控制节点上一键部署 nginx TLS 矩阵(M1~M4,test01~04);同步 ansible + SSH 密钥后执行 playbook
|
||||
- `scripts/03-verify-traefik-dashboard-acme.sh`
|
||||
- 03-03 配置验证:核对 traefik-dashboard-acme 模板合并 03-01+03-02 要素;检查当前 ACME;可选 `--apply` 尝试应用(会触发 Traefik 重启)
|
||||
- `scripts/02-verify-nginx-matrix-individual.sh`
|
||||
- 02 系列逐个验证:清理 → 逐个部署 02-01~02-04(path-based)→ TLS 矩阵 → onecloud 验证 HTTP path + HTTPS domain;验证通过后需手动更新 `docs/00-02-验证矩阵.md`
|
||||
- `scripts/01-08-verify-haproxy-openwrt.sh`
|
||||
- 家庭私网默认:调用主脚本,18080/18443、onecloud 第三方验证(见 `docs/01-08-openwrt-haproxy.md`)
|
||||
- `scripts/01-08-verify-haproxy.sh`
|
||||
- **核心**:校验 `ansible/files/01-08-haproxy/*.cfg` 在 OpenWrt 上 `haproxy -c` 通过;`--cfg-only` 仅做语法校验、不 curl。完整流程另经 ssh onecloud 验证 HTTP/HTTPS;可选 `--deploy-matrix http|tls`、`--https-hosts`;验证通过可更新验证矩阵
|
||||
- `scripts/ssh/setup-k3s-workers-ssh.sh`
|
||||
- 为 Ansible 自动化准备 SSH:为所有 k3s 节点配置 jack + root 公钥及每节点私钥(配合 `docs/01-07-节点初始化-ansible-实践.md`)
|
||||
- `scripts/diag/entrypath/entrypath.sh`
|
||||
@@ -20,9 +32,8 @@
|
||||
|
||||
## 从仓库根执行示例
|
||||
|
||||
`bas\1
|
||||
|
||||
\21) 初始化排障 SSH 密钥(可选)
|
||||
```bash
|
||||
# 1) 初始化排障 SSH 密钥(可选)
|
||||
./scripts/diag/ssh/setup-ssh-keys.sh
|
||||
|
||||
# 2) 验证 SSH(建议)
|
||||
@@ -52,7 +63,7 @@
|
||||
--pod-netns-trace-mode y \
|
||||
--pod-netns-trace-seconds 12 \
|
||||
--non-interactive
|
||||
`
|
||||
```
|
||||
|
||||
## 说明文档
|
||||
|
||||
|
||||
Reference in New Issue
Block a user