Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
基础设施与运维阅读约 11 分钟

面向容器化区块链工作负载的自定义网络设计

一份实用指南,介绍如何为区块链节点、RPC 客户端及配套服务构建、隔离并验证自定义容器网络。

TL;DR

自定义网络是用户定义的容器网络,让你可以控制哪些服务能够互相访问、名称如何解析,以及流量能否离开主机。对于区块链基础设施而言,这一点很重要,因为节点、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。

永远不用担心基础设施

OnFinality 消除了 DevOps 的繁重工作,让您能够更聪明、更快地构建。

开始