自定义网络是用户定义的容器网络,让你可以控制哪些服务能够互相访问、名称如何解析,以及流量能否离开主机。对于区块链基础设施而言,这一点很重要,因为节点、RPC 客户端、索引器和监控代理的暴露需求各不相同。本文解释自定义网络背后的心智模型,展示可运行的 Docker 和 Podman 操作流程,并说明如何在不猜测结果的情况下验证隔离性和 DNS 行为。文章还涵盖常见故障模式,以及桥接、内部、覆盖和主机相邻设计之间的权衡。
范围与直接答案
自定义网络是你自己定义的网络,而不是依赖运行时默认网络。在 Docker 和 Podman 中,最常见的形式是用户定义的桥接网络:接入该网络的容器会自动获得基于名称的 DNS 解析、专用子网,并与未接入的容器隔离。你可以使用 docker network create 或 podman network create 等命令创建它,然后通过 --network 将工作负载接入。
对于区块链工作负载,有用的模式是分离通信平面。节点的点对点流量、RPC 客户端对该节点的访问,以及运维人员的 SSH 或指标访问,不应全部共享一个扁平网络。自定义网络让你可以把节点及其可信客户端放在一起,同时将无关容器排除在外。
本指南假设你已经安装了容器运行时,并且熟悉基本的 docker run 或 podman run 命令。它不假设任何特定的链、提供商或主机操作系统。
- 自定义桥接网络通过容器名称提供基于 DNS 的服务发现。
- 内部网络阻止对主机局域网和互联网的出站访问。
- 覆盖网络将自定义网络扩展到多台主机。
- 主机网络绕过隔离,应作为有意的例外。
先决条件与假设
你需要一台 Linux 主机或 Docker Desktop 环境,并具有创建网络的权限。无根 Podman 适用于大多数示例,但子网和端口绑定行为可能与有根模式不同。在依赖驱动程序特定标志之前,请确认你的运行时版本。
你还需要规划每个容器应能访问什么。在创建任何东西之前先写下来:哪些服务互相通信、哪些需要出站互联网访问,以及哪些端口必须发布到主机。该计划将成为你后续的验证清单。
docker version
docker network ls
podman version
podman network ls心智模型:名称、子网与隔离边界
自定义桥接网络是一个带有自己子网的虚拟交换机。每个接入的容器在该交换机上获得一个接口。运行时运行一个嵌入式 DNS 解析器,使得名为 node-a 的容器可以被同一网络上的其他容器使用该名称访问。这是与默认桥接网络的主要实际区别,后者的名称解析能力有限。
隔离是接入的属性,而不是容器本身的属性。一个容器只有在与另一个容器不共享任何网络时才与之隔离。如果你将一个容器接入两个自定义网络,它就成为它们之间的路由器,这可能正是你希望代理或网关做的,也恰恰是你希望数据库不要做的。
内部网络增加了第二道边界:其上的容器可以互相通信,但无法到达主机外部。这对于只应通过另一网络上的反向代理访问的后端服务很有用。
- 每个信任边界一个网络通常比一个大共享网络更清晰。
- 名称解析的作用域限于网络,因此不同网络上的重复名称不会冲突。
- 使用
-p发布端口会创建一条面向主机的路径,该端口会绕过网络隔离。
使用 Docker 创建自定义桥接网络
以下过程创建一个具有显式子网的自定义桥接网络,然后在其上运行两个容器。将镜像名称替换为你自己的节点和客户端镜像。这些命令仅作说明,不依赖特定链。
选择一个不与主机局域网、VPN 或其他容器网络重叠的子网。子网重叠是路由意外问题的常见原因。
docker network create \
--driver bridge \
--subnet 172.28.0.0/24 \
--gateway 172.28.0.1 \
node-net
docker run -d --name node-a --network node-net \
--restart unless-stopped \
your-node-image:latest
docker run -d --name rpc-client --network node-net \
your-client-image:latest sleep infinity
docker network inspect node-net使用 Podman 创建内部自定义网络
Podman 使用相同的概念,但默认值略有不同。--internal 标志创建一个没有外部连接的网络。这适用于只应由同一网络上的容器访问的后端服务。
创建网络后,在其上运行一个容器,并确认它可以按名称解析对等容器,但无法访问公共地址。确切的错误消息取决于运行时和内核,因此将观察到的失败作为验证信号,而不是期望某个特定字符串。
podman network create \
--subnet 10.89.0.0/24 \
--internal \
backend-net
podman run -d --name backend-api --network backend-net \
your-api-image:latest
podman run --rm --network backend-net your-tools-image:latest \
sh -c 'getent hosts backend-api; curl -sS --max-time 5 https://example.com || echo outbound-blocked'验证 DNS 解析与隔离
验证应是一个可重复的过程,而不是一次性浏览。每次更改网络拓扑后都运行相同的检查。下表是一个模板:填写你环境中的观察结果,而不是假设某个值。
| 检查项 | 命令模式 | 预期信号 | 观察结果 |
|---|---|---|---|
| 名称解析 | 从对等容器执行 getent hosts node-a | 返回自定义子网上的地址 | 记录你的输出 |
| 跨网络隔离 | Ping 不同网络上的容器 | 失败或超时 | 记录你的输出 |
| 内部网络上的出站访问 | 对公共 URL 执行 curl | 被阻止 | 记录你的输出 |
| 已发布端口的可达性 | 从外部对主机端口执行 curl | 仅对你发布的端口成功 | 记录你的输出 |
| 重启后的 DNS | 重启容器后重新运行名称解析 | 仍能解析 | 记录你的输出 |
如果某项检查与预期信号不符,请停下来修复拓扑,然后再添加更多服务。在损坏的网络上叠加更多容器会使故障更难隔离。
docker exec rpc-client getent hosts node-a
docker exec rpc-client sh -c 'curl -sS --max-time 5 http://node-a:8545/health || true'
docker run --rm --network bridge your-tools-image:latest \
sh -c 'getent hosts node-a || echo not-visible-from-default-bridge'通过自定义网络将客户端连接到节点
网络就绪后,客户端应通过容器名称而不是硬编码 IP 来访问节点。这样在容器重启并获得新地址时,配置可以保持稳定。下面的示例使用一个通过自定义网络解析的占位 RPC URL。
如果你的客户端还需要访问公共 RPC 端点,请将其接入第二个非内部网络。这使客户端成为隔离节点网络与外部世界之间的有意桥梁,比让每个容器都具有出站访问权限更容易审计。
export RPC_URL=http://node-a:8545
curl -sS -X POST "$RPC_URL" \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'排查常见的自定义网络故障
大多数自定义网络问题都属于少数几类。名称解析失败通常意味着容器不在同一网络上,或者客户端使用了重启后已更改的 IP。内部网络上的出站失败是预期行为,不是缺陷。端口冲突通常意味着已发布的端口已在主机上被占用。
如果容器可以通过 IP 访问对等容器但无法通过名称访问,请检查两者是否都接入同一用户定义网络,以及运行时的 DNS 解析器是否正在运行。如果容器完全无法访问任何东西,请检查网络并确认子网不与现有路由重叠。
- 容器名称解析失败:确认两个容器共享同一自定义网络。
- 子网重叠:选择主机局域网和 VPN 范围之外的地址段。
- 端口已被分配:更改主机侧端口或停止冲突进程。
- 内部网络阻止了预期流量:将服务移到非内部网络或添加代理。
- 主机访问自定义网络的行为因平台而异:在目标主机上验证,而不仅仅在笔记本电脑上。
局限性与权衡
自定义网络会增加运维开销。每个新网络都是另一个需要命名、记录和清理的对象。覆盖网络会增加延迟,并且需要可用的集群控制平面。内部网络默认安全,但当服务合法地需要获取更新或访问公共 RPC 端点时会不方便。
主机网络有时用于避免 NAT 和端口发布,但它完全移除了隔离边界。对于暴露 RPC 或对等端口的区块链节点,这种权衡值得明确审查。在大多数情况下,具有狭窄发布端口的自定义桥接网络更容易理解。
如果你的目标只是选择一个可靠的公共 RPC 端点,而不是设计容器网络,那么该决策属于提供商比较,而不是本文。使用 RPC Assistant 获取具体的端点和提供商建议,并将本指南保留用于你自己基础设施周围的网络拓扑。
面向生产就绪的后续步骤
将验证表转化为每次部署后运行的脚本。将网络定义与你的 compose 文件或部署清单一起存储在版本控制中。记录每个服务属于哪个网络以及原因。
对于运行专用基础设施的团队,请审查节点托管和 RPC 服务层级如何适应你的拓扑。区块链节点托管指南涵盖了网络之外的运维关注点,多链 RPC 端点指南解释了客户端应如何跨链配置。如果你正在比较托管选项,请参阅 RPC 定价和专用节点。
最后,确定自定义网络与外部服务之间的边界在哪里。一种常见模式是为节点及其可信客户端使用内部网络,再加上通过代理的狭窄出口路径。这样可以将影响范围保持在较小程度,同时仍允许节点同步。
- 对网络定义和验证脚本进行版本控制。
- 每次拓扑更改后重新运行隔离检查。
- 将公共暴露限制在你有意发布的端口上。
- 当剩余问题是使用哪个端点或提供商时,使用 RPC Assistant。