Swoole 和 mDNS 的兼容性问题

简介⌗
自从用上 OrbStack 以后,就回不去了,OrbStack 会为容器注册域名到本机的 mDNS 中,这为新手解决了几个难以理解的问题:
- 同一个项目在宿主机和容器中访问数据库容器的 HOST 不同
- 数据库容器的端口需要映射到宿主机端口
例如我问本地开发环境启动了 mysql 和 redis 容器,并为它们分配了如下域名:
- mysql.database.local
- redis.database.local
当 OrbStack 中对应的容器启动后,OrbStack 会自动向 macOS 的 mDNS 注册,从而实现可以通过域名访问容器。
OrbStack 网络架构⌗
OrbStack 使用自定义的网络栈来管理容器和主机之间的通信,默认情况下:
容器内部 IP(如
10.0.8.33
):这是容器在 OrbStack 的虚拟网络(通常是一个桥接网络,例如bridge101
)中分配的私有 IP 地址,属于类似 10.0.0.0/8 的子网。这种 IP 通常只在 OrbStack 的内部网络中可见,用于容器间的通信或与虚拟机的交互。外部访问 IP(如
198.19.248.8
):OrbStack 会为容器分配一个对外暴露的 IP 地址,通常在198.19.248.0/23
范围内。这是 OrbStack 的网络代理层(运行在 macOS 主机上)提供的地址,用于将外部流量(例如通过container-name.orb.local
的域名访问)路由到容器。
换句话说,10.0.8.33
是容器在内部网络中的实际地址,而 198.19.248.8
是 OrbStack 的网络层为该容器提供的外部代理地址。
容器启动后,可以通过如下命令来查看 mDNS 中的记录:
dns-sd -Q mysql.database.local
DATE: ---Tue 11 Mar 2025---
13:51:43.488 ...STARTING...
Timestamp A/R Flags IF Name Type Class Rdata
13:51:43.623 Add 2 26 mysql.database.local. Addr IN 198.19.248.8
起因⌗
一切都看似美好,直到我们的项目中使用了 Swoole 这个 PHP 扩展,我在 Swoole 项目中无法使用前面提到的 mysql.database.local
来连接数据库容器。
会得到如下错误:
php bin/hyperf.php migrate --path migrations/tenant
In Connection.php line 1169:
SQLSTATE[HY000] [2002] DNS Lookup resolve failed (SQL: select `enterprise_id` from `enterprise`)
In Connector.php line 107:
SQLSTATE[HY000] [2002] DNS Lookup resolve failed
最初也没在意这个问题,还以为是 OrbStack 的网络兼容性问题,直到后来另一位同事的 macOS 上更我我同样的配置它却可以在 Swoole 项目中访问 OrbStack 中定义的域名。
排查⌗
于是我用排除法,对比了我和同事电脑的环境配置差异,对比下来发现就比他多启用了个 c-ares
库,从命名上完去看不出它跟 DNS 有啥关系,后来一查才知道,c-ares
是一个异步 DNS 解析库,它适用于需要在不阻塞的情况下执行 DNS 查询或需要并行执行多个 DNS 查询的应用程序。
Swoole 默认不开启,需要在编译 Swoole 时增加 –enable-cares 参数才能开启。
而这个库是不支持 mDNS 记录的查询的。
解决方案⌗
- 重新编译 Swoole 扩展,编译时不开启 cares
- 为容器设置固定 IP,然后在 /etc/hosts 中手动添加解析记录
I hope this is helpful, Happy hacking…