In the process of manually creating a fabric custom network, I encountered a lot of BUG, most of which were configuration items in the configuration file, and finally solved all of them and successfully created the network. Take this opportunity to record the detailed process of creating a network and the configuration of related configuration files for your reference and mutual learning.
My version:
ubuntu 20.04
fabric 2.3.3
docker 20.10.12
docker-compose 2.11.2
1. Copy the binary commands under the bin under fabric-samples to /usr/local/bin for global calling
2. Create a directory for storing configuration files
I put test-network in the root directory.
cd /
mkdir test-network
cd test-network
3. Generate organization configuration file crypto-config.yaml
Call command: cryptogen showtemplate > crypto-config.yaml
Contents in crypto-config.yaml:
# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
- Name: Orderer # orderer组织的名称
Domain: example.com # orderer组织的根域名
EnableNodeOUs: true # 是否使用组织单元
Specs:
- Hostname: orderer # 可以通过hostname设置多个orderer节点
# Hostname + Domain组成该orderer节点的完整域名
PeerOrgs: # 一个PeerOrgs设置多个peer组织
- Name: Org1 # peer组织的名称
Domain: org1.example.com # peer组织的域名
EnableNodeOUs: true
Template: # 节点的数量(peer0, peer1, .....)
Count: 1
Users: # 用户的数量
Count: 1
- Name: Org2
Domain: org2.example.com
EnableNodeOUs: true
Template:
Count: 1
Users:
Count: 1
4. Generate key
Call command: cryptogen generate --config=crypto-config.yaml
5. Create a network configuration file configtx.yaml
Organizations:
- &OrdererOrg
Name: OrdererOrg
ID: OrdererMSP
MSPDir: ./crypto-config/ordererOrganizations/example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Writers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Admins:
Type: Signature
Rule: "OR('OrdererMSP.admin')"
OrdererEndpoints:
- orderer.example.com:7050
- &Org1
Name: Org1MSP
ID: Org1MSP
MSPDir: ./crypto-config/peerOrganizations/org1.example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org1MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Org1MSP.peer')"
AnchorPeers:
- Host: peer0.org1.example.com
Port: 7051
- &Org2
Name: Org2MSP
ID: Org2MSP
MSPDir: ./crypto-config/peerOrganizations/org2.example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org2MSP.admin', 'Org2MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org2MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Org2MSP.peer')"
AnchorPeers:
- Host: peer0.org2.example.com
Port: 8051
Capabilities:
Channel: &ChannelCapabilities
V2_0: true
Orderer: &OrdererCapabilities
V2_0: true
Application: &ApplicationCapabilities
V2_0: true
Application: &ApplicationDefaults
Organizations:
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
LifecycleEndorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Endorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Capabilities:
<<: *ApplicationCapabilities
Orderer: &OrdererDefaults
OrdererType: etcdraft
Addresses: # orderer 集群节点
- orderer.example.com:7050
EtcdRaft:
Consenters:
- Host: orderer.example.com
Port: 7050
ClientTLSCert: ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
ServerTLSCert: ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
BatchTimeout: 2s # 生成区块超时时间
# Batch Size: Controls the number of messages batched into a block
BatchSize:
MaxMessageCount: 10 # 区块的消息数量
AbsoluteMaxBytes: 99 MB # 区块最大字节数
PreferredMaxBytes: 512 KB # 建议消息字节数
Organizations:
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
BlockValidation:
Type: ImplicitMeta
Rule: "ANY Writers"
Channel: &ChannelDefaults
Policies:
# Who may invoke the 'Deliver' API
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
# Who may invoke the 'Broadcast' API
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
# By default, who may modify elements at this config level
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
Capabilities:
<<: *ChannelCapabilities
Profiles:
TwoOrgsChannel:
Consortium: SampleConsortium
<<: *ChannelDefaults
Application:
<<: *ApplicationDefaults
Organizations:
- *Org1
- *Org2
Capabilities:
<<: *ApplicationCapabilities
TwoOrgsOrdererGenesis:
<<: *ChannelDefaults
Capabilities:
<<: *ChannelCapabilities
Orderer:
<<: *OrdererDefaults
Organizations:
- *OrdererOrg
Capabilities:
<<: *OrdererCapabilities
Consortiums:
SampleConsortium:
Organizations:
- *Org1
- *Org2
6. Generate the genesis block file (channelID specifies the system channel name)
configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block -channelID test-channel
7. Generate a channel file (channelID specifies the application channel name)
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
(The channelID of step6 and step7 cannot be the same!)
8. Generate anchor nodes for org1 and org2
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
9. Write docker-compose file
The cli container specifies the represented Peer node through the environment variable CORE_PEER_ADDRESS.
version: '2'
volumes:
orderer.example.com:
peer0.org1.example.com:
peer0.org2.example.com:
networks:
test:
name: fabric_test
services:
orderer.example.com:
container_name: orderer.example.com
image: hyperledger/fabric-orderer:latest
environment:
- FABRIC_LOGGING_SPEC=INFO
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 #监听的IP
- ORDERER_GENERAL_LISTENPORT=7050 #监听的端口
- ORDERER_GENERAL_GENESISMETHOD=file #创世块的来源方式
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block #创世文件的路径
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP #MSPID
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp #容器中msp的路径
- ORDERER_OPERATIONS_LISTENADDRESS=0.0.0.0:17050
- 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]
- ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: orderer
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
- 17050:17050
networks:
- test
peer0.org1.example.com:
container_name: peer0.org1.example.com
image: hyperledger/fabric-peer:latest
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_test
- CORE_PEER_ID=peer0.org1.example.com
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051 #服务的IP端口
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051 #本地监听的IP端口
- CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052 #链码的IP端口
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 #链码监听的端口
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051 #向哪个节点发起gossip连接
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_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
- CORE_CHAINCODE_EXECUTETIMEOUT=300s
- CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:17051
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
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
- 7052:7052
- 17051:17051
networks:
- test
peer0.org2.example.com:
container_name: peer0.org2.example.com
image: hyperledger/fabric-peer:latest
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_test
- CORE_PEER_ID=peer0.org2.example.com
- CORE_PEER_ADDRESS=peer0.org2.example.com:8051
- CORE_PEER_LISTENADDRESS=0.0.0.0:8051
- CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:8052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:8052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:8051
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:8051
- CORE_PEER_LOCALMSPID=Org2MSP
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_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
- CORE_CHAINCODE_EXECUTETIMEOUT=300s
- CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:18051
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
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:
- 8051:8051
- 8052:8052
- 18051:18051
networks:
- test
cli1:
container_name: cli1
image: hyperledger/fabric-tools:latest
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_ID=cli1
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/multiple-deployment/chaincode/go #用于映射本地链码的路径
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- peer0.org1.example.com
- peer0.org2.example.com
- orderer.example.com
networks:
- test
cli2:
container_name: cli2
image: hyperledger/fabric-tools:latest
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_ID=cli2
- CORE_PEER_ADDRESS=peer0.org2.example.com:8051
- CORE_PEER_LOCALMSPID=Org2MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key
- 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
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/multiple-deployment/chaincode/go #映射本地链码路径
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- peer0.org1.example.com
- peer0.org2.example.com
- orderer.example.com
networks:
- test
10. Orchestrating containers
docker-compose up -d
Here, each cli points to an organization, and the cli points to the node of the specific organization through the setting of the environment variable, and the node of the organization can be operated by operating the cli container.
11. Enter the container cli1 and create a channel
docker exec -it cli1 bash
peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem
-o orderer
-c channel name
-f path to channel file
It is found that mychannel.block is generated in the current directory
12. Exit cli1, copy mychannel.block from cli1 to cli2
docker cp cli1:/opt/gopath/src/github.com/hyperledger/fabric/peer/mychannel.block ./
docker cp ./mychannel.block cli2:/opt/gopath/src/github.com/hyperledger/fabric/peer
13. Open two terminals and enter cli1 and cli2 respectively
docker exec -it cli1 bash
docker exec -it cli2 bash
14. Join the channel (both cli needs to be operated)
peer channel join -b mychannel.block
15. Update the anchor nodes of org1 and org2
In cli1:
peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric /peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
In cli2:
peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric /peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
16. Use fabric-samples/chaincode/sacc for chaincode testing
cp -r /myFabric/fabric-samples/chaincode/sacc /test-network/chaincode/go
do you remember? In docker-compose, /test-network/chaincode/go implements container volume mapping with the directory in the container. We copy the chaincode to this directory, so that there is a corresponding chaincode in the container.
Enter cli1:
set goproxy proxy: go env -w GOPROXY=https://goproxy.cn,direct
Switch to the sacc directory:
cd /opt/gopath/src/github.com/hyperledger/multiple-deployment/chaincode/go/sacc
Download dependencies:
go mod vendor
Return to the working directory:
cd /opt/gopath/src/github.com/hyperledger/fabric/peer
17. Packaging chain code (both clis are required)
We can package it in cli1 first, and then use docker cp to other clis.
First package the chaincode in cli1:
peer lifecycle chaincode package sacc.tar.gz --path /opt/gopath/src/github.com/hyperledger/multiple-deployment/chaincode/go/sacc --label sacc_1.0
Then exit cli1 and copy the chaincode packaged in cli1 to cli2:
docker cp cli1:/opt/gopath/src/github.com/hyperledger/fabric/peer/sacc.tar.gz ./
docker cp ./sacc.tar.gz cli2:/opt/gopath/src/github.com/hyperledger/fabric/peer
18. Install the chain code (both clis are required)
peer lifecycle chaincode install sacc.tar.gz
19. Approval chain code (required for both cli)
Use the command peer lifecycle chaincode queryinstalled to view the package ID, which will be used later:
Package ID: sacc_1.0:5562f868f6fd43ff8873f403aa52bc6928161fec933065d0b81e2193f6038bd0, Label: sacc_1.0
After getting the package ID, approve the chaincode:
peer lifecycle chaincode approveformyorg --channelID mychannel --name sacc --version 1.0 --init-required –package-id sacc_1.0:5562f868f6fd43ff8873f403aa52bc6928161fec933065d0b81e2193f6038bd0 --sequence 1 --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
Check whether the approval is successful:
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name sacc --version 1.0 --init-required --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger /fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com
20. Submit the chain code (execute in cli1)
peer lifecycle chaincode commit -o orderer.example.com:7050 --channelID mychannel --name sacc --version 1.0 --init-required --sequence 1 --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 --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:8051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
21. Test chaincode function
peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n sacc --isInit --ordererTLSHostnameOverride orderer.example.com --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric /peer/crypto/ordersOrganizations/example.com/orderers/orders.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --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: . 8051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{; “Args”:[“a”,“bb”]}'
peer chaincode query -C mychannel -n sacc -c ‘{“Args”:[“query”,“a”]}’
S u c c e s s f u l ! Successful! Successful!