Edunexus 部署排查手册
整理自一次完整的故障排查实战。当部署后服务起来了但外部访问异常时,按本文档顺序排查。
0. 部署完毕后的健康检查清单
bash
# 1) 容器是否都 Up
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# 2) 业务端口是否在宿主机 LISTEN
sudo netstat -tlnp | grep -E ':(80|3306|6379|1883|8808|9000|18083) '
# 3) 容器内服务自检
docker exec platform_edunexus sh -c 'wget -qO- --timeout=3 http://127.0.0.1:8808/api/ 2>&1 | head -3' || true
docker exec platform_nginx nginx -t
任何一条不正常 → 进入下面对应章节。
1. 启动报错:Pool overlaps with other one on this address space
含义 :docker-compose 声明的 172.25.0.0/16 子网与宿主已有网络冲突(旧 compose 残留 / VPN / 公司内网)。
排查
bash
docker network ls
# 找出实际占用 172.25 段的那个网络
docker network inspect $(docker network ls -q) 2>/dev/null | grep -B5 '172.25' | head -30
ip route | grep 172.25
解决
优先方案:清残留
bash
docker-compose -f /edunexus/edunexus_deploy_v1.1/docker-compose.yaml down --remove-orphans
docker network prune -f
然后重跑 bootstrap_edunexus.sh。
真冲突:换子网
编辑 docker-compose.yaml,把 subnet: 172.25.0.0/16 换成 10.88.0.0/16,并把所有 ipv4_address: 172.25.0.x → 10.88.0.x,同时改 nginx.conf / application.yml / DetectSvr/conf.json / StreamSrv/conf.json 里的 172.25.0.*。
2. 启动报错:exec: "/opt/xxx/entrypoint.sh": permission denied
含义 :镜像内的 entrypoint.sh 没有 +x。常见于 EMQX、DetectSvr、StreamSvr。
临时绕过(不重建镜像)
在 docker-compose.yaml 该服务下加一行:
yaml
mqtt:
entrypoint: ["sh", "/opt/emqx/entrypoint.sh"]
sh xxx.sh 不要求脚本本身 +x。然后:
bash
docker-compose down && docker-compose up -d
根本修复(修源码再 build)
-
给宿主源文件加 +x:
bashchmod 755 avtronsys/Emqx/entrypoint.sh -
在
Dockerfile的COPY之后加:dockerfileRUN chmod +x /opt/emqx/entrypoint.sh # 或一次扫一波 RUN find /opt/avtronsys/StreamSrv -maxdepth 2 -name "*.sh" -exec chmod +x {} \; -
docker-compose build mqtt && docker-compose up -d mqtt
3. 端口 LISTEN 但 curl 返回 Connection reset by peer
症状 :netstat 看 docker-proxy 在 LISTEN,但 curl http://127.0.0.1:9000/ 报 Recv failure: 连接被对方重置。
这是 TCP 握手成功后被立刻 RST,不是防火墙(防火墙是 timeout/refuse),原因通常是 nginx 容器侧出问题。
排查 5 步走
bash
# 1) 路由是否冲突(最可疑)
ip route
docker network inspect $(docker network ls -q) 2>/dev/null | grep -E 'Subnet|Gateway' | head
# 2) nginx 配置是否有效
docker exec platform_nginx nginx -t
# 3) nginx 实际加载的运行配置里有没有 listen 9000
docker exec platform_nginx nginx -T 2>/dev/null | grep -E "listen 9000|edunexus_backend"
# 4) 容器内真正监听的端口(无 ss/netstat 时用 /proc/net/tcp)
docker exec platform_nginx sh -c "cat /proc/net/tcp | awk 'NR>1 {print \$2}' | cut -d: -f2 | sort -u | while read p; do printf '%d\n' 0x\$p; done | sort -un"
# 5) nginx 错误日志
docker logs platform_nginx --tail 80
常见根因 A:nginx 配置文件被旧版本"粘"住
deploy 脚本如果用的是"目录已存在则跳过"逻辑,换 tar 重部署后老 conf 一直没被覆盖。
判定 :第 3 步 nginx -T 输出里没有 listen 9000 或 edunexus_backend,但宿主机源文件里有。
修复:
bash
sudo cp -f /edunexus/edunexus_deploy_v1.1/avtronsys/Nginx/conf/nginx.conf /opt/avtronsys/Nginx/conf/nginx.conf
docker exec platform_nginx nginx -s reload
常见根因 B:nginx 版本不支持配置里的某些指令
判定:nginx -s reload 报 [emerg] "xxx" directive is not allowed here。
实例:
[emerg] "keepalive_requests" directive is not allowed here in nginx.conf:4
nginx 1.13.3 不支持 upstream 块的 keepalive_requests / keepalive_timeout(需 1.15.3+)。
修复:要么把 nginx 镜像升到 1.27,要么删掉这些不支持的指令。
bash
# 方案 1:临时删
sudo sed -i '/keepalive_requests/d; /keepalive_timeout 75s/d' /opt/avtronsys/Nginx/conf/nginx.conf
docker exec platform_nginx nginx -s reload
# 方案 2:长期升级镜像(修 Dockerfile)
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27-alpine
常见根因 C:前端 dist 目录没复制进容器
判定:
bash
docker exec platform_nginx ls /opt/avtronsys/Nginx/frontend/edunexus/dist/ 2>&1
# → No such file or directory
原因同 A,部署脚本的"目录非空就跳过"判断把整个 frontend/ 拷贝直接跳了,新加的 edunexus/dist 一直没补。
修复:
bash
sudo mkdir -p /opt/avtronsys/Nginx/frontend/edunexus
sudo cp -r /edunexus/edunexus_deploy_v1.1/avtronsys/Nginx/frontend/edunexus/dist \
/opt/avtronsys/Nginx/frontend/edunexus/
sudo chmod -R 755 /opt/avtronsys/Nginx/frontend/
# nginx 不需要 reload,静态文件即时生效
curl -I http://127.0.0.1:9000/
4. 容器间网络连通性测试(nginx 容器没 ping/wget/curl)
nginx-slim / nginx:alpine 镜像精简,没 ping/wget/curl。借用别的容器测:
bash
# mqtt 容器装了 netcat
docker exec platform_mqtt sh -c "nc -zv 172.25.0.7 8808 && echo OK"
docker exec platform_mqtt sh -c "nc -zv 172.25.0.2 9000"
# 从宿主机直打容器 IP(绕过 docker-proxy + nginx)
curl -sv http://172.25.0.7:8808/api/ 2>&1 | head -10
预期结果:
nc返回succeeded→ 容器间网络通curl 172.25.0.7:8808/api/返回HTTP/1.1 401(无 token 时正常)
5. 防火墙 / 外部访问问题
如果本机 curl 127.0.0.1:9000 通了,但同网段别的机器 curl 192.168.10.x:9000 不通:
bash
sudo ufw status
sudo iptables -L INPUT -n | head -20
如果 ufw active,放行:
bash
sudo ufw allow 9000/tcp
sudo ufw allow 80/tcp
sudo ufw reload
VMware NAT 场景:如果 VM 用 NAT 模式,要在 VMware 配置里把 host 的对应端口转发到 VM。Bridged 模式则不需要。
6. nginx 日志中频繁 502
典型日志:
connect() failed (113: No route to host) while connecting to upstream "http://172.25.0.6:8089/..."
connect() failed (111: Connection refused) while connecting to upstream "http://172.25.0.7:8013/..."
含义 :nginx.conf 里有大量 server 块(8070/8090/8091/...)指向未部署的旧服务(EDU V1 在 172.25.0.6:8089、EDU V2 在 :8013、iclass 在 172.25.0.8/0.11)。
Edunexus 单服务部署只用 :9000,其他端口的 502 可以忽略 或直接从 nginx.conf 删掉那些 server 块减噪。
7. SQL 数据库相关
重新导入 SQL(清空 data 目录)
bash
# 完全清空 mysql 数据卷以重新触发 /docker-entrypoint-initdb.d/*.sql
docker-compose down -v # -v 删命名卷
sudo rm -rf /opt/avtronsys/Mysql/data/*
docker-compose up -d mysql
docker logs platform_mysql -f # 看到 "ready for connections" 即完成首次初始化
验证 edunexus 库已建
bash
docker exec platform_mysql mysql -uroot -p'Avt@2024!' -e "SHOW DATABASES; USE edunexus; SHOW TABLES;" 2>&1 | tail -30
8. 一键全清重来(核选项)
部署彻底搞乱,想推倒重来:
bash
cd /edunexus/edunexus_deploy_v1.1
# 1) 停掉容器并删掉命名卷
docker-compose down -v
docker network prune -f
# 2) 清掉宿主机映射目录(注意:这会丢 mysql/redis/emqx 数据)
sudo rm -rf /opt/avtronsys/{Nginx,Mysql,Emqx,Redis,Edunexus,DetectSvr,StreamSrv}
# 3) 解压最新 tar 包覆盖项目目录(如果换了新 tar)
cd /edunexus
rm -rf edunexus_deploy_v1.1
tar -xf edunexus_deploy_v1.1.tar
cd edunexus_deploy_v1.1
# 4) 一键重装
sudo bash bootstrap_edunexus.sh
9. 排查常用命令速查
bash
# 容器
docker ps -a
docker logs <name> --tail 80 -f
docker exec -it <name> sh
docker inspect <name> | grep -E 'IPAddress|Mounts|Ports' -A2
# 网络
docker network ls
docker network inspect <network>
ip route
sudo netstat -tlnp | grep <port>
ss -lntp | grep <port>
# nginx 专用
docker exec platform_nginx nginx -t # 校验配置
docker exec platform_nginx nginx -T # 打印生效配置
docker exec platform_nginx nginx -s reload # 热加载
# 容器内端口(nginx-alpine 没 ss/netstat 时)
docker exec platform_nginx sh -c "cat /proc/net/tcp | awk 'NR>1 {print \$2}' | cut -d: -f2 | sort -u | while read p; do printf '%d\n' 0x\$p; done | sort -un"
# 跨容器探测(mqtt 容器有 netcat)
docker exec platform_mqtt nc -zv <container_ip> <port>
10. 已知配置不一致(仅参考,不影响 Edunexus 自身)
如果业务确实需要 DetectSvr / StreamSvr 把数据回写到 Edunexus,需要改这些业务配置:
| 文件 | 当前值(指向旧 EDU/IClass) | 应改为(指向 Edunexus) |
|---|---|---|
avtronsys/DetectSvr/conf.json platformIp/Port |
172.25.0.6:8089 |
172.25.0.7:8808 |
avtronsys/DetectSvr/conf.json sql.database |
zypt、zhjs |
edunexus |
avtronsys/StreamSrv/conf.json EDUplatformIp/Port |
172.25.0.6:8089 |
172.25.0.7:8808 |
avtronsys/StreamSrv/conf.json IClassplatformIp/Port |
172.25.0.8:8088 |
视业务需求决定 |
avtronsys/StreamSrv/conf.json sql.database |
zypt |
edunexus |
改完重启对应容器:
bash
docker-compose restart detectserver streamserver
附:本次实战的"路径依赖"陷阱
部署脚本最坑的不是语法错误,而是 "幂等"判断写错位置:
bash# 这个判断会让"换了新版本配置但旧目录还存在"的情况下,新配置永远不生效 if [ ! -d /opt/avtronsys/Nginx/conf ] || [ ! -f /opt/avtronsys/Nginx/conf/nginx.conf ]; then sudo cp -f new.conf /opt/avtronsys/Nginx/conf/nginx.conf else echo "已存在,跳过" # ← 灾难的源头 fi
最佳实践 :配置类文件(nginx.conf / application.yml)每次部署强制覆盖 ;只有用户数据(mysql data、redis dump、emqx mnesia)才需要"已存在则保留"。当前 deploy_edunexus.sh 已按此原则修正。