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。
易错点¶
- 内网 TCP 新增端口必须先改 traefik:traefik 的 entryPoint 是静态配置,本工程只能校验。缺了会在
pre_check直接报错并提示,不会静默失败。 - 暴露面组合约束:
exposure: internal只能配backend: k8s;exposure: public只能配backend: host;违反会被拦下。 - 公网域名必须先做解析,否则证书签发会失败(HTTP-01 校验不过)。
- 不要手工改生成的文件(
conf.d/k8s-ingress.conf、conf.d/k8s-ingress.toml),下次执行会被覆盖;长期改动请改config/ingress.yaml。 frpc.toml可能被外部工程覆盖:重跑frp_openvpn_tunnel会丢掉includes行,隧道随之消失;重跑一次./run.sh即自动补回。- 香港机安全组对公网全放行:清单里写什么端口,什么端口就会对公网开放,改配置前先确认暴露面。
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 |
建议关注(按优先级)¶
- 证书剩余 < 15 天 → 立即手工跑一次
./run.sh并确认续期成功(每日定时任务正常时不应出现)。 8082/8443任一未监听 → 隧道断,公网全断,按场景 2 处置。- 公网域名返回 5xx → 按场景 1 处置。
- 香港机根分区 > 90% → 会影响证书签发(certbot 需要写盘)与日志,按第 10 章处置。
- 香港机重启后 → frps 不会自启,必须手工拉起(场景 2)。
8. 故障处置¶
场景 1:某(些)公网域名打不开,返回 502 / 504 / 卡住¶
症状:浏览器报 502 Bad Gateway 或超时;其它域名可能正常。
诊断
-
确认范围——是所有域名还是单个
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 步)。 -
定位是哪一段断的——在香港机本地绕开公网直连
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/" - 预期 302 → nginx 与隧道都正常,问题在内网后端(第 4 步)
- 502 → 隧道或后端断(第 3 步)
-
连接失败 → nginx 没在监听(
systemctl status nginx) -
看隧道是否活着
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 处置。 -
内网后端与路由
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 无监听。
诊断
-
香港机 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 条。 -
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 步。 -
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 连接。 -
隧道配置是否还在(被外部工程覆盖时会丢)
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]]。
处置
- 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)'" # 确认起来了 - frps 在跑但 frpc 未连上 → 重启隧道客户端:
timeout 20 ssh root@192.168.31.2 "/etc/init.d/frpc-tunnel restart" - 配置丢失(
includes或片段缺失)→ 跑一次收敛自动补回:cd /home/rain/Documents/k8s_ins/ingress_tunnel_deploy && ./run.sh - 香港机连不上(网络/主机故障)→ 属主机故障,按香港机自身处置流程;公网在此期间不可用,需告知使用方。
验证
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 日志出现 证书签发失败。
诊断
- 看各证书剩余天数(速查表「证书还剩几天」)。预期 > 30 天;< 15 天即异常。
- 看每日定时任务是否在跑
bash crontab -l | grep ingress_tunnel tail -n 50 /home/rain/Documents/k8s_ins/ingress_tunnel_deploy/logs/cron.log - 手工跑一次续期预演(不消耗 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 失败或握手超时。
诊断
- 端口是否通(不依赖 mysql 客户端)
bash timeout 4 bash -c 'echo > /dev/tcp/192.168.31.10/3306' && echo 端口可达 || echo 端口不可达 - 路由资源是否还在
bash kubectl -n server get ingressroutetcp mariadb -o yaml # 预期:spec.entryPoints: [mariadb],services: mariadb:3306 - 后端 Pod 与 Service
bash kubectl -n server get pod mariadb-0 -o wide # 预期 1/1 Running kubectl -n server get svc mariadb # 预期 ClusterIP 3306 - 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 - 数据库自身是否在监听
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 步缺
mariadbentryPoint → 说明 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同步,请勿在站点侧修改)