首页 / 资讯中心 / 文章详情

Hyperledger Fabric多机部署实战:Docker跨主机网络与证书配置指南

Hyperledger Fabric多机部署实战:Docker跨主机网络与证书配置指南 ★ FEATURED ARTICLE
1. 从单机到多机为什么这一步非走不可单机跑通Fabric网络说实话只能算见过猪跑。真正到了要模拟生产环境、验证跨节点通信、测试分布式共识的时候单机那套东西立刻就不够用了。我见过太多人卡在这一步——单机环境里链码调用顺畅、通道创建秒过一上多机就开始报各种连接超时、证书验证失败、gRPC握手异常。问题出在哪出在单机环境下所有节点共享同一个Docker网络、同一套DNS解析、同一个文件系统挂载点很多配置你写错了它也能跑通因为环境帮你兜了底。一旦拆到多台机器上这些被掩盖的问题会集中爆发。这篇内容要解决的核心问题就一个如何用Docker把Fabric网络从一台机器扩展到多台机器并且保证网络稳定、可复现、可扩展。适合已经跑通过单机Fabric网络、对通道、排序服务、Peer节点、CA有基本认知的读者。如果你还没跑通单机版本建议先回去把单机流程走一遍否则多机部署会让你怀疑人生。多机部署的本质是什么是把原本靠localhost和容器名就能互相找到的组件拆散到不同的物理或虚拟主机上然后重新建立它们之间的信任关系和通信链路。这里面涉及三个层面的重新设计网络连通性容器怎么跨主机通信、证书体系TLS和签名证书怎么覆盖多机IP和域名、配置管理每个节点的配置文件怎么差异化生成。这三个层面任何一个出问题网络都起不来。我自己的经验是多机部署的难度不在于命令有多复杂而在于信息量大且相互关联——你改了一个节点的配置可能另外三个节点的证书都得重新生成。所以这篇文章不会只给你一堆命令让你复制粘贴而是把每一步背后的逻辑讲清楚让你知道为什么要这么做出了问题该往哪个方向排查。2. 多机部署的架构决策先想清楚再动手2.1 机器角色怎么分配多机部署第一个要做的决策是几台机器每台跑什么。这个问题没有标准答案取决于你的硬件资源和测试目标。但有一个原则是通用的排序服务节点尽量分散在不同机器上。排序服务是Fabric网络的大脑如果所有排序节点都在同一台机器上那台机器一挂整个网络就瘫了多机部署的意义就丢了一半。一个比较典型的最小多机拓扑是这样的三台机器每台跑一个排序节点Raft共识至少需要三个排序节点才能容忍一个故障同时每台机器再跑一个Peer节点。这样三台机器互为备份任何一台挂掉网络还能继续出块和背书。如果你有四台机器可以把CA单独拎出来放一台但CA不是性能瓶颈放哪里影响不大。这里有个容易踩的坑不要把排序节点和Peer节点混在同一台机器上还共用端口。Fabric默认排序服务用7050Peer用7051CA用7054这些端口本身不冲突但如果你在同一台机器上跑多个Peer每个Peer的端口必须错开。我建议的做法是每台机器上给每个组件分配独立的端口段比如机器A的Peer用7051、7052、7053机器B的Peer用8051、8052、8053这样后续加节点的时候不会乱。2.2 跨主机通信方案选型容器跨主机通信有好几种方案Docker原生的Overlay网络、第三方CNI插件、或者最简单的host网络模式。我实测下来对于Fabric这种对网络延迟敏感的场景host网络模式反而是最稳的。为什么因为Overlay网络会引入额外的封装和解封装开销而且VXLAN的MTU问题经常导致大包分片gRPC流式传输的时候容易出现莫名其妙的断连。用host网络模式的意思是容器直接使用宿主机的网络栈容器里的服务监听在宿主机的端口上。这样做的好处是第一没有NAT转换性能损耗最小第二容器里的服务看到的客户端IP就是真实IP方便排查问题第三配置简单不需要额外维护一套Overlay网络。坏处是端口管理要自己规划好不能像bridge网络那样靠Docker自动分配。如果你坚持要用Overlay网络也不是不行但一定要把MTU调对。Docker默认的Overlay网络MTU是1450而Fabric的gRPC消息有时候会超过这个值导致分片。解决办法是在创建网络时显式指定MTU为1400并且在Fabric的配置里把gRPC的max send message size调大。不过我还是那句话能host就host少一层抽象少一堆问题。2.3 证书体系的多机适配单机环境下证书里的SANSubject Alternative Name通常只写了localhost和127.0.0.1这在多机环境下直接废掉——机器A上的Peer用localhost去连机器B上的排序服务连的是它自己当然连不上。所以多机部署必须重新生成证书把每台机器的真实IP和主机名都写进SAN里。具体来说排序节点的TLS证书SAN里要包含所有排序节点的IP、所有排序节点的主机名、以及排序服务的域名如果你配了DNS。Peer节点的TLS证书SAN里要包含该Peer所在机器的IP、该Peer的主机名、以及Peer的域名。CA的证书SAN里要包含CA所在机器的IP和主机名。这里有个细节很多人忽略Fabric的TLS证书验证是双向的不仅客户端要验证服务端证书服务端也要验证客户端证书。所以每个节点的TLS证书里除了自己的信息还要把可能连接它的其他节点的信息也加进去。最省事的做法是把所有节点的IP和主机名都写进每一张TLS证书的SAN里虽然有点冗余但能避免很多证书验证失败的报错。3. 动手前的环境准备这些细节别跳过3.1 机器基础环境统一多机部署最怕什么最怕三台机器的环境不一致。机器A的Docker版本是20.10机器B是24.0机器C是18.09这种环境下你排查问题会疯掉。所以第一步把所有机器的Docker版本统一到同一个大版本我建议用20.10以上的版本对host网络和gRPC的支持都比较成熟。除了Docker版本还要检查几个东西时间同步。Fabric的证书有有效期如果机器之间时间差太大证书验证会直接失败。用timedatectl看一下每台机器的时间差超过30秒就要配NTP同步。文件句柄数。Fabric的Peer和Orderer在高负载下会打开大量文件句柄默认的1024不够用建议调到65535。内核参数。net.core.somaxconn和net.ipv4.tcp_max_syn_backlog这两个参数影响gRPC的连接队列长度默认值偏小建议分别调到32768和16384。还有一个容易被忽略的点主机名解析。如果你不想在每台机器的/etc/hosts里手动维护所有节点的IP映射那就配一个内部DNS。但说实话对于测试环境直接改/etc/hosts更简单直接。把每台机器的IP和主机名写进所有机器的/etc/hosts这样容器里用主机名就能互相访问。3.2 目录结构规划多机环境下目录结构必须提前规划好否则文件散落在各处后面维护起来很痛苦。我的习惯是在每台机器上创建一个统一的根目录比如/opt/fabric-network下面按组件分目录/opt/fabric-network/ ├── crypto-config/ # 证书材料 ├── channel-artifacts/ # 通道配置块 ├── config/ # 各节点配置文件 │ ├── orderer/ # 排序服务配置 │ ├── peer/ # Peer节点配置 │ └── ca/ # CA配置 ├── docker/ # Docker Compose文件 └── scripts/ # 启动、停止、清理脚本这个结构的好处是所有和网络相关的东西都在一个根目录下备份、迁移、清理都很方便。而且每台机器的目录结构完全一致只是config目录下的内容不同这样脚本可以复用。3.3 镜像准备与分发Fabric的Docker镜像有好几个hyperledger/fabric-orderer、hyperledger/fabric-peer、hyperledger/fabric-ca、hyperledger/fabric-tools。这些镜像在每台机器上都要有。最笨的办法是每台机器单独pull但如果你机器多或者网络环境不好建议在一台机器上pull好之后用docker save导出成tar文件再分发到其他机器用docker load导入。镜像的tag一定要统一。我见过有人机器A用2.4机器B用2.4.3结果排序服务和Peer之间的gRPC协议版本不兼容握手直接失败。所以定好一个版本号比如2.4.3所有机器都用这个版本。注意fabric-tools镜像里包含了peer、configtxgen、configtxlator等命令行工具多机环境下你不需要在每台机器上都跑这个容器但建议至少在一台机器上保留用来生成通道配置和证书。4. 证书生成的多机适配实操4.1 crypto-config.yaml的写法证书生成用cryptogen工具核心配置文件是crypto-config.yaml。单机环境下这个文件很简单但多机环境下你需要把每台机器的信息都写进去。关键在Specs部分的Hostname和SANS字段。以排序服务为例假设你有三台机器IP分别是192.168.1.101、192.168.1.102、192.168.1.103主机名分别是orderer1、orderer2、orderer3。那么crypto-config.yaml里排序服务的配置应该这样写OrdererOrgs: - Name: Orderer Domain: example.com EnableNodeOUs: true Specs: - Hostname: orderer1 SANS: - 192.168.1.101 - orderer1 - orderer1.example.com - Hostname: orderer2 SANS: - 192.168.1.102 - orderer2 - orderer2.example.com - Hostname: orderer3 SANS: - 192.168.1.103 - orderer3 - orderer3.example.comPeer节点的配置类似每个Peer的SANS里要包含它所在机器的IP和主机名。这里有个技巧如果你不确定后续会不会加节点可以把所有可能用到的IP段都写进SANS里比如192.168.1.0/24但cryptogen不支持CIDR写法只能一个一个列。所以更实际的做法是预留几个IP的SANS后续加节点的时候重新生成证书。4.2 生成证书并分发cryptogen generate --configcrypto-config.yaml --outputcrypto-config这条命令会在本地生成所有证书材料。生成完之后你需要把对应的证书目录分发到各台机器上。注意不是把所有证书都复制到每台机器而是每台机器只拿自己需要的部分。具体来说机器Aorderer1需要crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/下的所有文件以及crypto-config/ordererOrganizations/example.com/msp/下的组织MSP文件。机器A如果还跑Peer还需要对应的Peer证书目录。分发的时候用scp或者rsync都行但要注意文件权限。Fabric的证书文件权限要求比较严格私钥文件必须是600其他文件可以是644。如果权限不对Peer启动的时候会报private key not found或者permission denied。4.3 证书验证的常见坑证书生成和分发完之后先别急着启动网络做一次验证。验证的方法是在机器A上用openssl x509 -in 证书文件 -text -noout查看证书的SAN字段确认里面包含了机器B的IP和主机名。然后在机器A上用openssl s_client -connect 机器B的IP:端口测试TLS握手看能不能成功。我踩过的一个坑是证书里的CN和实际使用的主机名不一致。比如证书的CN是orderer1.example.com但你在配置里写的是orderer1TLS验证的时候会失败。解决办法是要么在配置里写完整的域名要么在SANS里把短主机名也加进去。我建议两个都加省得后面改来改去。还有一个坑是证书过期。cryptogen默认生成的证书有效期是10年但如果你之前生成过证书后来又重新生成旧证书可能还在某些节点的配置里被引用。所以每次重新生成证书后一定要把所有节点的配置文件和证书目录都更新一遍不能只更新一部分。5. 排序服务多机部署的配置要点5.1 orderer.yaml的差异化配置每个排序节点的orderer.yaml大部分内容是一样的但有几个字段必须差异化General.ListenAddress、General.ListenPort、General.TLS.Enabled、General.TLS.PrivateKey、General.TLS.Certificate、General.TLS.RootCAs、General.Cluster.ServerCertificate、General.Cluster.ServerPrivateKey、General.Cluster.ClientCertificate、General.Cluster.ClientPrivateKey、General.Cluster.RootCAs。ListenAddress建议写0.0.0.0这样容器里监听所有网卡宿主机上的其他机器才能连进来。ListenPort默认是7050如果你在同一台机器上跑多个排序节点这个端口要错开。TLS相关的证书路径要指向该节点自己的证书文件。Cluster部分的配置是Raft共识专用的用于排序节点之间的内部通信。ServerCertificate和ServerPrivateKey是该节点自己的TLS证书和私钥ClientCertificate和ClientPrivateKey是它作为客户端去连其他排序节点时用的证书。在Fabric 2.x里这两个可以复用同一套证书但路径要写对。5.2 系统通道配置块的生成系统通道的创世块用configtxgen生成配置文件是configtx.yaml。多机环境下configtx.yaml里要特别注意OrdererEndpoints和Consenters两个字段。OrdererEndpoints列出了所有排序节点的地址格式是主机名或IP:端口。这个列表会被写进系统通道的配置里Peer节点通过这个列表找到排序服务。所以这里必须写所有排序节点的真实地址不能只写一个。Consenters是Raft集群的成员列表每个成员包含Host、Port、ClientTLSCert、ServerTLSCert四个字段。Host和Port是该排序节点的监听地址ClientTLSCert和ServerTLSCert是该节点的TLS证书路径。注意这里的证书路径是相对于configtxgen运行时的路径不是容器里的路径。所以生成创世块的时候要在证书材料所在的目录下运行configtxgen。生成创世块的命令是configtxgen -profile MultiNodeEtcdRaft -configPath ./config \ -channelID system-channel -outputBlock ./channel-artifacts/genesis.block生成完之后把genesis.block分发到每台机器的channel-artifacts目录下。每个排序节点启动的时候都会读取这个文件所以每台机器上都要有一份。5.3 排序节点启动与验证排序节点的启动用Docker Compose或者直接docker run都行。我习惯用Docker Compose因为配置文件写起来清晰管理也方便。每个排序节点一个Compose文件或者用一个Compose文件加不同的-f参数。启动命令大概是这样的docker-compose -f docker-compose-orderer1.yaml up -d启动之后用docker logs -f 容器名看日志。正常的日志会显示Beginning to serve requests和Raft leader elected之类的信息。如果看到TLS handshake failed或者connection refused说明证书或者网络有问题。验证排序集群是否正常的一个方法是在任意一个排序节点上执行osnadmin channel list命令Fabric 2.x支持看能不能列出系统通道。如果三个排序节点都能正常响应说明Raft集群已经形成。注意Raft集群启动的时候第一个节点会先选举自己为Leader然后其他节点加入。如果三个节点同时启动可能会出现选票分裂导致选举超时。稳妥的做法是先启动一个节点等它成为Leader之后再启动另外两个。6. Peer节点多机部署与通道加入6.1 core.yaml的关键修改Peer节点的配置文件是core.yaml多机环境下需要修改的字段包括peer.id、peer.listenAddress、peer.chaincodeListenAddress、peer.address、peer.tls.enabled、peer.tls.cert.file、peer.tls.key.file、peer.tls.rootcert.file、peer.gossip.bootstrap、peer.gossip.endpoint、peer.gossip.externalEndpoint。peer.id是该Peer的唯一标识建议用主机名比如peer0。peer.listenAddress写0.0.0.0:7051peer.chaincodeListenAddress写0.0.0.0:7052。peer.address写该Peer的可达地址格式是主机名:7051这个地址会被写进背书策略和通道配置里所以必须是其他节点能访问到的地址。peer.gossip.bootstrap是Gossip协议的引导节点地址写该Peer自己或者其他Peer的地址都行。peer.gossip.endpoint写该Peer的Gossip监听地址peer.gossip.externalEndpoint写该Peer对外暴露的Gossip地址。如果Peer在NAT后面externalEndpoint要写公网地址但测试环境一般不需要。6.2 通道创建与加入通道创建用peer channel create命令需要指定排序服务的地址和TLS证书。多机环境下排序服务地址要写真实的IP或主机名不能写localhost。命令大概是这样的peer channel create -o orderer1.example.com:7050 -c mychannel \ -f ./channel-artifacts/mychannel.tx \ --tls --cafile /path/to/orderer-ca-cert.pem通道创建成功之后会在本地生成一个mychannel.block文件。这个文件需要分发到所有要加入该通道的Peer节点上。然后每个Peer用peer channel join命令加入通道peer channel join -b ./channel-artifacts/mychannel.block加入成功之后用peer channel list查看已加入的通道。如果看到mychannel说明加入成功。这里有个坑通道创建的时候排序服务地址必须用TLS证书里SAN包含的地址。比如证书SAN里写的是orderer1.example.com你命令里写192.168.1.101TLS验证会失败。所以要么统一用主机名要么统一用IP别混着来。6.3 Anchor Peer的配置每个组织需要选一个Peer作为Anchor Peer用于跨组织的Gossip通信。Anchor Peer的配置通过通道更新来实现具体步骤是先用peer channel fetch config拉取当前通道配置然后用configtxlator把配置块解码成JSON修改Anchor Peer的地址再编码回二进制最后用peer channel update提交更新。这个过程比较繁琐但多机环境下必须做否则不同组织的Peer之间发现不了对方。Anchor Peer的地址要写该Peer的真实可达地址格式是主机名:7051。7. 多机网络的验证与排错7.1 连通性验证的完整链路网络启动之后不要急着跑链码先做一轮完整的连通性验证。验证的顺序是容器到容器、容器到宿主机、宿主机到宿主机。容器到容器在Peer容器里用ping或者nc测试到排序服务容器的连通性。如果容器用的是host网络这一步其实测的是宿主机到宿主机的连通性。容器到宿主机在容器里测试到宿主机上其他服务的连通性。宿主机到宿主机在宿主机上用telnet或者nc测试到其他机器上端口的连通性。我习惯用nc -zv IP 端口来测试端口连通性比telnet快而且输出更清晰。如果端口不通先用netstat -tlnp看服务有没有在监听再用iptables -L看防火墙有没有拦截。7.2 常见报错与根因定位多机部署最常见的报错有这么几类报错信息可能原因排查方向TLS handshake failed证书SAN不匹配、证书过期、TLS版本不兼容检查证书SAN、有效期、TLS配置connection refused服务没启动、端口没监听、防火墙拦截检查容器状态、端口监听、防火墙规则context deadline exceeded网络延迟大、gRPC超时设置太短检查网络质量、调大gRPC超时certificate signed by unknown authorityCA证书不匹配、根证书没配检查根证书路径、CA证书是否一致channel not found通道没创建、创世块不一致检查通道创建日志、创世块是否相同排查的时候先看日志再看网络最后看配置。日志里通常会有具体的错误信息比如certificate verify failed会告诉你是哪张证书的问题。网络问题用nc和tcpdump定位。配置问题就逐字段对比看哪个字段写错了。7.3 性能调优的几个关键参数多机网络跑通之后如果性能不理想可以调这几个参数peer.gossip.maxBlockCountToStore、peer.gossip.maxPropagationBurstSize、peer.gossip.maxPropagationBurstLatency、peer.gossip.propagateIterations、peer.gossip.propagatePeerNum。这些参数控制Gossip协议的行为调大了会增加网络流量调小了会降低传播速度。排序服务这边General.MaxRecvMsgSize和General.MaxSendMsgSize控制gRPC消息的最大尺寸默认是100MB一般够用。如果链码返回的数据特别大可以适当调大。General.Kafka如果用的是Kafka共识或者General.EtcdRaftRaft共识的参数也会影响性能但Raft的参数一般不需要动。我自己的经验是多机环境下性能瓶颈通常不在Fabric本身而在网络带宽和磁盘IO。所以如果性能上不去先看看网络是不是千兆的磁盘是不是SSD的。这两样上去了Fabric的性能自然就上去了。8. 我踩过的那些坑和对应的解法第一个坑证书里的IP写成了127.0.0.1。单机环境下用cryptogen默认生成的证书SAN里只有localhost和127.0.0.1。多机部署的时候忘了改结果Peer连排序服务的时候排序服务用自己的证书去验证发现客户端证书里的IP是127.0.0.1和自己期望的不一样直接拒绝。解法就是重新生成证书把真实IP写进SAN。第二个坑Docker的host网络模式下容器里的服务监听在127.0.0.1。有些Fabric的默认配置里ListenAddress写的是127.0.0.1在bridge网络下没问题因为Docker会做端口映射。但在host网络下监听127.0.0.1意味着只有宿主机自己能访问其他机器访问不了。解法是把ListenAddress改成0.0.0.0。第三个坑排序节点的Cluster配置里ClientTLSCert和ServerTLSCert写反了。这两个字段一个用于客户端认证一个用于服务端认证写反了会导致排序节点之间无法建立Raft连接。解法是仔细看配置文件里的注释确认每个字段的含义。第四个坑通道创建的时候用了localhost。在机器A上创建通道命令里写-o localhost:7050结果连的是机器A自己但排序服务在机器B上。解法是统一用主机名或真实IP别用localhost。第五个坑文件权限不对导致容器启动失败。Fabric的私钥文件权限必须是600如果从其他机器复制过来的时候权限变了容器启动会报private key not found。解法是用chmod 600把私钥文件权限改对或者用rsync -p保留权限。这些坑说到底都是细节问题但多机部署就是细节决定成败。每一个配置字段、每一个证书SAN、每一个端口号都必须仔细核对。我建议的做法是把所有节点的配置文件放在一起用diff逐对比较确保除了该差异化的字段其他都一样。这样能避免很多为什么机器A能跑机器B不能跑的问题。最后说一个我自己的习惯每次部署完多机网络我都会写一个verify.sh脚本自动检查所有节点的容器状态、端口监听、证书有效期、通道加入情况。这个脚本在后续加节点、改配置的时候特别有用能快速定位是哪个环节出了问题。脚本内容不复杂就是一堆docker ps、nc、openssl命令的组合但省去了每次手动检查的麻烦。
阅读完成 · 觉得有帮助?
咨询建站