1. 多机部署前必须想清楚的几件事
单机跑通Fabric网络只是入门,真正到了多机部署这一步,坑的数量会翻好几倍。我前后搭过五六套不同规模的多机环境,从两台虚拟机到跨机房的四节点集群都折腾过,每次都会遇到新问题。这一篇接着前面的单机部署往下讲,重点解决多台物理机或虚拟机之间怎么把Fabric网络串起来。
先说清楚适用场景。如果你手头只有一台机器,单机方案完全够用,没必要硬上多机。但下面这几种情况就必须走多机路线了:一是需要模拟真实生产环境的分布式拓扑,比如orderer和peer分别部署在不同网段;二是单机资源扛不住,四个peer加三个orderer再加CA,内存直接吃满;三是团队协作时需要每个人连自己的节点,不想互相干扰。这几种场景我都遇到过,多机部署是绕不过去的坎。
多机部署和单机的本质区别在于网络通信和证书体系这两块。单机环境下所有容器共享一个docker网络,容器名就是主机名,通信走内部DNS就行。多机环境下每台机器有自己的IP,容器之间要跨主机通信,就得解决端口映射、证书SAN配置、时钟同步这几个核心问题。很多人单机跑得飞起,一到多机就卡在TLS握手失败或者gRPC连接超时上,根子都在这里。
这篇文章会从网络规划开始,一步步带你完成多机Fabric网络的搭建。我会把每一步的参数选择理由讲清楚,把踩过的坑标出来,让你少走弯路。需要说明的是,下面涉及的具体IP、路径、组织名称都是示例,你实际部署时按自己的环境替换即可。
2. 多机网络架构设计与规划
2.1 节点分布方案怎么定
多机部署第一步不是敲命令,而是画拓扑图。你得先想清楚哪些节点放哪台机器上。常见的分法有三种:按角色分、按组织分、混合分。
按角色分就是把orderer单独放一台,peer放另一台或几台。这种分法适合orderer负载较重的场景,因为orderer负责排序和出块,资源消耗相对独立。按组织分就是每个组织一台机器,组织内部的peer和CA都放一起。这种分法适合多组织联盟链场景,每个组织管理自己的机器,权限清晰。混合分则是综合考虑,比如orderer单独一台,两个组织各一台,CA再单独一台。
我个人的建议是,如果机器数量够,orderer单独一台,每个组织至少一台。这样出问题时排查范围小,不会因为一台机器挂了整个网络瘫痪。下面用一个四机方案来演示,拓扑如下:
| 机器别名 | IP地址 | 部署节点 | 用途 |
|---|---|---|---|
| orderer-host | 192.168.1.10 | orderer0 | 排序服务 |
| org1-host | 192.168.1.11 | peer0.org1, ca.org1 | 组织1节点 |
| org2-host | 192.168.1.12 | peer0.org2, ca.org2 | 组织2节点 |
| cli-host | 192.168.1.13 | cli客户端 | 运维操作 |
这个方案里cli单独一台机器,好处是运维操作不影响业务节点,而且cli可以随时重置不影响网络。如果机器紧张,cli可以跟org1-host合并,但要注意端口冲突。
2.2 端口规划与防火墙策略
多机部署最容易忽略的就是端口。单机环境下容器之间通信不经过宿主机防火墙,多机环境下每个跨主机连接都要经过防火墙。Fabric用到的端口主要有这几类:
- orderer的排序服务端口,默认7050
- peer的链码服务端口,默认7052
- peer的gossip端口,默认7051
- CA服务端口,默认7054
- 各节点的operations监控端口,默认9443等
规划端口时有个原则:同一台机器上不同节点的同类端口必须错开。比如org1-host上如果跑两个peer,那peer0用7051,peer1就得用8051或别的。这个在docker-compose里通过端口映射控制。
防火墙方面,我踩过最大的坑是只开了业务端口没开gossip端口。Fabric的peer之间通过gossip协议同步区块和状态,如果gossip端口不通,节点能启动但数据同步不了,表现就是peer日志一直报"connection refused"。所以防火墙规则要一次性配齐:
# 在每台机器上执行,开放Fabric所需端口 sudo firewall-cmd --permanent --add-port=7050/tcp sudo firewall-cmd --permanent --add-port=7051/tcp sudo firewall-cmd --permanent --add-port=7052/tcp sudo firewall-cmd --permanent --add-port=7053/tcp sudo firewall-cmd --permanent --add-port=7054/tcp sudo firewall-cmd --permanent --add-port=9443/tcp sudo firewall-cmd --reload注意:如果用的是云服务器,除了系统防火墙还要检查安全组规则。我遇到过系统防火墙开了但安全组没开的情况,排查了半天才发现。
2.3 时钟同步这个隐形杀手
这个问题单机部署时根本不会遇到,多机部署时如果不同步,TLS证书验证会直接失败。Fabric的证书有生效时间和过期时间,如果两台机器时间差超过证书容忍范围,握手就会报"certificate is not yet valid"或者"certificate has expired"。
我建议所有机器都配置NTP同步。具体操作:
# 安装chrony sudo yum install chrony -y # 启动并设置开机自启 sudo systemctl start chronyd sudo systemctl enable chronyd # 检查同步状态 chronyc sources -v看到输出里有个^*标记的源就说明同步正常了。如果内网没有NTP服务器,可以指定一个可用的时间源。这一步花五分钟,能省掉后面几小时的排查时间。
3. 证书体系的多机适配
3.1 为什么单机证书不能直接用
单机部署时,我们用cryptogen工具生成的证书里,SAN字段填的是容器名,比如"peer0.org1.example.com"。容器之间通过docker网络的DNS解析这个名称,所以证书能验证通过。
多机环境下,跨主机通信走的是IP地址,证书里的SAN必须包含目标机器的IP,否则TLS握手时客户端拿IP去验证证书,发现证书里没有这个IP,直接拒绝连接。这就是为什么很多人把单机配置原样搬到多机就报"x509: certificate is valid for peer0.org1.example.com, not 192.168.1.11"。
解决办法有两个:一是证书SAN里同时填域名和IP,二是配置hosts文件让域名解析到对应IP。我推荐两个都做,双保险。
3.2 用Fabric CA重新签发证书
生产环境不建议用cryptogen,应该用Fabric CA。多机环境下CA的部署也要跨主机,这里以org1的CA为例。
首先在org1-host上启动CA容器。CA的配置需要指定数据库、证书路径等。启动命令:
docker run -d --name ca.org1.example.com \ -p 7054:7054 \ -e FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server \ -e FABRIC_CA_SERVER_CA_NAME=ca.org1.example.com \ -e FABRIC_CA_SERVER_TLS_ENABLED=true \ -v /data/ca/org1:/etc/hyperledger/fabric-ca-server \ hyperledger/fabric-ca:1.5 \ sh -c 'fabric-ca-server start -b admin:adminpw -d'这里-b admin:adminpw是CA的管理员账号密码,生产环境要改复杂。FABRIC_CA_SERVER_TLS_ENABLED=true开启TLS,多机环境必须开。
CA启动后,需要注册peer节点身份并签发证书。注册命令:
export FABRIC_CA_CLIENT_HOME=/data/ca/org1/admin fabric-ca-client enroll -u https://admin:adminpw@192.168.1.11:7054 \ --caname ca.org1.example.com \ --tls.certfiles /data/ca/org1/tls-cert.pem然后注册peer0:
fabric-ca-client register --caname ca.org1.example.com \ --id.name peer0 --id.secret peer0pw --id.type peer \ --tls.certfiles /data/ca/org1/tls-cert.pem注册完再enroll,生成peer0的MSP目录。关键点来了:enroll时要指定CSR的SAN字段。命令如下:
fabric-ca-client enroll -u https://peer0:peer0pw@192.168.1.11:7054 \ --caname ca.org1.example.com \ -M /data/peer0/msp \ --csr.hosts peer0.org1.example.com,192.168.1.11 \ --tls.certfiles /data/ca/org1/tls-cert.pem--csr.hosts里同时写了域名和IP,这样签出来的证书两个都能验证。这一步是多机部署的核心,漏了IP后面必报错。
3.3 TLS证书的SAN配置
除了身份证书,TLS证书也要配SAN。TLS证书用于节点之间的加密通信,同样需要包含IP。在enroll TLS证书时:
fabric-ca-client enroll -u https://peer0:peer0pw@192.168.1.11:7054 \ --caname ca.org1.example.com \ -M /data/peer0/tls \ --enrollment.profile tls \ --csr.hosts peer0.org1.example.com,192.168.1.11 \ --csr.hosts 192.168.1.11 \ --tls.certfiles /data/ca/org1/tls-cert.pem注意TLS证书的profile是tls,跟身份证书不同。签完后把tls/signcerts下的证书改名为server.crt,tls/keystore下的私钥改名为server.key,放到peer的tls目录下。
实操心得:证书签发后可以用openssl检查SAN是否包含IP。命令是
openssl x509 -in server.crt -text -noout | grep -A1 "Subject Alternative Name",输出里能看到DNS和IP列表就对了。
4. 多机Docker网络与容器编排
4.1 跨主机通信方案选择
多机环境下容器怎么通信,有三种方案:host网络、overlay网络、端口映射。
host网络就是容器直接用宿主机网络,性能最好但端口不能冲突,一台机器只能跑一个同端口服务。overlay网络是Docker Swarm的功能,能跨主机组建虚拟网络,但配置复杂,而且Fabric官方示例没这么用。端口映射是最常用的方案,容器内部用固定端口,通过-p映射到宿主机不同端口,跨主机通过宿主机IP加映射端口访问。
我推荐端口映射方案,原因是配置直观、排查方便、跟Fabric官方示例兼容。缺点是端口管理要仔细,但做好规划就不是问题。
4.2 docker-compose文件的多机改造
单机的docker-compose文件搬到多机,主要改这几个地方:
第一,networks部分。单机用自定义bridge网络,多机可以保留bridge但要去掉external依赖,或者直接用默认网络。我习惯每台机器上建一个独立的bridge网络,容器之间通过容器名通信,跨主机通过IP。
第二,环境变量里的地址。单机配置里ORDERER_GENERAL_LISTENADDRESS=0.0.0.0不用改,但CONFIGTX_ORDERER_ADDRESSES要改成orderer所在机器的IP。peer的CORE_PEER_GOSSIP_BOOTSTRAP和CORE_PEER_GOSSIP_EXTERNALENDPOINT也要改成对应IP。
第三,volumes路径。多机环境下每台机器的证书路径不同,要用绝对路径或者各自机器上的相对路径。
以peer0.org1的compose片段为例:
peer0.org1.example.com: container_name: peer0.org1.example.com image: hyperledger/fabric-peer:2.4 environment: - CORE_PEER_ID=peer0.org1.example.com - CORE_PEER_ADDRESS=192.168.1.11:7051 - CORE_PEER_LISTENADDRESS=0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS=192.168.1.11:7052 - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 - CORE_PEER_GOSSIP_BOOTSTRAP=192.168.1.11:7051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=192.168.1.11:7051 - CORE_PEER_LOCALMSPID=Org1MSP - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp - CORE_PEER_TLS_ENABLED=true - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt volumes: - /data/peer0/msp:/etc/hyperledger/fabric/msp - /data/peer0/tls:/etc/hyperledger/fabric/tls ports: - 7051:7051 - 7052:7052 - 9443:9443 networks: - fabric_net关键改动是CORE_PEER_ADDRESS、CORE_PEER_CHAINCODEADDRESS、CORE_PEER_GOSSIP_BOOTSTRAP、CORE_PEER_GOSSIP_EXTERNALENDPOINT这四个都填了宿主机IP。CORE_PEER_LISTENADDRESS和CORE_PEER_CHAINCODELISTENADDRESS保持0.0.0.0,表示监听所有网卡。
4.3 通道配置文件的IP替换
创建通道用的configtx.yaml里,orderer的地址也要改成IP。在OrdererEndpoints和Consenters部分:
OrdererEndpoints: - 192.168.1.10:7050 Consenters: - Host: 192.168.1.10 Port: 7050 ClientTLSCert: /data/orderer/tls/server.crt ServerTLSCert: /data/orderer/tls/server.crt如果orderer集群有多个节点,每个都要列出来。这里只演示单orderer的情况。
通道的genesis block生成后,里面就固化了orderer地址。如果后面改了IP,需要重新生成genesis block并重新创建通道。所以IP规划要在生成genesis之前定好,别中途改。
5. 完整部署流程实操
5.1 环境准备与依赖安装
每台机器都要装Docker和Docker Compose。版本要求Docker 20以上,Compose 2.0以上。安装命令:
# 安装Docker sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io sudo systemctl start docker sudo systemctl enable docker # 安装Docker Compose sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose然后拉取Fabric相关镜像。每台机器按需拉取,orderer机器拉orderer镜像,peer机器拉peer和ccenv镜像,CA机器拉fabric-ca镜像。镜像版本要统一,我用的2.4系列。
docker pull hyperledger/fabric-orderer:2.4 docker pull hyperledger/fabric-peer:2.4 docker pull hyperledger/fabric-ccenv:2.4 docker pull hyperledger/fabric-ca:1.5 docker pull hyperledger/fabric-tools:2.4注意:ccenv镜像是链码运行环境,每个跑链码的peer机器都要拉。如果链码用Go写,还要拉fabric-baseos镜像。
5.2 证书生成与分发
按第3节的方法,在每台机器上生成各自的证书。生成完后,需要把根证书分发给其他机器。比如org1的CA根证书要放到orderer机器上,这样orderer验证org1的peer证书时才有信任链。
分发方式可以用scp:
# 在org1-host上执行,把CA根证书拷到orderer-host scp /data/ca/org1/ca-cert.pem root@192.168.1.10:/data/certs/org1-ca-cert.pemorderer的configtx.yaml里要配置各组织的MSP路径,指向这些分发的证书。
5.3 启动orderer节点
在orderer-host上,先生成genesis block。需要configtx.yaml和crypto-config。生成命令:
configtxgen -profile TwoOrgsOrdererGenesis \ -channelID system-channel \ -outputBlock /data/orderer/genesis.block然后启动orderer容器:
docker-compose -f docker-compose-orderer.yaml up -d检查日志:
docker logs -f orderer.example.com看到"Beginning to serve on service address 192.168.1.10:7050"就说明启动成功。
5.4 启动peer节点并加入通道
在org1-host和org2-host上分别启动peer。启动前确认peer的MSP和TLS证书路径正确。
docker-compose -f docker-compose-peer.yaml up -dpeer启动后,用cli创建通道。在cli-host上操作:
# 设置环境变量 export ORDERER_CA=/data/certs/orderer-ca-cert.pem export CHANNEL_NAME=mychannel # 创建通道 peer channel create -o 192.168.1.10:7050 -c $CHANNEL_NAME \ -f /data/channel/mychannel.tx \ --ordererTLSHostnameOverride orderer.example.com \ --tls --cafile $ORDERER_CA这里--ordererTLSHostnameOverride很关键。因为orderer证书的SAN里可能只有域名没有IP,用IP连接时TLS验证会失败,加上这个参数让客户端用域名去验证证书。
然后各peer加入通道:
# 在org1的cli环境 peer channel join -b mychannel.block # 在org2的cli环境 peer channel join -b mychannel.block加入成功会返回"Successfully submitted proposal to join channel"。
5.5 链码安装与跨机调用
链码安装要在每个需要背书的peer上分别执行。以org1的peer0为例:
peer lifecycle chaincode package mycc.tar.gz \ --path /data/chaincode/mycc \ --lang golang \ --label mycc_1.0 peer lifecycle chaincode install mycc.tar.gz安装完会返回package ID,记下来。然后在org2的peer上也安装同样的链码。
接下来是approve和commit。这一步需要两个组织都approve,然后由一个peer commit。approve命令:
peer lifecycle chaincode approveformyorg \ -o 192.168.1.10:7050 \ --channelID mychannel \ --name mycc \ --version 1.0 \ --package-id <package_id> \ --sequence 1 \ --tls --cafile $ORDERER_CA两个组织都approve后,检查commit readiness:
peer lifecycle chaincode checkcommitreadiness \ --channelID mychannel --name mycc --version 1.0 --sequence 1 --tls --cafile $ORDERER_CA看到两个组织都是true就可以commit了。
6. 多机环境常见问题排查
6.1 TLS握手失败排查思路
这是多机部署最高频的问题。报错通常是"tls: bad certificate"或者"x509: certificate signed by unknown authority"。排查步骤:
第一步,确认证书SAN是否包含目标IP。用openssl检查:
openssl x509 -in server.crt -text -noout | grep -A1 "Subject Alternative Name"第二步,确认CA根证书是否正确分发。客户端验证服务端证书时,需要服务端CA的根证书。检查--cafile指向的文件是否是签发服务端证书的那个CA的根证书。
第三步,确认时钟同步。用date命令对比两台机器的时间,差超过几分钟就要查NTP。
第四步,确认--ordererTLSHostnameOverride参数。如果证书SAN里只有域名,用IP连接时必须加这个参数。
6.2 gossip同步失败排查
peer启动正常但区块不同步,日志报"Failed to connect to peer"。排查:
- 检查gossip端口是否开放,默认7051
- 检查
CORE_PEER_GOSSIP_BOOTSTRAP是否指向正确的peer地址 - 检查
CORE_PEER_GOSSIP_EXTERNALENDPOINT是否填了本机IP - 检查两个peer的TLS根证书是否互相信任
我遇到过一次gossip同步失败,最后发现是CORE_PEER_GOSSIP_EXTERNALENDPOINT填了容器名而不是IP,跨主机解析不了。改成IP就好了。
6.3 链码容器启动失败
链码安装后第一次调用时,peer会启动一个链码容器。多机环境下链码容器也在peer所在机器上启动,但需要能访问peer的地址。常见报错是链码容器启动后连不上peer。
原因是链码容器通过CORE_PEER_CHAINCODEADDRESS连接peer,这个地址必须是peer所在机器的IP,不能是容器名。检查peer的compose配置里这个变量是否填了IP。
另外链码容器需要拉取fabric-ccenv镜像,如果peer机器上没有这个镜像,链码容器启动会失败。提前拉好。
6.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| TLS握手失败 | 证书SAN缺IP | openssl检查SAN |
| 证书验证失败 | CA根证书未分发 | 检查cafile路径 |
| 时钟不同步 | NTP未配置 | date对比时间 |
| gossip不同步 | 端口未开放 | telnet测试端口 |
| 链码容器启动失败 | 镜像缺失或地址错误 | 检查ccenv镜像和CHAINCODEADDRESS |
| orderer连接超时 | 防火墙或IP错误 | ping和telnet测试 |
| 通道创建失败 | genesis block地址不对 | 重新生成genesis |
实操心得:多机部署出问题时,先用
telnet IP 端口测试网络连通性,再用docker logs看容器日志,最后用openssl检查证书。这三板斧能解决八成问题。
7. 生产环境的一些经验补充
多机部署跑通只是第一步,真正上生产还要考虑高可用和监控。orderer建议部署集群,至少三个节点,用Raft共识。peer的gossip配置要调优,CORE_PEER_GOSSIP_USELEADERELECTION设为true让节点自动选主。
监控方面,Fabric 2.x提供了operations服务,可以暴露Prometheus指标。在每个节点的compose里加CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:9443,然后配Prometheus抓取。我一般会监控区块高度、交易数量、gossip连接数这几个指标。
日志收集也很重要。多机环境下日志分散在各机器,排查问题要一台台登。建议用ELK或者Loki收集,每个容器的日志通过docker的log driver转发到中心。这个配置一次,后面省心很多。
最后说个数据备份的事。多机环境的证书和MSP目录一定要备份,丢了就得重新签发,通道里的历史数据可能就访问不了了。我习惯用rsync定时同步到备份服务器,简单可靠。
这套多机方案我在几个项目里都用过,稳定性没问题。关键是把网络规划、证书SAN、时钟同步这三块做扎实,后面基本不会出大问题。链码和通道操作跟单机一样,多机只是多了跨主机通信这一层,理解了就不难。