Mac 上的容器网络如何工作
macOS 无法直接运行 Linux 容器,因此 Mac 上的每款容器应用都会在 Linux 环境中运行它们,并在 Linux 和 Mac 之间转发流量。需要关注三条路径:
- 入站:Mac 上的已发布端口将连接转发到容器。
- 出站:容器连接互联网、公司网络或 Mac 上的服务。
- 名称:容器查询主机名。
这些路径一旦绕过 Mac 自身的网络,VPN 路由就不会生效,内部主机名无法解析,防火墙也看不到哪个应用正在通信。Oxcart 的设计避免了这些问题。
出站:VPN、DNS 和防火墙依然生效
Oxcart 将容器和构建步骤发出的 IPv4、IPv6 出站 TCP 流量重定向到 Mac,由 Mac 使用自身的套接字建立连接。Mac 的路由表决定连接的路径,包括 VPN 客户端安装的路由。Oxcart 不修改 Mac 路由、VPN 设置或防火墙偏好设置。
地址查询(A 和 AAAA)使用 macOS 系统解析器,包括 /etc/hosts 和 VPN 配置的解析器选择,因此容器中的公司主机名解析方式与浏览器相同。容器名称仍限定在各自的 Docker 网络内,DNS 同时支持 UDP 和 TCP。
Little Snitch、LuLu 与终端安全代理
网络过滤器通常会在询问用户时,将新程序的首次连接暂缓约两秒。Oxcart 不会等待:在主链路验证通过前,连接走备用路径;连接缓慢或失败时会自动切换到备用路径;连续三次失败则暂停主链路 30 秒,再次探测。只需在过滤器中批准 Oxcart 一次,之后就会按规则处理。
入站:发布端口
使用标准 Docker 语法发布端口:
# Mac loopback only (recommended for development)
docker run -d -p 127.0.0.1:8080:80 nginx
# Ephemeral host port, UDP
docker run -d -p 127.0.0.1::9000/udp my-udp-service
# IPv4 and IPv6 listeners on the Mac
docker run -d -p "[::]:8080:80" nginx 未指定地址的绑定会监听 Mac 的所有 IPv4 地址,因此同一网络上的其他机器可以访问,除非被 macOS 防火墙阻止。TCP 和 UDP 可以使用相同的主机端口号。容器停止时,会释放已发布的监听端口。
已发布的端口也会在引擎自身的 localhost 上响应,因此容器中运行的镜像仓库可以作为推送目标:
docker run -d -p 127.0.0.1:5000:5000 --name registry registry:2
docker tag my-app localhost:5000/my-app
docker push localhost:5000/my-app Ports 视图:端口为什么没有响应
Oxcart 的 Ports 视图列出 Mac 上的所有监听端口和每个容器端口,按仓库、工作树和分支分组,让同一项目的两份检出副本不再混淆。每个绑定都会显示为就绪、等待中或错误,并注明原因:
- 该地址已被 Mac 上的其他进程占用;
- 容器内的服务器只监听
127.0.0.1; - 该端口尚无服务监听。
其他机器可以访问的端口会有标记。编码代理可以通过 Oxcart 的 MCP ports 工具看到相同信息;请参阅面向 AI 编码代理的 Docker。
从容器访问 Mac
host.docker.internal 可在容器和构建步骤中解析,并通过 TCP 访问绑定在 Mac 的 127.0.0.1 上的服务。让容器连接到 Mac 上原生运行的数据库或开发服务器:
docker run --rm curlimages/curl http://host.docker.internal:3000/health 请把这视为一条有意开放的访问通道:运行的任何容器都能通过它访问 Mac 回环地址上的服务。因此,运行不可信容器时,不要在 127.0.0.1 上留下无需身份验证的管理服务。
Mac 与引擎之间的加密链路
Mac 与 Linux 之间的流量经过一个虚拟网络,macOS 会将它与同一 Mac 上的其他虚拟化软件共享。Oxcart 在这条链路上用 TLS 1.3(TLS_AES_128_GCM_SHA256)传输已发布端口和出站连接的 TCP 流量,并固定使用每次引擎启动时新生成的证书,每次启动还会生成一个 256 位 bearer 令牌。令牌无效会关闭连接;来自非 Mac 地址的连接,Linux 端会在 TLS 开始前关闭。
这解决的威胁是:共享网络上的其他软件伪造地址,以读取或注入流量,或向容器建立新连接。客户机防火墙还会阻止这些软件访问未发布的容器端口和内部解析器。链路加密有开销,这是我们主动选择承担的成本。Docker API 本身从不经过网络:它使用私有 Unix 套接字;没有发布端口时,Oxcart 在 Mac 上不持有任何 TCP 或 UDP 套接字。
当前限制
- 尚未实现主机网络模式(
--network host)和 IPv6 容器网络;容器使用 IPv4 地址。 host.docker.internal支持 TCP;尚未实现到主机网关的 UDP。- 发布的 TCP 和 UDP 端口不会保留客户端地址:容器看到的对端是 Linux 一侧。
- 非地址类 DNS 记录(如 SRV 和 TXT)使用网络的 DHCP 解析器,而非 macOS 分流 DNS。
故障排查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
连接 localhost:PORT 被拒绝 | 服务器在容器内监听 127.0.0.1 | 改为监听 0.0.0.0;Ports 视图会指出此问题 |
| "port is already allocated" | 另一个进程或容器占用了主机端口 | 换一个主机端口;Ports 视图会显示占用者 |
| 容器内无法解析内部主机名 | 名称仅存在于 VPN 的 DNS 中 | 在 Mac 上连接 VPN;地址查询会使用 Mac 的解析器 |
| 容器无法访问 Mac 上的开发服务器 | 在容器内使用了 localhost | 使用 host.docker.internal |
| 首次拉取停顿几秒 | 网络过滤器正在询问是否允许新连接 | 批准 Oxcart 一次即可;在此期间连接使用备用路径 |
| 同事可以访问你的开发端口 | 发布时未指定地址 | 发布到 127.0.0.1 |
常见问题
Mac 上的 Docker 容器会使用我的 VPN 吗?
在 Oxcart 中会。容器的出站连接由 Mac 自身建立,因此 Mac 的路由、VPN、用于地址查询的分流 DNS 和按应用设置的防火墙都会生效。Oxcart 不修改 Mac 路由、VPN 设置或防火墙偏好设置。
如何从容器访问 Mac 上的服务?
使用 host.docker.internal。在 Oxcart 中,容器和构建步骤都能通过它以 TCP 访问绑定在 Mac 的 127.0.0.1 上的服务。--add-host mac:host-gateway 可为同一地址添加另一个名称。
为什么容器明明在运行,却无法访问它的端口?
通常是容器内的服务器监听了 127.0.0.1,发布端口无法访问该地址;请改为监听 0.0.0.0。其他原因包括主机端口已被占用,或尚无服务监听。Oxcart 的 Ports 视图会指出具体原因。
Oxcart 能与 Little Snitch 和 LuLu 配合使用吗?
可以。网络过滤器在询问用户时暂缓 Oxcart 的首次连接,Oxcart 会在链路验证通过前使用备用路径,因此不会中断工作,也不会等待你的回答。缓慢或失败的连接会自动切换到备用路径。
Mac 上的容器流量会加密吗?
Mac 与 Oxcart 引擎之间,已发布端口和出站连接的 TCP 流量都通过 TLS 1.3 传输,并固定使用每次引擎启动时生成的证书和该次启动的 256 位令牌。这可保护该链路免受 Mac 共享网络中其他虚拟化软件的干扰。通往互联网的流量则由应用自身使用的方式保护,例如 HTTPS。
同一网络中的其他机器能看到我发布的端口吗?
未指定地址的发布端口会监听 Mac 的所有 IPv4 地址,因此除非 macOS 防火墙阻止,否则其他机器可以访问。发布到 127.0.0.1 可将访问限制在本机。Oxcart 会标记其他机器可以访问的端口。
Oxcart 支持容器的主机网络或 IPv6 吗?
不支持。尚未实现主机网络模式和 IPv6 容器网络。容器使用 IPv4 地址;仍可通过 "[::]:8080:80" 在 IPv6 上发布端口。
来源与方法
本文描述的网络行为于 2026 年 10 月 10 日在 Oxcart 上进行了测试,包括出站 TCP、DNS、发布端口、主机访问,以及 Mac 到容器链路上的 TLS。