Module 4: Network Deployment and Management
4.3 Network Deployment
After configuring your Hyperledger Fabric network, the next step is to deploy it. This section covers the deployment process, from starting the network to creating channels and deploying chaincode.
Starting the Network
The first step in deploying a Hyperledger Fabric network is to start the containers defined in your Docker Compose files.
Starting the Certificate Authorities
If you're using Fabric CA for a production environment, start the CA containers first:
# Create directories for CA
mkdir -p fabric-ca/org1 fabric-ca/org2 fabric-ca/orderer
# Start the CA containers
docker-compose -f docker-compose-ca.yaml up -d
Generating Cryptographic Material with Fabric CA
Once the CA containers are running, you can generate the cryptographic material:
# Register and enroll the orderer organization admin
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/ordererOrganizations/example.com/
fabric-ca-client enroll -u https://admin:adminpw@localhost:9054 --caname ca.orderer.example.com --tls.certfiles ${PWD}/organizations/fabric-ca/orderer/tls-cert.pem
# Register and enroll orderer nodes
fabric-ca-client register --caname ca.orderer.example.com --id.name orderer --id.secret ordererpw --id.type orderer --tls.certfiles ${PWD}/organizations/fabric-ca/orderer/tls-cert.pem
fabric-ca-client enroll -u https://orderer:ordererpw@localhost:9054 --caname ca.orderer.example.com -M ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp --csr.hosts orderer.example.com --tls.certfiles ${PWD}/organizations/fabric-ca/orderer/tls-cert.pem
# Register and enroll the peer organization admin
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/
fabric-ca-client enroll -u https://admin:adminpw@localhost:7054 --caname ca.org1.example.com --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
# Register and enroll peer nodes
fabric-ca-client register --caname ca.org1.example.com --id.name peer0 --id.secret peer0pw --id.type peer --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
fabric-ca-client enroll -u https://peer0:peer0pw@localhost:7054 --caname ca.org1.example.com -M ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp --csr.hosts peer0.org1.example.com --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem
# Repeat for other organizations and peers
Starting the Orderers and Peers
Once the cryptographic material is generated, start the orderer and peer containers:
# Start the network
docker-compose -f docker-compose.yaml up -d
Verifying Network Startup
Verify that all containers are running correctly:
# Check container status
docker ps
# Check container logs
docker logs orderer.example.com
docker logs peer0.org1.example.com
Creating and Joining Channels
After the network is up and running, the next step is to create channels and have peers join them.
Creating a Channel
Use the CLI container to create a channel:
# Enter the CLI container
docker exec -it cli bash
# Set environment variables
export CHANNEL_NAME=channel1
export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
# Create the channel
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/channel1.tx --tls --cafile $ORDERER_CA
Joining Peers to the Channel
Have each peer join the channel:
# Join peer0.org1 to the channel
peer channel join -b channel1.block
# Switch to peer0.org2
export CORE_PEER_LOCALMSPID="Org2MSP"
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:9051
# Join peer0.org2 to the channel
peer channel join -b channel1.block
Updating Anchor Peers
Update the channel configuration to define anchor peers:
# Switch back to peer0.org1
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
# Update anchor peers for Org1
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org1MSPanchors.tx --tls --cafile $ORDERER_CA
# Switch to peer0.org2
export CORE_PEER_LOCALMSPID="Org2MSP"
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:9051
# Update anchor peers for Org2
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org2MSPanchors.tx --tls --cafile $ORDERER_CA
Deploying Chaincode
The final step in network deployment is to deploy chaincode to the channel.
Packaging Chaincode
Package the chaincode using the peer lifecycle commands:
# Create a chaincode package
peer lifecycle chaincode package mycc.tar.gz --path /opt/gopath/src/github.com/chaincode/mycc/ --lang golang --label mycc_1.0
Installing Chaincode on Peers
Install the chaincode package on each peer:
# Install on peer0.org1
peer lifecycle chaincode install mycc.tar.gz
# Get the package ID
peer lifecycle chaincode queryinstalled
# Set the package ID as an environment variable
export CC_PACKAGE_ID=mycc_1.0:hash
# Switch to peer0.org2
export CORE_PEER_LOCALMSPID="Org2MSP"
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:9051
# Install on peer0.org2
peer lifecycle chaincode install mycc.tar.gz
Approving Chaincode Definition
Each organization must approve the chaincode definition:
# Approve for Org1
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name mycc --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1
# Approve for Org2
export CORE_PEER_LOCALMSPID="Org2MSP"
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:9051
peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name mycc --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1
Committing Chaincode Definition
Once enough organizations have approved, commit the chaincode definition to the channel:
peer lifecycle chaincode commit -o orderer.example.com:7050 --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name mycc --version 1.0 --sequence 1 --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
Invoking Chaincode
Initialize the chaincode and test it with an invoke transaction:
# Initialize the chaincode (if needed)
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -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 '{"function":"InitLedger","Args":[]}'
# Invoke a transaction
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -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 '{"function":"CreateAsset","Args":["asset1", "blue", "5", "tom", "100"]}'
# Query the ledger
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"function":"ReadAsset","Args":["asset1"]}'
Deployment Automation
For production environments, it's recommended to automate the deployment process using scripts or tools.
Deployment Scripts
Create shell scripts to automate the deployment process:
#!/bin/bash
# network.sh - Script to deploy a Hyperledger Fabric network
# Function to generate crypto material
function generateCrypto() {
echo "Generating crypto material..."
cryptogen generate --config=./crypto-config.yaml --output=./crypto-config
}
# Function to generate genesis block and channel transactions
function generateGenesisBlock() {
echo "Generating genesis block..."
configtxgen -profile TwoOrgsOrdererGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block
echo "Generating channel transaction..."
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel1.tx -channelID channel1
echo "Generating anchor peer updates..."
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID channel1 -asOrg Org1MSP
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID channel1 -asOrg Org2MSP
}
# Function to start the network
function networkUp() {
echo "Starting the network..."
docker-compose -f docker-compose.yaml up -d
}
# Function to create and join channel
function createChannel() {
echo "Creating channel..."
docker exec cli peer channel create -o orderer.example.com:7050 -c channel1 -f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/channel1.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
echo "Joining peer0.org1 to channel..."
docker exec cli peer channel join -b channel1.block
echo "Joining peer0.org2 to channel..."
docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e 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 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 cli peer channel join -b channel1.block
echo "Updating anchor peers..."
docker exec cli peer channel update -o orderer.example.com:7050 -c channel1 -f /opt/gopath/src/github.com/hyperledger/fabric/peer/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
docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e 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 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 cli peer channel update -o orderer.example.com:7050 -c channel1 -f /opt/gopath/src/github.com/hyperledger/fabric/peer/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
}
# Function to deploy chaincode
function deployChaincode() {
echo "Packaging chaincode..."
docker exec cli peer lifecycle chaincode package mycc.tar.gz --path /opt/gopath/src/github.com/chaincode/mycc/ --lang golang --label mycc_1.0
echo "Installing chaincode on peer0.org1..."
docker exec cli peer lifecycle chaincode install mycc.tar.gz
echo "Installing chaincode on peer0.org2..."
docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e 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 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 cli peer lifecycle chaincode install mycc.tar.gz
echo "Getting package ID..."
CC_PACKAGE_ID=$(docker exec cli peer lifecycle chaincode queryinstalled | grep mycc_1.0 | awk '{print $3}' | sed 's/,//')
echo "Approving chaincode for Org1..."
docker exec cli peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --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 --channelID channel1 --name mycc --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1
echo "Approving chaincode for Org2..."
docker exec -e CORE_PEER_LOCALMSPID=Org2MSP -e 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 -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 cli peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --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 --channelID channel1 --name mycc --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1
echo "Committing chaincode definition..."
docker exec cli peer lifecycle chaincode commit -o orderer.example.com:7050 --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 --channelID channel1 --name mycc --version 1.0 --sequence 1 --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
echo "Initializing chaincode..."
docker exec cli peer chaincode invoke -o orderer.example.com:7050 --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 -C channel1 -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 '{"function":"InitLedger","Args":[]}'
}
# Function to stop the network
function networkDown() {
echo "Stopping the network..."
docker-compose -f docker-compose.yaml down --volumes --remove-orphans
}
# Main script logic
case "$1" in
"up")
generateCrypto
generateGenesisBlock
networkUp
createChannel
deployChaincode
;;
"down")
networkDown
;;
*)
echo "Usage: $0 [up|down]"
;;
esac
Using Ansible for Deployment
For more complex deployments, consider using Ansible:
# playbook.yml
---
- name: Deploy Hyperledger Fabric Network
hosts: fabric_nodes
become: yes
tasks:
- name: Install prerequisites
apt:
name:
- docker.io
- docker-compose
- golang-go
- git
state: present
update_cache: yes
- name: Create fabric directory
file:
path: /opt/fabric
state: directory
mode: '0755'
- name: Copy configuration files
copy:
src: "{{ item }}"
dest: /opt/fabric/
with_items:
- crypto-config.yaml
- configtx.yaml
- docker-compose.yaml
- name: Download Fabric binaries
shell: |
cd /opt/fabric
curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.5.0 1.5.5
args:
creates: /opt/fabric/bin/peer
- name: Generate crypto material
shell: |
cd /opt/fabric
./bin/cryptogen generate --config=./crypto-config.yaml --output=./crypto-config
args:
creates: /opt/fabric/crypto-config
- name: Generate genesis block
shell: |
cd /opt/fabric
export FABRIC_CFG_PATH=/opt/fabric
./bin/configtxgen -profile TwoOrgsOrdererGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block
args:
creates: /opt/fabric/system-genesis-block/genesis.block
- name: Start the network
shell: |
cd /opt/fabric
docker-compose -f docker-compose.yaml up -d
args:
creates: /var/lib/docker/volumes/fabric_orderer.example.com
Deployment Considerations for Production
When deploying a Hyperledger Fabric network in production, consider the following:
High Availability
- Deploy multiple orderer nodes with Raft consensus
- Use load balancers for client connections
- Implement peer redundancy across organizations
- Set up database replication for CouchDB
- Use container orchestration platforms like Kubernetes
Security
- Use Hardware Security Modules (HSMs) for key management
- Implement network segmentation and firewalls
- Enable TLS for all communications
- Regularly rotate TLS certificates
- Implement proper access control with MSPs
- Use private data collections for sensitive information
Monitoring and Logging
- Set up centralized logging with ELK stack or similar
- Implement metrics collection with Prometheus
- Create dashboards with Grafana
- Set up alerts for critical issues
- Monitor resource usage and performance
Backup and Recovery
- Regularly backup cryptographic material
- Create snapshots of the ledger
- Document recovery procedures
- Test recovery processes
- Implement disaster recovery plans
Scalability
- Design for horizontal scaling
- Optimize batch size and timeout for transaction throughput
- Use appropriate hardware for orderers and peers
- Implement proper caching strategies
- Consider channel design for data isolation
By following these deployment guidelines, you can create a robust, secure, and scalable Hyperledger Fabric network that meets your production requirements. In the next section, we'll explore how to manage and maintain this network over time.