在 Docker 容器中发现 Apple TV:mDNS、多播与 Avahi
Home Assistant(HA)在物理机上可以自动发现 Apple TV(ATV),
但当 HA 跑在 Docker 容器里、使用 bridge 网络时,经常会出现下面这些现象:
-
HA 发现不了 ATV
-
容器里
atvremote scan看不到 ATV,宿主机可以 -
容器里和宿主机里
avahi-browse都能看到 ATV
下面是我排查这个问题的过程。
Avahi 能看到,但 HA 看不到
按照 HA 的推荐配置,把宿主机的 Avahi socket 挂进容器:
在容器里跑:
能看到 Apple TV,但 HA 依然发现不了。
查了一下才意识到一点:
HA 并不通过 Avahi 发现 Apple TV。
HA 用的是 pyatv,pyatv 用的是 zeroconf,完全不走 Avahi。
avahi-browse 能看到,是因为它通过 socket 连的是宿主机上的 Avahi。
这意味着:
HA 是在容器里自己直接发 mDNS 包。
mDNS 在跑,但容器里收不到
mDNS 用的是 UDP 5353,多播地址 224.0.0.251。
在局域网里随便抓:
能看到 Apple TV 的广播。
但在容器里:
-
抓不到任何 5353 流量
-
在容器里跑
atvremote scan,查询包看起来“发了”,但宿主机物理网卡上完全看不到
基本可以确认两件事:
-
Docker bridge 网络 收不到 外部 mDNS 广播
-
Docker bridge 网络 发不出 mDNS 多播查询
主动扫描 vs 被动发现
atvremote scan 是主动扫描:
发 mDNS 查询,等设备回应 —— 在 bridge 网络里直接死掉。
但 mDNS 还有一条路:
设备会周期性广播 announce 包,只要你在监听,就能“被动发现”。
这也解释了一个现象:
即使容器里发不出查询,只要能收到广播,理论上还是能发现 ATV。
Avahi reflector
Avahi 有个选项叫 reflector,可以把一个接口上的 mDNS 包转发到另一个接口。
宿主机开启:
开启之后再抓包,可以看到:
-
Apple TV 的 mDNS 广播被转进了 Docker bridge
-
容器里终于能收到 5353 流量了
atvremote 还是不行,但 HA 行了
此时再跑:
还是啥也没有。
抓包确认后发现原因没变:
容器里的主动 mDNS 查询还是发不出去。
但这时 HA 却已经能发现 Apple TV 了。
推测原因很简单:
-
HA 持续监听 mDNS
-
Apple TV 定期发广播
-
广播被 Avahi reflector 转进容器
-
HA 通过被动发现拿到了设备信息
至于 atvremote scan,它依赖主动扫描,所以依然失败。
总结
-
Docker bridge 网络不支持 multicast 发送
-
挂 Avahi socket 只能救 Avahi 客户端,救不了 HA
-
开启宿主机 Avahi reflector,可以把 mDNS 广播转进容器
-
主动扫描仍然不工作,但被动发现足够 HA 使用
评论
发表评论