INCIDENT-20260920:phpLDAPadmin 管理界面点击目录树后一直加载¶
1. 概要¶
| 项目 | 内容 |
|---|---|
| 发生时间 | 2026-09-20 21:19(CST) |
| 发现时间 | 2026-09-20 21:20(用户截图反馈) |
| 等级 | 一般(P3):单一管理界面不可用,不影响 LDAP 目录服务与业务系统 |
| 影响面 | 仅 server/phpldapadmin 管理界面;用户无法浏览、编辑目录条目 |
| 当前状态 | 已恢复(2026-09-20 21:42,helm revision 8) |
2. 影响范围¶
- 受影响:所有通过
https://ldapadmin.rainchen.top使用 phpLDAPadmin 的用户;登录可成功,但点击目录树后右侧内容区一直转圈。 - 不受影响:OpenLDAP 目录服务(389/636 正常)、gitlab / minio / mariadb 等业务系统、LDAP 数据。
- 数据:无损坏、无丢失(本次故障未写入任何目录数据)。
3. 时间线(CST)¶
| 时间 | 事件 |
|---|---|
| 21:16 | 用户登录成功(应用日志 ALG:Attempting login for [uid=ldapadmin,...]) |
| 21:19:46–21:19:56 | 用户点击目录树,浏览器发出 POST /frame,服务端返回 409(traefik 访问日志) |
| 21:20 | 用户反馈"点了两下就一直这样转圈",附界面截图 |
| 21:21–21:36 | 只读取证:确认 LDAP 服务、目录数据、应用配置、各 AJAX 接口均正常;/ajax/bases、/ajax/children 均为 200,唯独 POST /frame 为 409 |
| 21:38 | 用户提供 F12 证据:Request URL: https://ldapadmin.rainchen.top/frame、Referer: https://ldapadmin.rainchen.top/、Remote Address: 129.226.138.204:443 |
| 21:32 | 留档容器内原始 HomeController.php(sha256 0a87cc51…) |
| 21:37 | 预演(dry-run)基线:内网 http POST /frame=200,公网 https=409 |
| 21:39:44 | helm revision 6:部署 ConfigMap 覆盖 + 挂载 |
| 21:40:44 | helm revision 7:修正覆盖文件字节(ConfigMap 块标量由 \| 改为 \|-,消除尾随换行差异) |
| 21:42:56 | helm revision 8:收敛 Deployment 注解,使渲染结果与线上完全一致 |
| 21:43 | 恢复验证通过:两条链路 POST /frame 均 200;幂等复核 SKIPPED |
4. 根因¶
镜像内 app/Http/Controllers/HomeController.php 的 frame() 判据过严,叠加公网 https 反代链路,导致合法的点击恒被 409 拒绝。
// If our index was not render from a root url, then redirect to it
if (($request->root().($request->getBasePath() ? '' : '/') !== url()->previous()) && ($request->method() === 'POST'))
abort(409);
证据链:
- 只有 /frame 失败:traefik 访问日志(用户 IP)显示
POST /ajax/bases 200→POST /frame 409→GET /login 200。 - 服务端一切正常:容器内用服务账号、目录条目 DN + 同一口令做
ldap_bind均返回result: 0 Success;GET /、POST /ajax/bases、POST /ajax/children均 200 且耗时 < 0.3s。 - 判据行为实测(同一会话,仅改 Referer):
| Referer | 内网 http | 公网 https |
|---|---|---|
| 不带 | 409 | 409 |
http://ldapadmin.rainchen.top/ |
200 | — |
https://ldapadmin.rainchen.top/ |
— | 409 |
http://192.168.31.10/ |
409 | — |
- 链路特征:
ldapadmin.rainchen.top解析到公网129.226.138.204,由其 443 端口的 nginx 反代到集群 traefik(80), 故页面为 https(服务器端生成的所有 URL 亦为 https),而 Laravel 记录的「上一页 URL」不带尾斜杠, 与判据右侧的「根地址 +/」不相等 →abort(409)。
补充说明:http 访问会被该 nginx 301 强制跳转到 https,因此用户"输入时没加 s"也会自动进入 https 链路。
5. 处置过程¶
- 只读取证阶段未改动任何系统状态(应用日志、slapd 日志、traefik 访问日志、session、配置逐项核对)。
- 采用「ConfigMap 覆盖镜像内单文件」方式修复(沿用本环境既有做法),把判据改为按主机名归一化比较: 仅在能确定上一页、且其主机与本站不一致时才拒绝,跨站 POST 仍被拦截。
- 变更落本地定制 chart(
homeControllerFix开关),保证后续helm upgrade不回退;实现体为ldap-deploy/pla-frame409-fix/Python 工程(幂等、备份、回滚、验证齐备)。 - 期间修正两处实现问题(均发生在变更落地前/后,未造成数据影响):
- 容器内
mktemp参数不兼容 → 语法校验脚本改用固定命名; - ConfigMap 块标量
|会补尾随换行,与目标文件不等 → 改为|-(revision 7 修正)。 - 无回滚动作(变更一次成功)。
6. 恢复验证¶
| 验证项 | 命令/方法 | 结果 |
|---|---|---|
| 容器内文件为目标版本 | kubectl -n server exec … sha256sum /app/app/Http/Controllers/HomeController.php |
61413d08…,与 assets/HomeController.php、chart 内文件三方一致 |
| APP_KEY 未变 | 比对 Secret phpldapadmin 中 APP_KEY 的 sha256 |
变更前后一致(未导致会话失效) |
| 内网链路 | http://192.168.31.10(Host 头 ldapadmin.rainchen.top)登录 → /ajax/bases → POST /frame |
200 / 200 / 200(47860 字节) |
| 公网链路(用户实际路径) | https://ldapadmin.rainchen.top 同上 |
200 / 200 / 200(47874 字节) |
| 幂等 | 重复执行部署脚本两次 | 两次均 skipped(零变更、无报错) |
| 集群状态 | kubectl -n server get pod -l app.kubernetes.io/name=phpldapadmin |
1/1 Running,RESTARTS 0 |
7. 复盘¶
有效做法:
- 先只读取证、用 traefik 访问日志把故障窄化到单个端点(
/frame409),避免了在 LDAP 服务上做无谓改动; - 用「同一会话、只改一个变量」的对照实验确定判据边界,根因有可复现证据;
- 修复顺带落了 chart 层开关,避免下次
helm upgrade静默回退。
拖慢恢复的因素:
- 起初按「内网 http 直连」验证,
POST /frame为 200,一度误判服务端正常;直到拿到用户 F12 的scheme=https与公网 IP 才定位到反代链路——验证必须覆盖用户实际访问路径; - 覆盖文件时未预先考虑 ConfigMap 块标量对尾随换行的处理,多花了一次 helm revision。
8. 行动项¶
| 事项 | 责任人 | 期限 | 状态 |
|---|---|---|---|
升级 phpLDAPadmin 镜像前,比对上游 HomeController.php 与该覆盖文件是否冲突 |
运维(待指派) | 下次镜像升级前 | 待处理 |
清理 pla-frame409-fix/backup/ 中的中间版本备份(见该目录 README 台账) |
用户 | 观察稳定后 | 待处理 |
决策是否在集群内为 ldapadmin.rainchen.top 发布 443 路由(当前集群侧仅 80,https 由公网 nginx 提供) |
用户 | 待定 | 待决策 |
将本次故障场景补充进 ldap-deploy/RUNBOOK.md 的「故障处置」章节 |
运维(待指派) | 待定 | 待处理 |
来源:
/home/rain/Documents/k8s_ins/ldap-deploy/pla-frame409-fix/INCIDENT-20260920-pla-frame-409.md| 最后更新:2026-09-20 21:43(由build/sync.py同步,请勿在站点侧修改)