Fabric 1.4.4 是我带过不少入门项目后,依然觉得最适合“从零讲清楚联盟链”的一个版本。它虽然是 2019 年的 LTS,但模块边界非常干净:身份怎么生成、排序服务怎么启动、通道怎么创建、链码怎么装上去,每一层都能单独拆开看。这篇文章不吹概念,直接按我实际操作过的路径走一遍:先讲清楚为什么要选这个版本,再准备环境,然后用官方脚本快速验证,最后手动把网络组建起来。想自己动手跑通一条联盟链的人,按这篇文章的顺序来,基本不会卡。
1. 项目整体思路与版本选型
1.1 先搞清楚联盟链到底在“联盟”什么
很多第一次接触 Fabric 的人,最容易混淆的点是:它跟比特币、以太坊这类公链根本不是一回事。公链的核心是“任何人不经许可就能加入”,而联盟链的核心恰好相反——每个成员都要经过审批才能进入网络,节点的身份是可管理的。
放到实际场景里类比,联盟链就像几家合作公司共用一个带权限的档案室。每家公司在档案室里都有自己的独立柜子,但有一个公共台账记录所有柜子的变更情况。约定达成之后,任何公司单独去改公共台账都是不被承认的,必须按照规定流程提交、背书、排序、落账。这种模型天然适合金融结算、供应链溯源、政务协同这类需要多方共享数据但又不想把数据完全公开的业务。
Fabric 把这种模型拆成了几个明确的模块:
- Peer 节点:负责存储账本副本,执行链码(相当于智能合约),在交易中承担背书和校验的角色。
- Orderer 节点:只负责把收到的交易排成有顺序的区块,不保存业务状态,也不执行链码。
- MSP 与证书体系:给每一个组织、每一个节点签发身份证书。谁有权限做什么事,全部由证书决定。
- Channel(通道):一条通道就是一个隔离的账本空间。两个组织在通道 A 里交换数据,通道 B 里的成员完全看不到。
这种“身份 + 通道 + 排序 + 链码”的骨架,是后续所有操作的基础。后面的手动搭建,本质上就是把这四个东西一步步生成出来。
1.2 为什么入门优先选 1.4.4 而不是新版本
我经常被问到一个问题:“现在 Fabric 都到 2.x / 3.x 了,怎么还让我用 1.4.4?”
答案很实在:1.4.4 是最典型的 LTS 版本,同时它保留了 Fabric 设计上最直白的一套节点和通道概念。新版本加入了更多治理、隐私和生命周期管理的抽象,逻辑更强,但对新手来说,反而是额外负担。1.4.4 的链码生命周期非常简单:安装后直接实例化,一条命令就能看到效果。这对理解账本、背书策略、通道关系,远比新版本里那套需要多轮审批的流程更友好。
另外从工程实际看,很多存量系统至今仍然跑在 1.4.x 上,企业里的生产网络、供应链平台,大量是基于这套版本设计出来的。把 1.4.4 的运作原理吃透,再去看 2.x 的“链码生命周期管理”“私有数据”“状态级校验”,几乎是无缝衔接的。
看完版本定位,接下来就要动手做环境准备。这一步是最枯燥但也最决定成败的,我见过太多人卡在环境不对,浪费一整天。
2. 环境准备与核心工具链
2.1 宿主机准备:Docker、内存、磁盘一个都不能少
Fabric 网络本身不是一个单机程序,而是一组容器化的服务节点。所以宿主机必须先具备以下条件:
- Docker与 docker-compose:Fabric 官方教程基于 Docker 容器运行,版本建议 Docker 18.06+ 以上,核心是能正常拉取镜像。
- 内存:最低 4GB,强烈建议 6GB 以上。同时起 Peer、Orderer、CLI 这几个容器,再加上链码容器,内存不足会出现莫名其妙的启动失败。
- 磁盘空间:镜像和构建缓存加起来至少准备 15GB,Fabric 相关镜像每个大约 300-700MB,链码编译还会产生额外的镜像层。
我在实际环境里遇到过内存只有 3GB 的家用机器跑一个双组织网络,Peer 进程频繁被杀,日志却只显示“Killed”。遇到这种问题,优先加内存,而不是去调配置。
在你开始拉取代码之前,建议先做一个最简单的检查:docker info能看到正常的容器信息,再继续。否则后面所有错误都会让人怀疑人生。
2.2 下载二进制工具:使用 bootstrap.sh 或手动拉取
Fabric 官方提供了一键脚本bootstrap.sh,会同时做三件事:拉取 fabric-samples 代码仓库、下载对应版本的二进制工具到本地bin目录、拉取 Docker 镜像。
完整命令一般是:
curl -sSL https://bit.ly/2ysbOFE -o bootstrap.sh chmod +x bootstrap.sh ./bootstrap.sh 1.4.4如果不指定版本,脚本默认拉取当前最新版本,这对想要 1.4.4 的人来说是坑,一定记得加版本参数。
脚本执行完成后,项目的bin目录里会出现几个关键文件:cryptogen、configtxgen、peer、orderer。如果你下载的是官方二进制包,也要把bin目录手动加入 PATH。
我在实际部署中更建议从网速稳定的镜像源拉取 fabric-samples,然后单独下载对应版本的二进制文件。因为 bootstrap.sh 虽然方便,但对网络波动比较敏感,容易在拉镜像阶段中断。拉取完成后,可以用这个命令确认版本对不对:
configtxgen --version只要显示configtxgen的版本是1.4.4,说明工具链没问题。经常有人在这里拿到 1.4.4 的镜像,却配了 1.4.3 的二进制工具,结果生成创世块时直接报错,后面我会单独讲这个坑。
2.3 三个核心工具的分工逻辑
在手动搭建之前,必须先理解这三个工具各自负责什么。很多人搞混了对象,后面操作就全乱套:
| 工具 | 作用 | 我习惯的理解方式 |
|---|---|---|
cryptogen | 根据组织定义文件生成全部证书和 MSP 目录 | 相当于给参加联盟的每个公司、每台设备办“工作证” |
configtxgen | 根据通道配置模板生成创世块、通道交易文件和锚点更新文件 | 相当于制定“公司章程”和“议会开会规则”,并把规则写成文件 |
peer | 负责创建通道、加入通道、安装链码、调用链码 | 相当于“现场执行人员”,所有与账本相关的手续都由它完成 |
这三个工具都是从命令行操作的,输入的都是文件路径,不同的是它们所代表的权限:cryptogen偏离线管理,configtxgen偏配置管理,而peer是在网络真正跑起来之后与运行中的节点交互。
2.4 configtx.yaml 里你需要关注的核心字段
configtx.yaml是一份很容易被忽略但极其重要的文件。它定义了网络中有哪些组织、每个组织的 MSP 路径、通道的排序规则、区块大小和出块策略。
在第一次搭建网络时,我不建议一头扎进去研究所有字段,你需要重点理解这几个:
- Organizations:定义组织名称、MSP ID、MSP 目录位置。注意 MSP ID 必须与证书目录里的组织名称严格一致,否则 Peer 启动时无法识别身份。
- Capabilities:定义通道能力版本。1.4.4 的
V1_4_3能力值是最常用的,不同版本混合会出现兼容性问题。 - Orderer 配置块:
OrdererType默认是solo(单节点排序),生产环境如果用 Raft,字段会多出Consensus和EtcdRaft的配置。新手阶段用 solo 把流程跑通,是最省心的。 - Channel 配置块:
Profiles部分是模板入口,一条 Profile 对应一个完整的通道定义组合。
关于区块参数,常用配置参考如下:
| 参数 | 常见值 | 说明 |
|---|---|---|
BatchTimeout | 2s | 超过这个时间未达成批量,也会强制出块 |
MaxMessageCount | 500 | 每个区块内最大交易数量 |
AbsoluteMaxBytes | 98 MB | 单个区块最大体积 |
PreferredMaxBytes | 512 KB | 据说最常被使用的目标区块尺寸 |
这些值在你手动修改时不需要精确调优,唯一要提醒的是:BatchTimeout如果设得太短,交易还没攒够就会频繁出块,容易造成账本碎片化;设得太长又会让交易确认延迟变高。2 秒属于比较折中的选择。
3. 用官方脚本快速验证环境
3.1 运行 first-network 示例
环境准备无误后,最稳妥的验证方式就是直接跑官方示例。在 fabric-samples 的first-network目录下,执行:
cd fabric-samples/first-network ./byfn.sh generate ./byfn.sh upbyfn.sh generate的作用是调用 crypto-config.yaml 和 configtx.yaml,把证书和通道配置文件生成到crypto-config和channel-artifacts目录里。
byfn.sh up则会按照 docker-compose 编排文件,启动两个组织共四个 Peer 节点、一个 Orderer、一个 CLI 容器,并自动完成建通道、加入通道、安装链码、实例化的全部流程。
如果一切正常,命令最后会输出类似这样的结果:
========== Channel successfully joined ========== ========== Chaincode instantiation is successful ========== ========== All GOOD, BYFN execution completed ==========3.2 验证链码调用结果
脚本跑完后,网络已经可用了,但最好亲自调一次链码验证。进入 CLI 容器:
docker exec -it cli bash然后执行转账调用:
peer chaincode invoke -o orderer.example.com:7050 \ --tls true --cafile /opt/hyperledger/fabric/peer/orderer/tls/tlscacerts/tls-localhost-7050-ca-orderer.pem \ -C mychannel -n mycc \ -c '{"Args":["invoke","a","b","10"]}'再查询一下 a 的余额:
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'如果查询结果从初始的100变为了90,说明整条交易链路已经打通。这里的“打通”不仅是容器起来了,而是:背书节点执行了链码逻辑,交易被排序服务打包成了区块,账本状态发生了实际变更。
跑通脚本之后,很多人会直接开始改配置做自己的网络,但我建议再往下走一步:把官方脚本做的事情手做一遍。只有手做一遍,你才会真正理解第一步到第二步之间,哪些是自动化的“障眼法”,哪些是网络成立的真实条件。
4. 手动搭建第一个网络:不依赖脚本,亲手组建
4.1 设计一个最小但完整的网络
手动搭建并不是把官方脚本删掉重写,而是把它的核心步骤拆开,一步一步执行。我这里设计一个最小可行的网络:一个 Orderer 节点、两个 Peer 节点(分别属于 Org1 和 Org2)、一个 CLI 工具容器。
为什么需要两个组织?因为联盟链的背书策略里通常要有"OR ('Org1MSP.peer','Org2MSP.peer')",只有一家组织参与就不叫联盟链了。生产环境里组织数往往更多,但两个组织已经能完整表达“多成员”这个核心语义。
这里放一个最简单的crypto-config.yaml结构:
OrdererOrgs: - Name: Orderer Domain: example.com Specs: - Hostname: orderer PeerOrgs: - Name: Org1 Domain: org1.example.com EnableNodeOUs: true Template: Count: 1 Users: Count: 1 - Name: Org2 Domain: org2.example.com EnableNodeOUs: true Template: Count: 1 Users: Count: 1Template.Count: 1代表每个组织生成一个 Peer 节点,Users.Count: 1代表额外生成一个普通用户身份(除了默认的 admin 之外)。初学者经常忽略EnableNodeOUs: true,这个字段是后续 Fabric 区分节点身份(peer/orderer/client)的基础。没有它,很多权限校验会走不通。
4.2 生成证书和密钥材料
确认crypto-config.yaml无误后,执行:
cryptogen generate --config=./crypto-config.yaml --output=./crypto-config/命令执行完,crypto-config目录下会按组织生成完整的证书树:
crypto-config/ ├── ordererOrganizations/ │ └── example.com/ │ ├── ca/ │ ├── msp/ │ ├── orderers/ │ └── tlsca/ ├── peerOrganizations/ │ ├── org1.example.com/ │ │ ├── ca/ │ │ ├── msp/ │ │ ├── peers/ │ │ ├── tlsca/ │ │ └── users/ │ └── org2.example.com/这一步是整个网络的安全根基。生成的msp目录里存放的是该组织在通道级别使用的身份,tls证书用于节点之间的安全通信。证书是后续所有权限判断的依据,所以crypto-config目录一定不要提交到公开仓库,也不要随意删除,删了网络里所有节点就变成“没有身份证的人”。
4.3 用 configtxgen 生成创世块和通道配置
接下来编写configtx.yaml。这里给的是一个最小可用版本的关键结构,我故意略去部分重复的组织定义,你在实际操作时可以直接参考官方first-network里的同名文件来补齐细节。
先定义组织和排序者配置:
Organizations: - &OrdererOrg Name: OrdererOrg ID: OrdererMSP MSPDir: crypto-config/ordererOrganizations/example.com/msp - &Org1 Name: Org1MSP ID: Org1MSP MSPDir: crypto-config/peerOrganizations/org1.example.com/msp AnchorPeers: - Host: peer0.org1.example.com Port: 7051 - &Org2 Name: Org2MSP ID: Org2MSP MSPDir: crypto-config/peerOrganizations/org2.example.com/msp AnchorPeers: - Host: peer0.org2.example.com Port: 7051 Orderer: &OrdererDefaults OrdererType: solo Addresses: - orderer.example.com:7050 BatchTimeout: 2s BatchSize: MaxMessageCount: 500 AbsoluteMaxBytes: 98 MB PreferredMaxBytes: 512 KB Organizations: - *OrdererOrg Profiles: TwoOrgsOrdererGenesis: Orderer: <<: *OrdererDefaults Organizations: - *OrdererOrg Consortiums: SampleConsortium: Organizations: - *Org1 - *Org2 TwoOrgsChannel: Consortium: SampleConsortium Application: Organizations: - *Org1 - *Org2有了这个文件,依次执行三条命令:
mkdir channel-artifacts configtxgen -profile TwoOrgsOrdererGenesis \ -channelID byfn-sys-channel \ -outputBlock ./channel-artifacts/genesis.block configtxgen -profile TwoOrgsChannel \ -outputCreateChannelTx ./channel-artifacts/channel.tx \ -channelID mychannel configtxgen -profile TwoOrgsChannel \ -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx \ -channelID mychannel -asOrg Org1MSP configtxgen -profile TwoOrgsChannel \ -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx \ -channelID mychannel -asOrg Org2MSP这里的核心逻辑要理解清楚:
- 创世块是排序服务的第一个区块,它包含联盟里所有组织的信息,相当于“网络成立的公告”。
- channel.tx是创建业务通道时的初始配置交易,它定义了通道里存在哪些组织,但内容比创世块简单。
- 锚点更新文件用于在通道内部广播“我这个组织的 peer 在哪里”,相当于告诉通道里的其他成员“我就是这个组织的联络点”。
每次执行configtxgen都可能出现大量日志输出,看到Generating genesis block或者Writing new channel tx就说明成功了。如果中途报错,优先检查MSPDir路径是否与cryptogen生成的实际路径一致。
4.4 编写并启动 docker-compose 服务
证书和配置产出后,需要把它变成运行中的服务节点。这一环节要比前几步复杂,因为你不仅要给每个节点配置容器,还要把证书目录挂载进容器对应位置。
一个最小化的docker-compose-cli.yaml需要包含四类服务:
- orderer.example.com:排序服务节点
- peer0.org1.example.com+peer0.org2.example.com:两个组织的 peer
- cli:命令行工具容器,便于执行 peer 命令
关键挂载配置这样写:
services: orderer.example.com: image: hyperledger/fabric-orderer:1.4.4 container_name: orderer.example.com environment: - ORDERER_GENERAL_LOGLEVEL=debug - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 - ORDERER_GENERAL_GENESISMETHOD=file - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block - ORDERER_GENERAL_LOCALMSPID=OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp - ORDERER_GENERAL_TLS_ENABLED=true - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] working_dir: /opt/gopath/src/github.com/hyperledger/fabric volumes: - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls:/var/hyperledger/orderer/tlsPeer 节点的配置逻辑类似,以 Org1 为例:
peer0.org1.example.com: image: hyperledger/fabric-peer:1.4.4 container_name: peer0.org1.example.com environment: - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - CORE_PEER_ID=peer0.org1.example.com - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 - CORE_PEER_LOCALMSPID=Org1MSP - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/msp - CORE_PEER_TLS_ENABLED=true - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key volumes: - /var/run/:/host/var/run/ - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls启动全部服务:
docker-compose -f docker-compose-cli.yaml up -d执行以后,用docker ps检查容器状态。正常状态下所有容器都要是Up状态。如果某个 Peer 反复重启,大概率是证书路径挂载错了,直接看容器日志定位:
docker logs peer0.org1.example.com日志里会明确告诉你 MSP 目录里的config.yaml是否存在、TLS 证书是否找到、创世块是否能解析。这是工厂里先看日志再猜问题的典型思路,比盲目改配置有效得多。
4.5 创建通道、加入通道
容器起来后,进入 CLI 容器开始执行“现场操作”:
docker exec -it cli bashCLI 容器内部已经预置了组织相关的环境变量,但你要明确自己现在操作的是哪个组织。默认 CLI 容器绑定的是 Org1,使用 Org2 操作时需要切换环境变量。
首先创建通道:
peer channel create \ -o orderer.example.com:7050 \ -c mychannel \ -f ./channel-artifacts/channel.tx \ --tls true \ --cafile /opt/hyperledger/fabric/peer/orderer/tls/tlscacerts/tls-localhost-7050-ca-orderer.pem这条命令会向 Orderer 提交通道创建请求,返回一个mychannel.block文件。这个文件就是通道的创世区块,后续加入通道必须依赖它。
然后 Org1 的 peer 加入通道:
peer channel join -b mychannel.block切换到 Org2 的上下文后重复操作,通常是设置这些环境变量:
CORE_PEER_LOCALMSPID=Org2MSP CORE_PEER_ADDRESS=peer0.org2.example.com:7051 CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt再看一下已加入的通道:
peer channel list输出里出现mychannel才算真正加入成功。
这里有一个操作上的重点:通道创建只需要一次,但加入动作必须是每个组织的 peer 分别执行。如果某个组织不执行 join,它在这个通道里就没有账本副本,自然也无法参与背书。
4.6 安装并实例化链码
通道创建好只是有了“场地”,真正产生业务逻辑的是链码。一段链码相当于办公室里的业务规则:里面写了 a、b 两个账户各有多少余额,转账时怎么改状态。
首先把示例链码复制到 CLI 容器的 GOPATH 路径下,Fabric 1.4.4 默认使用 Go 链码。先在宿主机把链码文件放到fabric-samples/chaincode/chaincode_example02/go/下,然后安装:
peer chaincode install -n mycc -v 1.0 \ -p github.com/chaincode/chaincode_example02/go/Org1 执行完安装后,还要切换到 Org2 的环境变量,再安装一次。因为在实际网络中,背书节点必须能拿到链码,否则它无法参与链码调用。
接下来在 Org1 上发起实例化:
peer chaincode instantiate \ -o orderer.example.com:7050 \ --tls true \ --cafile /opt/hyperledger/fabric/peer/orderer/tls/tlscacerts/tls-localhost-7050-ca-orderer.pem \ -C mychannel \ -n mycc \ -v 1.0 \ -c '{"Args":["init","a","100","b","200"]}' \ -P "OR ('Org1MSP.peer','Org2MSP.peer')"这条命令才真正把链码启动起来,并初始化了账本状态。里面的-P参数是背书策略,意思是“只要有 Org1 或 Org2 任一组织的 peer 背书,这笔交易就有效”。
实例化会触发链码容器构建。第一次会比较慢,因为要编译 Go 代码并生成对应镜像。此时可以观察:
docker ps如果你看到类似dev-peer0.org1.example.com-mycc-1.0的容器,说明链码已经成功启动。
4.7 转账调用与结果验证
链码实例化成功后,就可以和前面快速验证时一样,执行转账:
peer chaincode invoke \ -o orderer.example.com:7050 \ --tls true \ --cafile /opt/hyperledger/fabric/peer/orderer/tls/tlscacerts/tls-localhost-7050-ca-orderer.pem \ -C mychannel -n mycc \ -c '{"Args":["invoke","a","b","10"]}'然后分别查询两个组织的 Peer 是否都拿到了同样的结果:
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'如果输出90,且 Org2 的 Peer 查询结果相同,说明账本已经在这个通道内的所有 Peer 上完成了状态同步。
走到这一步,一条“从零到链码可调用”的联盟链就已经完整搭起来了。整个过程回顾起来其实就四件事:申请身份、写配置、起节点、部署链码。
5. 常见问题与排查技巧实录
5.1 版本不一致导致的“疑难杂症”
这是排第一位的坑。fabric-samples 仓库、二进制工具、Docker 镜像三者版本必须严格对齐。我只用官方一套操作做示例,但现实中很多人是自己分开下载的,容易遇到configtxgen生成创世块时报无法识别V1_4_3能力,或者 Peer 启动后日志里出现unknown capability。
排查方法是统一检查三个地方:
configtxgen --version docker images | grep fabric镜像标签必须全部包含1.4.4。如果镜像版本是latest,实际可能是 2.x,二进制却是 1.4.4,网络根本立不起来。
我见过一个典型案例:宿主机上同时存在 1.4.4 和 2.2 两套 fabric-samples 目录,结果 CLI 容器映射的路径指向了 2.2 的 crypto-config,启动后 MSP 目录结构完全不同,Peer 一直报找不到组织的admincerts。排查到最后,只是因为路径变量写错了。
5.2 镜像拉取慢或失败
网络原因导致 Docker Hub 镜像拉取中断,是入门时最崩溃的问题之一。几个可行方案:
- 先尝试在本地配置可信的镜像加速器地址,再
docker pull hyperledger/fabric-peer:1.4.4等逐个拉取。 - 重点拉取这些镜像:
fabric-peer、fabric-orderer、fabric-ccenv、fabric-tools。其中fabric-ccenv是链码容器的基础镜像,很多人会漏掉它。 - 确认镜像都拉取成功后,再运行
docker-compose up,而不是让脚本自己边拉边启动。
有一个经验值得分享:直接在docker-compose里写镜像版本,不要用latest,这样可以避开后期缓存错乱的问题。1.4.4 的镜像名统一是hyperledger/fabric-*:1.4.4,写清楚比什么都稳。
5.3 链码 instantiate 一直报错
链码实例化失败,是所有 Fabric 新手都会遇到的高频问题。错误信息五花八门,但归纳起来大多数是这几种:
| 症状 | 原因 | 解决思路 |
|---|---|---|
chaincode registration failed | 链码容器没有启动或编译失败 | 观察dev-peer...容器日志,常见是 Go 代码路径错误 |
chaincode already exists | 上一次实例化失败但中间状态未清理 | 使用peer chaincode package打包并尝试新版本号,或手动清理相关容器 |
Error: endorsement failure | 背书策略要求多个组织,但只有一个组织装了链码 | 检查 Org2 是否执行了 install 命令 |
Error: could not assemble transaction | Orderer 与 Peer 之间 TLS 配置不一致 | 核对 CA 文件路径,单个阶地使用 root CA 而不是组织 CA |
我习惯的做法是:遇到 instantiate 失败,先看链码容器日志,再清理干净重新来。不要反复修改同一版本号重试,因为 Fabric 对重复实例化的状态处理会让问题越搞越乱。手动清理时可以用:
docker rm -f $(docker ps -aq --filter "name=dev-peer")删除所有链码容器后,再重新安装、实例化,通常能解决大半问题。
5.4 端口占用与网络残留
Fabric 默认使用不少端口:Orderer 的 7050,Peer 的 7051 和 7053,CLI 的 7053 等。如果你之前跑过其它区块链框架,或者同机的 Docker 容器占用了这些端口,会直接导致节点启动失败。
清理时不要简单 kill 进程,而是把整套 Docker 资源重置干净:
docker-compose -f docker-compose-cli.yaml down -v docker rm -f $(docker ps -aq) docker network prune -f-v很关键,它会删除容器挂在的卷。否则你可能费力清掉容器,但旧数据卷还带着上个网络的创世块残留,启动后新的 Peer 会拿到完全不一致的配置。
5.5 操作顺序与配置速查
最后补一张我常用的操作顺序速查表,接近“抄作业”的参考。做一次完整网络部署时,每一步的关键确认点都在里面:
| 序号 | 操作 | 关键确认点 |
|---|---|---|
| 1 | 生成证书 | 两个组织的 MSP 目录是否都有 ca/tls/msp |
| 2 | 生成创世块 | 日志是否显示Successfully generated genesis block |
| 3 | 生成 channel.tx | 日志是否显示Writing new channel tx |
| 4 | 启动容器 | docker ps全部Up |
| 5 | 创建通道 | 返回mychannel.block |
| 6 | 加入通道 | peer channel list显示 mychannel |
| 7 | 安装链码 | 两个组织都执行了 install |
| 8 | 实例化链码 | 出现dev-peer...容器 |
| 9 | 转账验证 | query 结果为 90 |
这张表如果每一步都能对得上,说明你的第一个 Fabric 网络已经从“跑通”升级到了“理解”。
我自己的实际操作体会是:Fabric 初期的“陡峭感”大多来自环境、版本和证书路径,而不是链码本身。只要把 crypto-config.yaml 和 configtx.yaml 这两份文件吃透,再把 docker-compose 的挂载目录跟磁盘实际目录对照一遍,后面所有问题基本都是顺藤摸瓜的事。这个 1.4.4 的网络搭完,建议你再自己改一改组织数量、换一换链码逻辑,甚至试一下启用 CouchDB 作为状态数据库。把这条链路玩熟了,再看新版本里的私有数据和新的链码生命周期,你会发现底子已经完全够用。