跳转至

RUNBOOK — 服务暴露编排(内网 / 公网入口链路)

交付物目录:ingress_tunnel_deploy/(相对项目根目录 k8s_ins/) 本文写给接手日常运维与值班的人:不假设你熟悉这套链路,凌晨被叫起来也能照着做完。 变更档案(这次改了什么、怎么退)见同目录 SOP.md;备份台账见 backup/README.md。

目录

1. 服务概览

它是干什么的

把内网服务按声明的"暴露面"投放到公网或内网:

公网用户 ──► 香港 nginx(443, LE 证书) ──► 本机 8082/8443 ──► frp 隧道
                                                              │
                        OpenWrt frpc(192.168.31.2) ◄──────────┘
                                                              │
                        traefik(192.168.31.10:80/443) ◄───────┘
                                                              │
                        IngressRoute / IngressRouteTCP ──► 业务 Service

内网 TCP(如 MariaDB)不走隧道,直接由内网 traefik 的 hostPort 暴露给内网。

组件构成与依赖

组件 位置 版本 作用
nginx 香港 129.226.138.204 1.20.1 公网 80/443 入口,按域名分流;80 兼做 ACME 校验与 301 跳转
frps 香港 129.226.138.204 0.70.1 隧道服务端:bindPort 5443、vhostHTTPPort 81、面板 6443
certbot 香港 129.226.138.204 1.11.0 Let's Encrypt 证书签发/续期(webroot / HTTP-01)
frpc OpenWrt 192.168.31.2 0.70.1 隧道客户端,由 frpc-tunnel 服务托管
traefik k8s 192.168.31.10 v3.7.13 内网入口代理,hostPort 80/443/389/636/3306
编排脚本 执行机(本仓库) — ./run.sh 收敛全部配置,幂等、自动备份

依赖关系:公网访问依赖「DNS → 香港 nginx → frp 隧道 → traefik → 业务」全链路,任一段故障公网即不可用。内网 MariaDB 只依赖 traefik。

异常时的业务影响

故障点 影响
香港机整体故障 5 个公网域名全部不可访问;内网服务与 MariaDB 不受影响
frps / frpc / 隧道断 同上(公网全断,内网正常)
traefik 故障 公网全断 + 内网 MariaDB 中断 + 内网其他 traefik 服务中断
单张证书过期 仅该域名浏览器告警或拒绝访问,其余域名正常

重要性等级

高。公网入口是单点(frps、frpc、traefik 各一份),无冗余;且 MariaDB 内网入口同样依赖 traefik 单点。

2. 接入与凭据

访问入口

暴露面 服务 入口 后端
公网 GitLab https://gitlab.rainchen.top traefik websecure → Envoy Gateway
公网 Prometheus https://prometheus.rainchen.top traefik → kube-prometheus-stack-prometheus:9090
公网 Grafana https://grafana.rainchen.top traefik → kube-prometheus-stack-grafana:80
公网 Traefik Dashboard https://traefik.rainchen.top traefik api@internal(BasicAuth)
公网 phpLDAPadmin https://ldapadmin.rainchen.top traefik web → phpldapadmin-web:80
公网 frps 面板(未纳入本工程) http://fps.rainchen.top 香港 nginx → 127.0.0.1:6443
内网 MariaDB 192.168.31.10:3306 traefik TCP entryPoint → mariadb:3306

凭据从哪取(文档不记录明文)

用途 存放位置 取用命令
Traefik Dashboard BasicAuth traefik_deploy/secrets/dashboard-basic-auth.txt(权限 600) cat traefik_deploy/secrets/dashboard-basic-auth.txt
Grafana 管理员 k8s Secret monitoring/grafana-admin kubectl -n monitoring get secret grafana-admin -o jsonpath='{.data.admin-user}' \| base64 -d; echo; kubectl -n monitoring get secret grafana-admin -o jsonpath='{.data.admin-password}' \| base64 -d; echo
GitLab root k8s Secret server/gitlab-gitlab-initial-root-password kubectl -n server get secret gitlab-gitlab-initial-root-password -o jsonpath='{.data.password}' \| base64 -d; echo
MariaDB root k8s Secret server/mariadb-root kubectl -n server get secret mariadb-root -o jsonpath='{.data.password}' \| base64 -d; echo
frps 面板账号 香港机 /usr/local/frps/frps.toml 的 webServer.user / webServer.password timeout 20 ssh root@129.226.138.204 "grep -n webServer /usr/local/frps/frps.toml"
frp 隧道 token 香港机 /usr/local/frps/frps.toml、OpenWrt /etc/frp/frpc.toml 的 auth.token 同上(两端必须一致)
phpLDAPadmin 登录 DN LDAP cn=admin,dc=rainchen,dc=com,口令见 ldap-deploy/values-openldap.yaml(权限 600) grep -n -i pass ldap-deploy/values-openldap.yaml
Let's Encrypt 注册邮箱 config/ingress.yaml 的 tls.email grep -n email config/ingress.yaml

客户端接入示例

MariaDB(内网任意机器):

mysql -h 192.168.31.10 -P 3306 -u <账号> -p

若无 mysql 客户端,用 socket 直接读握手包判断链路是否通到真实库:

python3 - <<'EOF'
import socket
with socket.create_connection(("192.168.31.10", 3306), timeout=5) as s:
    data = s.recv(256)
print("protocol=", data[4], "server=", data[5:data.find(b"\x00", 5)].decode())
EOF
# 预期:protocol= 10 server= 12.3.3-MariaDB-ubu2404

3. 日常速查表

我要做什么 命令
看整体是否正常(最快) for d in gitlab prometheus grafana traefik ldapadmin; do curl -s -o /dev/null -w "$d %{http_code}\n" https://$d.rainchen.top/; done
收敛全部配置(日常唯一动作) cd /home/rain/Documents/k8s_ins/ingress_tunnel_deploy && ./run.sh
只看会改什么、不动手 ./run.sh --dry-run
香港机 nginx 状态 timeout 20 ssh root@129.226.138.204 "systemctl status nginx --no-pager -l \| head -12"
香港机 frps 状态 timeout 20 ssh root@129.226.138.204 "/etc/rc.d/init.d/frps status"
隧道端口是否在监听 timeout 20 ssh root@129.226.138.204 "ss -lnt \| grep -E ':(8082\|8443) '"
frpc 状态 timeout 20 ssh root@192.168.31.2 "/etc/init.d/frpc-tunnel status"
traefik 状态 kubectl -n server get pod -l app.kubernetes.io/name=traefik -o wide
证书还剩几天 timeout 20 ssh root@129.226.138.204 "for c in \$(ls /etc/letsencrypt/live/ \| grep -v README); do printf '%-30s %s 天\n' \$c \$(( (\$(date -d \"\$(openssl x509 -in /etc/letsencrypt/live/\$c/fullchain.pem -noout -enddate \| cut -d= -f2)\" +%s) - \$(date +%s)) / 86400 )); done"
回滚到变更前 cd /home/rain/Documents/k8s_ins/ingress_tunnel_deploy && ./run.sh --rollback(详见 SOP.md 第 7 章)
定时任务日志 tail -n 50 /home/rain/Documents/k8s_ins/ingress_tunnel_deploy/logs/cron.log

4. 日常操作

4.1 状态检查(三层)

# 第一层:公网可用性(最快判断)
for d in gitlab prometheus grafana traefik ldapadmin; do
  printf "%-30s" "$d.rainchen.top"; curl -s -o /dev/null -w "%{http_code}\n" "https://$d.rainchen.top/"
done
# 预期:gitlab/prometheus/grafana/ldapadmin = 302(跟随跳转后 200),traefik = 401
# 第二层:隧道两端
timeout 20 ssh root@129.226.138.204 "ss -lnt | grep -E ':(8082|8443) '"
# 预期:两行 LISTEN(frps 侧落地端口)
timeout 20 ssh root@192.168.31.2 "/etc/init.d/frpc-tunnel status"
# 预期:running
# 第三层:内网入口与路由
kubectl -n server get pod -l app.kubernetes.io/name=traefik -o wide
# 预期:1/1 Running,NODE=k8s-master-01
kubectl -n server get ingressroute gitlab -o wide
kubectl -n server get ingressroutetcp mariadb -o wide
# 预期:两条都存在

4.2 启动 / 停止 / 重启

组件 命令 备注
香港 nginx timeout 20 ssh root@129.226.138.204 "systemctl reload nginx" 优先 reload(平滑);restart 会瞬断
香港 frps timeout 20 ssh root@129.226.138.204 "/etc/rc.d/init.d/frps restart" 支持 start\|stop\|restart\|status\|config\|info\|version;重启会断开所有隧道
OpenWrt frpc timeout 20 ssh root@192.168.31.2 "/etc/init.d/frpc-tunnel restart" 【高危】断开隧道约 5 秒;frpc 由 procd respawn 托管,进程崩溃会自动拉起
traefik kubectl -n server rollout restart deploy/traefik 【高危】单副本 + hostPort 需"先停旧再起新",公网入口中断数秒
编排脚本 cd /home/rain/Documents/k8s_ins/ingress_tunnel_deploy && ./run.sh 幂等;无需手工重启上述组件

注意:frps 未注册开机自启(/etc/rc.d/rc3.d/ 下无软链),香港机重启后需手工 /etc/rc.d/init.d/frps start,否则公网全断。见第 8 章场景 2。

4.3 日志查看

# 香港 nginx:访问日志与错误日志
timeout 20 ssh root@129.226.138.204 "tail -n 50 /var/log/nginx/error.log"
timeout 20 ssh root@129.226.138.204 "tail -n 50 /var/log/nginx/access.log"

# 香港 frps:隧道注册与转发错误
timeout 20 ssh root@129.226.138.204 "tail -n 50 /usr/local/frps/frps.log | grep -E 'proxy|error|success'"

# OpenWrt frpc(注意:/var 是 tmpfs,路由器重启后日志清空)
timeout 20 ssh root@192.168.31.2 "tail -n 50 /var/log/frpc.log"

# traefik
kubectl -n server logs deploy/traefik --tail=100
kubectl -n server logs deploy/traefik --tail=200 | grep -iE "error|err"

# 编排脚本日志(含每次执行的完整命令与返回码)
tail -n 100 /home/rain/Documents/k8s_ins/ingress_tunnel_deploy/logs/ingress_tunnel.log

4.4 进入排障现场

# 香港机 / OpenWrt(执行机已配置 root 免密)
ssh root@129.226.138.204
ssh root@192.168.31.2

# k8s 集群
kubectl -n server get pods
kubectl -n server exec -it deploy/traefik -- sh
kubectl -n server exec -it mariadb-0 -- sh          # MariaDB 容器
kubectl -n server exec -it mariadb-0 -- sh -c 'mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" -e "SELECT VERSION();"'

# MariaDB 数据目录与 CR(mariadb-operator 管理)
kubectl -n server get mariadb mariadb -o yaml
kubectl -n server get sts mariadb -o wide

4.5 手工验证单条链路

# 绕过公网,直接在香港机本地验证「nginx → 隧道 → traefik → 业务」是否通
timeout 20 ssh root@129.226.138.204 "curl -sk -o /dev/null -w '%{http_code}\n' --resolve gitlab.rainchen.top:443:127.0.0.1 https://gitlab.rainchen.top/"
# 预期:302;若 502 → 隧道或后端问题(见场景 2);若连接失败 → nginx 未监听

# 只验证隧道到内网 traefik 这一段(香港机本地直连落地端口)
timeout 20 ssh root@129.226.138.204 "curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8082/"
# 预期:404(traefik 已接管且无匹配 Host);连接拒绝 → 隧道断

5. 配置管理

配置在哪

配置 位置 归属
服务清单(唯一日常改动点) ingress_tunnel_deploy/config/ingress.yaml 本工程
香港 nginx 主配置 香港机 /etc/nginx/nginx.conf 本工程只清理旧 server 块,其余不动
香港 nginx 业务配置 香港机 /etc/nginx/conf.d/k8s-ingress.conf 脚本全量生成,请勿手工修改
frpc 主配置 OpenWrt /etc/frp/frpc.toml 外部工程 frp_openvpn_tunnel 生成
frpc 隧道片段 OpenWrt /etc/frp/conf.d/k8s-ingress.toml 脚本全量生成,请勿手工修改
frps 配置 香港机 /usr/local/frps/frps.toml 本工程不管
traefik values traefik_deploy/values.yaml traefik 主题;内网 TCP 端口需在此声明
k8s 路由清单 ingress_tunnel_deploy/manifests/*.yaml 脚本生成,另有 .before.yaml 为变更前留档

修改流程

cd /home/rain/Documents/k8s_ins/ingress_tunnel_deploy
vim config/ingress.yaml      # 1. 改清单(新增服务写法见 SOP.md 附录 A)
./run.sh --dry-run           # 2. 预演,确认将要发生的变更
./run.sh                     # 3. 收敛:证书 → nginx → frp → 路由 → 端到端验证

生效方式:脚本按内容指纹比对,有变化才下发并 reload/restart;无变化则整体 skipped。

易错点

  1. 内网 TCP 新增端口必须先改 traefik:traefik 的 entryPoint 是静态配置,本工程只能校验。缺了会在 pre_check 直接报错并提示,不会静默失败。
  2. 暴露面组合约束:exposure: internal 只能配 backend: k8s;exposure: public 只能配 backend: host;违反会被拦下。
  3. 公网域名必须先做解析,否则证书签发会失败(HTTP-01 校验不过)。
  4. 不要手工改生成的文件(conf.d/k8s-ingress.conf、conf.d/k8s-ingress.toml),下次执行会被覆盖;长期改动请改 config/ingress.yaml。
  5. frpc.toml 可能被外部工程覆盖:重跑 frp_openvpn_tunnel 会丢掉 includes 行,隧道随之消失;重跑一次 ./run.sh 即自动补回。
  6. 香港机安全组对公网全放行:清单里写什么端口,什么端口就会对公网开放,改配置前先确认暴露面。

6. 备份与恢复

备份策略

  • 触发方式:由 ./run.sh 在每次实际变更前自动执行,无需人工干预(预演模式不备份)。
  • 命名:<原文件名>.bak.<YYYYmmdd-HHmmss>
  • 位置:与被改文件同目录(香港机 /etc/nginx/、OpenWrt /etc/frp/)。这是刻意设计——--rollback 依赖"同目录最近一次 .bak.*"。
  • 台账:全部备份逐条登记在 ingress_tunnel_deploy/backup/README.md,含原路径、产生时间、因何产生、何时可删。
  • 基线留档:变更前原始内容另存本仓库 backup/etc/...(已校验与远端 MD5 一致)。

手工备份(变更前自查)

# 香港机两份配置
timeout 20 ssh root@129.226.138.204 "cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.\$(date +%Y%m%d-%H%M%S)"
timeout 20 ssh root@129.226.138.204 "cp -a /etc/nginx/conf.d/k8s-ingress.conf /etc/nginx/conf.d/k8s-ingress.conf.bak.\$(date +%Y%m%d-%H%M%S)"

# OpenWrt 两份配置
timeout 20 ssh root@192.168.31.2 "cp -a /etc/frp/frpc.toml /etc/frp/frpc.toml.bak.\$(date +%Y%m%d-%H%M%S)"
timeout 20 ssh root@192.168.31.2 "cp -a /etc/frp/conf.d/k8s-ingress.toml /etc/frp/conf.d/k8s-ingress.toml.bak.\$(date +%Y%m%d-%H%M%S)"

恢复步骤

优先用脚本(会做 nginx -t 校验后才 reload):

cd /home/rain/Documents/k8s_ins/ingress_tunnel_deploy && ./run.sh --rollback

手工恢复单个文件(以香港机 nginx 主配置为例):

# 1. 看有哪些备份可选(按时间倒序,第一条最新)
timeout 20 ssh root@129.226.138.204 "ls -1t /etc/nginx/nginx.conf.bak.*"

# 2. 指定某一份恢复(建议显式写文件名,别用通配)
timeout 20 ssh root@129.226.138.204 "cp -a /etc/nginx/nginx.conf.bak.20260918-025352 /etc/nginx/nginx.conf"

# 3. 校验并生效(校验不通过就不要 reload)
timeout 20 ssh root@129.226.138.204 "nginx -t && systemctl reload nginx"

恢复后的验证:

for d in gitlab prometheus grafana traefik ldapadmin; do
  printf "%-30s" "$d.rainchen.top"; curl -s -o /dev/null -w "%{http_code}\n" "https://$d.rainchen.top/"
done

演练记录

时间 内容 结果
2026-09-18 02:53–03:18 变更期间共生成 34 份自动备份(含中间态);nginx -t 校验机制生效,未发生"坏配置进入生产" 通过
— 正式回滚演练:未执行。--rollback 的代码路径未在真实故障下验证过 待补

建议在业务低峰期做一次演练:./run.sh --rollback 后立即 ./run.sh 重建,观察公网中断时长并记录到本表。演练会真实中断公网入口,需提前告知使用方。

7. 监控与告警

当前监控覆盖

对象 手段 状态
k8s 集群 / 各 Pod kube-prometheus-stack(namespace monitoring) ✅ 已覆盖
香港入口机 主机上装了 node_exporter(:9100) ⚠️ 未被内网 Prometheus 采集(ServiceMonitor 清单中无对应条目),属监控盲区
frps / frpc / nginx 业务指标 无 ⚠️ 仅靠日志与手工检查
证书有效期 无自动告警(依赖每日 run.sh 顺带检查与续期) ⚠️ 建议补

关键指标与查看入口

看什么 怎么看
公网 5 个域名可用性 速查表第 1 条命令
隧道落地端口是否监听 timeout 20 ssh root@129.226.138.204 "ss -lnt \| grep -E ':(8082\|8443) '"
证书剩余天数 速查表「证书还剩几天」
nginx 5xx 比例 timeout 20 ssh root@129.226.138.204 "awk '\$9 ~ /^5/ {n++} END {print n+0}' /var/log/nginx/access.log"
traefik 报错 kubectl -n server logs deploy/traefik --tail=200 \| grep -iE "error"
香港机资源水位 timeout 20 ssh root@129.226.138.204 "uptime; free -m \| head -2; df -h / \| tail -1"
Grafana https://grafana.rainchen.top(凭据见第 2 章)
Prometheus https://prometheus.rainchen.top

建议关注(按优先级)

  1. 证书剩余 < 15 天 → 立即手工跑一次 ./run.sh 并确认续期成功(每日定时任务正常时不应出现)。
  2. 8082/8443 任一未监听 → 隧道断,公网全断,按场景 2 处置。
  3. 公网域名返回 5xx → 按场景 1 处置。
  4. 香港机根分区 > 90% → 会影响证书签发(certbot 需要写盘)与日志,按第 10 章处置。
  5. 香港机重启后 → frps 不会自启,必须手工拉起(场景 2)。

8. 故障处置

场景 1:某(些)公网域名打不开,返回 502 / 504 / 卡住

症状:浏览器报 502 Bad Gateway 或超时;其它域名可能正常。

诊断

  1. 确认范围——是所有域名还是单个 bash for d in gitlab prometheus grafana traefik ldapadmin; do printf "%-30s" "$d.rainchen.top"; curl -s -o /dev/null -w "%{http_code}\n" "https://$d.rainchen.top/" done 预期:全部 302/401。若只有一个异常 → 多半是该后端服务或路由问题(跳到第 4 步)。

  2. 定位是哪一段断的——在香港机本地绕开公网直连 bash timeout 20 ssh root@129.226.138.204 "curl -s -o /dev/null -w '%{http_code}\n' --resolve gitlab.rainchen.top:443:127.0.0.1 https://gitlab.rainchen.top/"

  3. 预期 302 → nginx 与隧道都正常,问题在内网后端(第 4 步)
  4. 502 → 隧道或后端断(第 3 步)
  5. 连接失败 → nginx 没在监听(systemctl status nginx)

  6. 看隧道是否活着 bash timeout 20 ssh root@129.226.138.204 "ss -lnt | grep -E ':(8082|8443) '" timeout 20 ssh root@192.168.31.2 "/etc/init.d/frpc-tunnel status" 两端口未监听或 frpc 非 running → 按场景 2 处置。

  7. 内网后端与路由 bash kubectl -n server get pod -l app.kubernetes.io/name=traefik -o wide # 预期 1/1 Running kubectl -n server get ingressroute -A # 预期含 traefik-dashboard/grafana/prometheus/phpldapadmin-web/gitlab kubectl -n server get pod # 后端(如 gitlab-webservice-*)是否 Running kubectl -n server logs deploy/traefik --tail=100 | grep -iE "error|502|no available"

处置

  • nginx 未运行 → timeout 20 ssh root@129.226.138.204 "systemctl restart nginx",并 nginx -t 确认配置无误。
  • 隧道断 → 场景 2。
  • 路由缺失 → 跑一次收敛:cd /home/rain/Documents/k8s_ins/ingress_tunnel_deploy && ./run.sh(幂等,只补缺失项)。
  • 后端 Pod 异常 → 属业务服务问题,按该服务的 RUNBOOK/SOP 处理(本工程不涉及)。
  • 配置被误改 → ./run.sh --rollback 或按第 6 章手工恢复(【高危】会覆盖当前配置,先备份)。

验证:重跑场景 1 诊断第 1 步,5 个域名应全部恢复 302/401。

场景 2:隧道断了(公网全断)

症状:所有公网域名 502 或超时;内网服务正常;香港机 8082/8443 无监听。

诊断

  1. 香港机 frps 是否在跑 bash timeout 20 ssh root@129.226.138.204 "/etc/rc.d/init.d/frps status" timeout 20 ssh root@129.226.138.204 "ss -lntp | grep -E ':(5443|6443)'" 预期:进程存在,5443(隧道)与 6443(面板)在监听。若进程不存在 → 见处置第 1 条。

  2. frps 是否收到了客户端 bash timeout 20 ssh root@129.226.138.204 "tail -n 50 /usr/local/frps/frps.log | grep -iE 'login|new proxy|client exit'" 预期:有 client login 与 new proxy 记录。大量 client exit → frpc 侧在反复重连,看第 3 步。

  3. OpenWrt frpc 状态与日志 bash timeout 20 ssh root@192.168.31.2 "/etc/init.d/frpc-tunnel status" timeout 20 ssh root@192.168.31.2 "tail -n 30 /var/log/frpc.log" timeout 20 ssh root@192.168.31.2 "netstat -tnp 2>/dev/null | grep 5443" 预期:running、日志有 login to server success、有到 129.226.138.204:5443 的 ESTABLISHED 连接。

  4. 隧道配置是否还在(被外部工程覆盖时会丢) bash timeout 20 ssh root@192.168.31.2 "grep -c includes /etc/frp/frpc.toml" timeout 20 ssh root@192.168.31.2 "cat /etc/frp/conf.d/k8s-ingress.toml" 预期:includes 计数为 1;片段内应有 traefik-web(8082)与 traefik-websecure(8443)两条 [[proxies]]。

处置

  1. frps 没在跑(香港机刚重启过时最常见): bash timeout 20 ssh root@129.226.138.204 "/etc/rc.d/init.d/frps start" timeout 20 ssh root@129.226.138.204 "ss -lnt | grep -E ':(5443|6443)'" # 确认起来了
  2. frps 在跑但 frpc 未连上 → 重启隧道客户端:timeout 20 ssh root@192.168.31.2 "/etc/init.d/frpc-tunnel restart"
  3. 配置丢失(includes 或片段缺失)→ 跑一次收敛自动补回:cd /home/rain/Documents/k8s_ins/ingress_tunnel_deploy && ./run.sh
  4. 香港机连不上(网络/主机故障)→ 属主机故障,按香港机自身处置流程;公网在此期间不可用,需告知使用方。

验证

timeout 20 ssh root@129.226.138.204 "ss -lnt | grep -E ':(8082|8443) '"
# 预期:两行 LISTEN
for d in gitlab prometheus grafana traefik ldapadmin; do
  printf "%-30s" "$d.rainchen.top"; curl -s -o /dev/null -w "%{http_code}\n" "https://$d.rainchen.top/"
done
# 预期:全部恢复 302/401

场景 3:证书即将到期 / 续期失败

症状:浏览器提示证书过期或不安全;或 run.sh 日志出现 证书签发失败。

诊断

  1. 看各证书剩余天数(速查表「证书还剩几天」)。预期 > 30 天;< 15 天即异常。
  2. 看每日定时任务是否在跑 bash crontab -l | grep ingress_tunnel tail -n 50 /home/rain/Documents/k8s_ins/ingress_tunnel_deploy/logs/cron.log
  3. 手工跑一次续期预演(不消耗 LE 生产配额) bash timeout 240 ssh root@129.226.138.204 "certbot renew --dry-run 2>&1 | tail -20" 预期:所有证书 simulating renewal 成功。若报 challenge failed → ACME 校验没打通,检查: bash # 80 端口是否公网可达、能否读到校验文件 timeout 20 ssh root@129.226.138.204 "mkdir -p /var/www/letsencrypt/.well-known/acme-challenge && echo ok > /var/www/letsencrypt/.well-known/acme-challenge/probe" curl -s http://gitlab.rainchen.top/.well-known/acme-challenge/probe # 预期输出 ok timeout 20 ssh root@129.226.138.204 "rm -f /var/www/letsencrypt/.well-known/acme-challenge/probe"

处置

  • ACME 路径不通 → 多半是 nginx 未加载业务配置:timeout 20 ssh root@129.226.138.204 "nginx -t && systemctl reload nginx"
  • 到期但续期失败 → 手工强制续期(【高危】会改动生产证书,先备份 /etc/letsencrypt): bash timeout 20 ssh root@129.226.138.204 "cp -a /etc/letsencrypt /root/letsencrypt.bak.\$(date +%Y%m%d-%H%M%S)" timeout 200 ssh root@129.226.138.204 "certbot certonly --webroot -w /var/www/letsencrypt -d gitlab.rainchen.top --email saier_cy@163.com --agree-tos --no-eff-email --non-interactive" timeout 20 ssh root@129.226.138.204 "nginx -t && systemctl reload nginx"
  • certbot 1.11.0 已很旧(CentOS 7 已 EOL),若持续失败 → 用 acme.sh 兜底签发后把证书放到 /etc/letsencrypt/live/<域名>/(或改用香港机外的机器签发再同步)。

验证

timeout 20 openssl s_client -connect gitlab.rainchen.top:443 -servername gitlab.rainchen.top </dev/null 2>/dev/null | openssl x509 -noout -dates
# 预期:notAfter 距今天 > 60 天
curl -s -o /dev/null -w '%{http_code} tls=%{ssl_verify_result}\n' https://gitlab.rainchen.top/
# 预期:302 tls=0

场景 4:内网连不上 MariaDB(192.168.31.10:3306)

症状:客户端报 Can't connect to MySQL server;nc -vz 192.168.31.10 3306 失败或握手超时。

诊断

  1. 端口是否通(不依赖 mysql 客户端) bash timeout 4 bash -c 'echo > /dev/tcp/192.168.31.10/3306' && echo 端口可达 || echo 端口不可达
  2. 路由资源是否还在 bash kubectl -n server get ingressroutetcp mariadb -o yaml # 预期:spec.entryPoints: [mariadb],services: mariadb:3306
  3. 后端 Pod 与 Service bash kubectl -n server get pod mariadb-0 -o wide # 预期 1/1 Running kubectl -n server get svc mariadb # 预期 ClusterIP 3306
  4. traefik 是否仍声明了该 entryPoint(被回退过就会没) bash kubectl -n server get pod -l app.kubernetes.io/name=traefik -o jsonpath='{range .items[0].spec.containers[0].ports[*]}{.name}:{.hostPort}{" "}{end}' # 预期输出中包含 mariadb:3306
  5. 数据库自身是否在监听 bash kubectl -n server exec mariadb-0 -- sh -c 'mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" -e "SELECT VERSION();"'

处置

  • 第 2 步资源缺失 → cd /home/rain/Documents/k8s_ins/ingress_tunnel_deploy && ./run.sh(自动重建路由)
  • 第 4 步缺 mariadb entryPoint → 说明 traefik values 被回退过;改回 traefik_deploy/values.yaml 并 helm upgrade(【高危】公网入口会中断数秒),命令见 SOP.md 第 5 章步骤 5.0
  • 第 3/5 步 Pod 或数据库异常 → 属 MariaDB(mariadb-operator)自身问题,检查: bash kubectl -n server describe pod mariadb-0 | tail -30 kubectl -n server logs mariadb-0 --tail=100 kubectl -n server get mariadb mariadb -o yaml
  • 认证类报错(Access denied)→ 账号/密码问题,不属链路故障;用 kubectl -n server get secret mariadb-root -o jsonpath='{.data.password}' | base64 -d 取正确口令

验证

python3 - <<'EOF'
import socket
with socket.create_connection(("192.168.31.10", 3306), timeout=5) as s:
    data = s.recv(256)
print("protocol=", data[4], "server=", data[5:data.find(b"\x00", 5)].decode())
EOF
# 预期:protocol= 10 server= 12.3.3-MariaDB-ubu2404

场景 5:run.sh 执行报错

症状:脚本非零退出,日志出现 配置错误、traefik 未声明 entryPoint、nginx -t 校验失败、模块 [...] 执行失败。

诊断与处置

报错关键字 含义 处置
traefik 未声明 entryPoint '<名>' 新增的内网 TCP 端口没在 traefik 侧声明 按提示在 traefik_deploy/values.yaml 的 ports 下加同名端口并 helm upgrade(命令见 SOP.md 5.0)
配置错误: 服务 X: exposure=... 仅支持 backend=k8s 暴露面与后端类型组合非法 改 config/ingress.yaml 的 exposure / backend 组合(约束见 SOP.md 附录 A)
nginx -t 校验失败 生成的 nginx 配置语法错误(通常因站点参数异常) 脚本已自动从备份恢复且未 reload,生产配置未被破坏;检查 config/ingress.yaml 中该站点的字段
证书签发失败: <域名> ACME 校验未通过 见场景 3
隧道端口未监听: <host>:<port> frpc 重启后隧道没起来 见场景 2
获取进程锁失败 有另一个 run.sh 在跑 等它结束;若确属崩溃遗留,日志会提示孤儿锁已自动清理

验证:修复后重跑 ./run.sh,预期三个模块 success 或 skipped,末尾出现「部署完成,所有模块均已收敛到期望状态」。

9. 安全与权限

访问模型

通道 认证方式 说明
执行机 → 香港机 / OpenWrt SSH 密钥(root 免密) 执行机私钥即等同于两台主机的 root 权限,务必保护
执行机 → k8s ~/.kube/config(cluster-admin) 可操作全集群
公网 → 业务服务 各业务自身认证(GitLab 登录、Grafana 登录、phpLDAPadmin 的 LDAP 绑定) 本工程只做转发,不参与认证
公网 → Traefik Dashboard HTTP BasicAuth 凭据见第 2 章
公网 → frps 面板 BasicAuth 凭据见第 2 章;未纳入本工程管理
frpc ↔ frps 共享 token 两端配置文件中的 auth.token 必须一致

证书与密钥位置

对象 位置 轮换方式
业务域名证书(LE) 香港机 /etc/letsencrypt/live/<域名>/ 自动续期(每日 run.sh,剩余 <30 天触发);手工见场景 3
traefik 自签证书(内网用) k8s Secret server/traefik-selfsigned-tls;源文件 traefik_deploy/certs/ 见 traefik_deploy/SOP.md
MariaDB 服务端/客户端证书 k8s Secret server/mariadb-server-cert、mariadb-client-cert、mariadb-ca 由 mariadb-operator 管理
frp token 香港机 frps.toml、OpenWrt frpc.toml 改两端后同时重启 frps 与 frpc

已知风险(需管理者决策)

风险 现状 建议
香港机安全组对公网全放行 实测 5443/6443/8082/8443/9100 等均可从公网直连 收敛为只放行 80/443 与必要的隧道端口
frps 面板暴露公网且口令明文存配置文件 http://fps.rainchen.top 可访问;口令强度一般 限制来源 IP,或从 nginx 侧加访问控制;口令改为强口令并移出明文
frps 5443 公网可达 + token 明文 token 泄漏即可注册隧道占用端口 限制来源 IP(只允许 OpenWrt 出口 IP)
公网暴露面的数据库服务 当前 MariaDB 为 internal,未上公网 ✅ 保持现状;确需公网时用非标端口 + 来源白名单 + 强口令,并评估是否改用 SSH 隧道
回源不校验内网 traefik 证书 nginx proxy_ssl_verify off 内网为受控二层环境;如需加固可导入内部 CA 并开启校验

10. 容量与性能

当前水位基线(2026-09-18)

对象 基线 备注
香港机根分区 25G,已用 83%(剩余约 4G) ⚠️ 偏紧,见下方处置
香港机内存 991M,已用约 258M 宽裕
香港机负载 load average < 0.1 极低
traefik 单副本;requests 100m/128Mi,limits 1C/512Mi 固定在 k8s-master-01
MariaDB 单实例(replicas: 1) mariadb-operator 管理
隧道带宽 无显式限速(bandwidth_limit 未设) 与香港机公网带宽同源

扩容触发与操作

触发条件 操作
香港机根分区 > 90% 清理 /var/log(nginx 日志按需切割)与过期 nginx 备份(对照 backup/README.md);仍不足则扩容云盘
公网访问量增长、traefik CPU 长期接近 limits 评估改多副本 + 反亲和(需放弃 hostPort 方案,见 traefik_deploy/SOP.md 风险章)
隧道吞吐成为瓶颈 在香港机侧对 frps 加 bandwidth_limit,或按业务分拆到多条隧道
MariaDB 负载升高 属数据库侧,调 server/mariadb 的 CR 资源与存储

已知瓶颈

  • 单点:香港机、frps、frpc、traefik 均单实例,无冗余;traefik 与 OpenWrt 节点故障都会让公网入口全断。
  • traefik 升级瞬断:单副本 + hostPort 必须先停旧再起新,helm upgrade 期间公网中断数秒。
  • 香港机磁盘:83% 水位,证书签发与日志都写在同一分区,需重点盯。

11. 附录

术语表

术语 含义
暴露面(exposure) 服务投放范围:internal 仅内网、public 公网、both 两者
隧道(tunnel) 内网后端到香港机落地端口的映射,此处特指 tunnels 中登记的两条(8082/8443)
站点(site) 公网 HTTP(S) 服务,按域名分流,对应 sites
entryPoint traefik 的监听入口;web=80、websecure=443、mariadb=3306
落地端口 frps 在香港机上监听、供 nginx 回源的端口(8082、8443)
收敛 执行 ./run.sh 让实际状态与 config/ingress.yaml 一致

相关文档与交付物

文档 位置 内容
变更档案(SOP) ingress_tunnel_deploy/SOP.md 这次改了什么、怎样手工复现、如何回滚
运行手册(本文) ingress_tunnel_deploy/RUNBOOK.md 日常使用、排障、监控、安全
备份台账 ingress_tunnel_deploy/backup/README.md 每份备份的位置、来历、可删时机
服务清单 ingress_tunnel_deploy/config/ingress.yaml 唯一日常改动点
traefik 主题 traefik_deploy/SOP.md 内网入口代理自身的部署与风险
内网监控 monitoring_upgrade/、prometheus_deploy/ kube-prometheus-stack
GitLab / LDAP gitlab-deploy-v2/SOP.md、ldap-deploy/SOP.md 业务服务自身

修订记录

日期 修改人 内容
2026-09-18 rain 首版:公网 5 站点 + 内网 MariaDB 打通后的运行手册

来源:/home/rain/Documents/k8s_ins/ingress_tunnel_deploy/RUNBOOK.md | 最后更新:2026-09-19 16:25(由 build/sync.py 同步,请勿在站点侧修改)