AI 日记
今晚又是深夜折腾。起因是我想给家里的 NAS 再加一个新服务——Byparr,一个 FlareSolverr 的替代品,专门用来绕过 Cloudflare 的人机验证,好让 Prowlarr 能正常抓取 52BT 这类套了 CDN 防护的索引站。
服务倒是跑起来了,8191 端口也通了,但 Prowlarr 死活连不上。排查了半小时,最后发现是 Docker 网络的老问题:两个容器不在同一个 bridge 网络里,互相看不见。
这已经不是我第一次被 Docker 网络坑了。每次新建容器,默认丢进 bridge 网络,端口映射到宿主机没问题,但容器之间想通信?要么加 --link(已废弃),要么手动建自定义 bridge,要么用 host 网络模式直接共享宿主机网络栈。
AI 给我出了个主意:把 Byparr 和 Prowlarr 都加进同一个自定义网络,让它们直接用容器名互访,不走宿主机端口转发。操作了一遍,确实干净多了。
技术笔记:Docker 网络那些绕不过去的坑
用 Docker 跑家庭媒体栈时间久了,网络问题是绕不过去的一道坎。整理了几个最常见的场景:
1. 默认 bridge 网络的坑
Docker 默认给每个容器分配 172.17.x.x 地址,加进 docker0 这个默认桥接网络。问题在于,默认 bridge 网络里的容器不能用容器名互相解析,只能靠 IP,而容器 IP 每次重启都可能变。
正确做法是建自定义 bridge:
docker network create media-net
docker run --network media-net --name byparr ...
docker run --network media-net --name prowlarr ...
这样 Prowlarr 直接填 http://byparr:8191 就能通,不需要知道 IP,也不依赖端口映射。
2. 反向代理的网络隔离问题
我用 Nginx Proxy Manager(NPM)做反代,但 NPM 本身也是跑在 Docker 里的。如果后端服务不在同一个 Docker 网络,NPM 是访问不到 容器名:端口 的。
解决方法:把 NPM 容器也加进 media-net,或者让后端服务 expose 端口到宿主机,NPM 填 宿主机IP:端口。两种方案各有取舍——前者更安全(不暴露端口到宿主机),后者更方便(不需要手动管理网络)。
3. host 网络模式的权衡
有些服务(比如 qBittorrent)直接跑在 --network host 模式下,共享宿主机网络,性能最好,配置最简单。但代价是:无法和其他自定义 bridge 网络的容器互通,而且容器内开的端口直接暴露在宿主机上,安全性差一些。
家庭内网环境下,host 模式图省事无可厚非;但如果服务要对外开放,建议还是老老实实用 bridge + 端口映射 + 反代的三层结构。
4. docker-compose 的网络自动化
用 docker-compose 管理多个容器时,同一个 compose.yml 里的服务默认自动加入同名的自定义 bridge,容器名即 DNS 名,这是最省心的方案。问题在于:如果你的服务分散在不同的 compose.yml 里(比如媒体栈一个、监控栈一个),它们之间就是隔离的。
跨 compose 互通的办法:在各自的 compose.yml 里声明同一个外部网络:
networks:
media-net:
external: true
提前用 docker network create media-net 建好,各 compose 共用,问题就解决了。
随想
折腾 Docker 网络这件事,让我想到一个更大的问题:复杂度是会累积的。
一开始图省事,每个服务随手 docker run -p 端口:端口,能跑就行。等到服务多了,互相依赖,端口冲突,网络不通,才开始手忙脚乱地补救。这和技术债一个道理——当时省的力气,后来都要加倍还回去。
最近在整理 NAS 上的容器,想把乱糟糟的启动命令都迁移到 compose 管理。这活不急,但越早做越省心。就像备份这件事,出事之前你永远觉得没必要,出事之后才后悔当初为什么没做。
另一个感悟是:看文档真的很重要。Docker 网络这块官方文档写得很清楚,我踩的坑基本上都是没认真看文档、凭直觉乱搞的结果。AI 能帮你快速定位问题,但理解底层逻辑还是得靠自己读文档、动手试。
今晚 Byparr + Prowlarr 终于跑通了,52BT 索引正常抓取,Jellyfin 队列里又多了几部新片。收工,睡觉。