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,49 @@
#!/usr/bin/env bash
# 经 ssh ylc61 在控制节点上一键部署 nginx TLS 矩阵M1M4test0104.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 密钥到 ylc61ansible 连接各节点需此)
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'"

View File

@@ -0,0 +1,61 @@
#!/usr/bin/env bash
# OpenWrtuhttpd 改回 80/443IPv4+IPv6HAProxy 部署到 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/443IPv4 + 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/443IPv4+IPv6"
echo " - HAProxy: 18080/18443"

View 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())

View 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 \
"$@"

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

View File

@@ -0,0 +1,106 @@
#!/usr/bin/env bash
# 02 系列逐个验证:清理 → 逐个部署 02-0102-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-0102-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. 验证 HTTPStest0104
echo "[4] 经 ${VERIFY_HOST} 验证 HTTPStest0104.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-0102-04 HTTP path + TLS domain"

View 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-tokenssh 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] 当前集群 ACMEtest01.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 验证完成"

View File

@@ -3,6 +3,18 @@
本目录集中维护 K3s 排障与恢复脚本。统一约定:**在仓库根目录执行**,使用 `./scripts/...` 路径调用。
## 目录
- `scripts/01-08-deploy-openwrt-haproxy.sh`
- 一键部署uhttpd 改回 80/443IPv4+IPv6HAProxy 部署到 18080/18443默认 haproxy-tls
- `scripts/01-08-deploy-nginx-tls-via-ylc61.sh`
- 经 ssh ylc61 在控制节点上一键部署 nginx TLS 矩阵M1M4test0104同步 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-0102-04path-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
`
```
## 说明文档