参考文章
- 触不可及的深入解析Hyperledger Fabric搭建的全过程:
https://ifican.top/2019/11/23/blog/fabric/%E6%B7%B1%E5%85%A5%E8%A7%A3%E6%9E%90Fabric%E6%90%AD%E5%BB%BA%E7%9A%84%E5%85%A8%E8%BF%87%E7%A8%8B/ - Hyperledger fabric : 单机多节点kafka模式的数据持久化:
https://www.wandouip.com/t5i98262/ - willaty的博客园博文 fabric持久化
https://www.cnblogs.com/willaty/p/10077531.html - Hyperledger Fabric 1.0 实例简析 第一课 network_setup.sh分析
https://blog.csdn.net/tiandiwuya/article/details/79471094
准备工作
按照触不可及的深入理解一篇,熟练通过改变环境变量手动搭建成功Fabric网络
解释
首先介绍四篇参考文章分别的作用。第一篇是具体操作命令,包括生成通道配置信息、创建通道等;第二篇是数据持久化的具体步骤;第三篇是实现持久化需要在docker-compose.yaml中添加的不同角色对应的具体参数;第四篇是解释第二篇中脚本文件具体干了什么。
根据第二篇文章的具体操作来实现持久化。其中generateArtifacts.sh和script.sh具体操作的内容可以通过第四篇文章来得到解释,并且根据触不可及一文中的操作命令可以手动实现。
实现过程
1. 正常配置区块链网络
首先正常启动区块链网络。
若generateArtifacts.sh没有或不可用,则手动搭建网络。这里引用触不可及中的前部分内容。
生成证书
#路径需要更改为自己的路径
cd ~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/
#在这里可能会报错,通常是权限问题,可以添加sudo重新执行
cryptogen generate --config=./crypto-config.yaml
#执行完毕后,当前文件夹下会出现一个新的文件夹:crypto-config,在该文件夹下就是刚刚生成的证书.
生成创世区块
#执行命令生成创世区块
configtxgen -profile TwoOrgsOrdererGenesis -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block
#如果没有channel-artifacts这个文件夹,则需要手动去创建
生成通道配置信息
#执行命令生成通道配置信息
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
生成锚节点配置文件
#首先生成Org1的锚节点配置文件
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
#生成Org2的锚节点配置文件
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
所有需要的配置文件全部建立完成,在channel-artifacts中应该有以下几个文件:
channel.tx genesis.block Org1MSPanchors.tx Org2MSPanchors.tx
2. 更改docker-compose配置文件(暂时未配置couchdb)
在1.4.4版本的fabric-example的first-network中,可以看到docker-compose-cli.yaml下的配置继承了base目录下的docker-compose.yaml文件
extends:
file: base/docker-compose-base.yaml
在base目录下的docker-compose.yaml中,在volume的最后增加参数使得docker挂载到本地目录(本地目录必须创建,具体对应参考第三篇博客园的文章)
我的配置文件如下,仅供参考
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
version: '2'
services:
orderer.example.com:
container_name: orderer.example.com
extends:
file: peer-base.yaml
service: orderer-base
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/tls
- orderer.example.com:/var/hyperledger/production/orderer
ports:
- 7050:7050
peer0.org1.example.com:
container_name: peer0.org1.example.com
extends:
file: peer-base.yaml
service: peer-base
environment:
- CORE_PEER_ID=peer0.org1.example.com
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051
- CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org1.example.com:8051
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
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
- peer0.org1.example.com:/var/hyperledger/production
ports:
- 7051:7051
peer1.org1.example.com:
container_name: peer1.org1.example.com
extends:
file: peer-base.yaml
service: peer-base
environment:
- CORE_PEER_ID=peer1.org1.example.com
- CORE_PEER_ADDRESS=peer1.org1.example.com:8051
- CORE_PEER_LISTENADDRESS=0.0.0.0:8051
- CORE_PEER_CHAINCODEADDRESS=peer1.org1.example.com:8052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:8052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:8051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
volumes:
- /var/run/:/host/var/run/
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls
- peer1.org1.example.com:/var/hyperledger/production
ports:
- 8051:8051
peer0.org2.example.com:
container_name: peer0.org2.example.com
extends:
file: peer-base.yaml
service: peer-base
environment:
- CORE_PEER_ID=peer0.org2.example.com
- CORE_PEER_ADDRESS=peer0.org2.example.com:9051
- CORE_PEER_LISTENADDRESS=0.0.0.0:9051
- CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:9052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:9052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:9051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org2.example.com:10051
- CORE_PEER_LOCALMSPID=Org2MSP
volumes:
- /var/run/:/host/var/run/
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls
- peer0.org2.example.com:/var/hyperledger/production
ports:
- 9051:9051
peer1.org2.example.com:
container_name: peer1.org2.example.com
extends:
file: peer-base.yaml
service: peer-base
environment:
- CORE_PEER_ID=peer1.org2.example.com
- CORE_PEER_ADDRESS=peer1.org2.example.com:10051
- CORE_PEER_LISTENADDRESS=0.0.0.0:10051
- CORE_PEER_CHAINCODEADDRESS=peer1.org2.example.com:10052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:10052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.example.com:10051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:9051
- CORE_PEER_LOCALMSPID=Org2MSP
volumes:
- /var/run/:/host/var/run/
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/msp:/etc/hyperledger/fabric/msp
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls:/etc/hyperledger/fabric/tls
- peer1.org2.example.com:/var/hyperledger/production
ports:
- 10051:10051
3. 启动网络并验证持久化
继续按照第二篇文章中的步骤。
- 启动网络
sudo docker-compose -f docker-compose-cli.yaml up -d
- 进入cli容器
sudo docker exec -it cli bash
- 创建mychannel通道并加入,安装链码及实例化
# 此步骤也可按照深入理解一篇手动更改环境变量操作
./scripts/script.sh mychannel
- 执行invoke、query操作
# query
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
# invoke
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}'
- tree命令查看/var/hyperledger文件,确实有备份的容器数据
.
├── orderer
│ └── orderer
├── peer0
│ ├── org1
│ │ ├── chaincodes
│ │ │ └── mycc.1.0
│ │ ├── ledgersData
│ │ │ ├── bookkeeper
│ │ │ │ ├── 000002.log
│ │ │ │ ├── CURRENT
│ │ │ │ ├── CURRENT.bak
│ │ │ │ ├── LOCK
│ │ │ │ ├── LOG
│ │ │ │ └── MANIFEST-000003
│ │ │ ├── chains
│ │ │ │ ├── chains
│ │ │ │ │ └── mychannel
│ │ │ │ │ └── blockfile_000000
│ │ │ │ └── index
│ │ │ │ ├── 000002.ldb
│ │ │ │ ├── 000003.log
│ │ │ │ ├── CURRENT
│ │ │ │ ├── CURRENT.bak
│ │ │ │ ├── LOCK
│ │ │ │ ├── LOG
│ │ │ │ └── MANIFEST-000004
│ │ │ ├── configHistory
│ │ │ │ ├── 000002.log
│ │ │ │ ├── CURRENT
│ │ │ │ ├── CURRENT.bak
│ │ │ │ ├── LOCK
│ │ │ │ ├── LOG
│ │ │ │ └── MANIFEST-000003
│ │ │ ├── fileLock
│ │ │ │ ├── 000002.log
│ │ │ │ ├── CURRENT
│ │ │ │ ├── CURRENT.bak
│ │ │ │ ├── LOCK
│ │ │ │ ├── LOG
│ │ │ │ └── MANIFEST-000003
│ │ │ ├── historyLeveldb
│ │ │ │ ├── 000002.ldb
│ │ │ │ ├── 000003.log
│ │ │ │ ├── CURRENT
│ │ │ │ ├── CURRENT.bak
│ │ │ │ ├── LOCK
│ │ │ │ ├── LOG
│ │ │ │ └── MANIFEST-000004
│ │ │ ├── ledgerProvider
│ │ │ │ ├── 000002.ldb
│ │ │ │ ├── 000003.log
│ │ │ │ ├── CURRENT
│ │ │ │ ├── CURRENT.bak
│ │ │ │ ├── LOCK
│ │ │ │ ├── LOG
│ │ │ │ └── MANIFEST-000004
│ │ │ ├── pvtdataStore
│ │ │ │ ├── 000002.ldb
│ │ │ │ ├── 000003.log
│ │ │ │ ├── CURRENT
│ │ │ │ ├── CURRENT.bak
│ │ │ │ ├── LOCK
│ │ │ │ ├── LOG
│ │ │ │ └── MANIFEST-000004
│ │ │ └── stateLeveldb
│ │ │ ├── 000002.ldb
│ │ │ ├── 000003.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000004
│ │ └── transientStore
│ │ ├── 000002.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000003
│ └── org2
│ ├── chaincodes
│ │ └── mycc.1.0
│ ├── ledgersData
│ │ ├── bookkeeper
│ │ │ ├── 000002.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000003
│ │ ├── chains
│ │ │ ├── chains
│ │ │ │ └── mychannel
│ │ │ │ └── blockfile_000000
│ │ │ └── index
│ │ │ ├── 000002.ldb
│ │ │ ├── 000003.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000004
│ │ ├── configHistory
│ │ │ ├── 000002.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000003
│ │ ├── fileLock
│ │ │ ├── 000002.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000003
│ │ ├── historyLeveldb
│ │ │ ├── 000002.ldb
│ │ │ ├── 000003.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000004
│ │ ├── ledgerProvider
│ │ │ ├── 000002.ldb
│ │ │ ├── 000003.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000004
│ │ ├── pvtdataStore
│ │ │ ├── 000002.ldb
│ │ │ ├── 000003.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000004
│ │ └── stateLeveldb
│ │ ├── 000002.ldb
│ │ ├── 000003.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000004
│ └── transientStore
│ ├── 000002.log
│ ├── CURRENT
│ ├── CURRENT.bak
│ ├── LOCK
│ ├── LOG
│ └── MANIFEST-000003
└── peer1
├── org1
│ ├── chaincodes
│ ├── ledgersData
│ │ ├── bookkeeper
│ │ │ ├── 000002.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000003
│ │ ├── chains
│ │ │ ├── chains
│ │ │ │ └── mychannel
│ │ │ │ └── blockfile_000000
│ │ │ └── index
│ │ │ ├── 000002.ldb
│ │ │ ├── 000003.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000004
│ │ ├── configHistory
│ │ │ ├── 000002.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000003
│ │ ├── fileLock
│ │ │ ├── 000002.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000003
│ │ ├── historyLeveldb
│ │ │ ├── 000002.ldb
│ │ │ ├── 000003.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000004
│ │ ├── ledgerProvider
│ │ │ ├── 000002.ldb
│ │ │ ├── 000003.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000004
│ │ ├── pvtdataStore
│ │ │ ├── 000002.ldb
│ │ │ ├── 000003.log
│ │ │ ├── CURRENT
│ │ │ ├── CURRENT.bak
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000004
│ │ └── stateLeveldb
│ │ ├── 000002.ldb
│ │ ├── 000003.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000004
│ └── transientStore
│ ├── 000002.log
│ ├── CURRENT
│ ├── CURRENT.bak
│ ├── LOCK
│ ├── LOG
│ └── MANIFEST-000003
└── org2
├── chaincodes
│ └── mycc.1.0
├── ledgersData
│ ├── bookkeeper
│ │ ├── 000002.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000003
│ ├── chains
│ │ ├── chains
│ │ │ └── mychannel
│ │ │ └── blockfile_000000
│ │ └── index
│ │ ├── 000002.ldb
│ │ ├── 000003.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000004
│ ├── configHistory
│ │ ├── 000002.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000003
│ ├── fileLock
│ │ ├── 000002.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000003
│ ├── historyLeveldb
│ │ ├── 000002.ldb
│ │ ├── 000003.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000004
│ ├── ledgerProvider
│ │ ├── 000002.ldb
│ │ ├── 000003.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000004
│ ├── pvtdataStore
│ │ ├── 000002.ldb
│ │ ├── 000003.log
│ │ ├── CURRENT
│ │ ├── CURRENT.bak
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000004
│ └── stateLeveldb
│ ├── 000002.ldb
│ ├── 000003.log
│ ├── CURRENT
│ ├── CURRENT.bak
│ ├── LOCK
│ ├── LOG
│ └── MANIFEST-000004
└── transientStore
├── 000002.log
├── CURRENT
├── CURRENT.bak
├── LOCK
├── LOG
└── MANIFEST-000003
- 关闭docker容器
sudo docker rm -f $(sudo docker ps -aq)
# 注意: 不需要把channel-artifacts和crypto-config两个文件也删掉
- 重启docker后进入容器,直接进行invoke,query操作,发现可行,并且仍是继续上次的数据。也就是跳过了链码安装、部署、实例化等等操作,即测试完成。