{"id":18301801,"url":"https://github.com/kfsoftware/meetup-hlf-3-0","last_synced_at":"2025-07-14T17:40:20.682Z","repository":{"id":221200930,"uuid":"744998852","full_name":"kfsoftware/meetup-hlf-3-0","owner":"kfsoftware","description":"Instructions to run Hyperledger Fabric 3.0 on Kubernetes in 2024","archived":false,"fork":false,"pushed_at":"2024-02-07T11:30:07.000Z","size":7,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-15T04:18:48.489Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kfsoftware.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-01-18T12:44:44.000Z","updated_at":"2024-05-23T11:52:07.000Z","dependencies_parsed_at":"2024-02-06T18:44:33.512Z","dependency_job_id":null,"html_url":"https://github.com/kfsoftware/meetup-hlf-3-0","commit_stats":null,"previous_names":["kfsoftware/meetup-hlf-3-0"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kfsoftware%2Fmeetup-hlf-3-0","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kfsoftware%2Fmeetup-hlf-3-0/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kfsoftware%2Fmeetup-hlf-3-0/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kfsoftware%2Fmeetup-hlf-3-0/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kfsoftware","download_url":"https://codeload.github.com/kfsoftware/meetup-hlf-3-0/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248017976,"owners_count":21034042,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T15:17:01.130Z","updated_at":"2025-04-09T09:46:41.859Z","avatar_url":"https://github.com/kfsoftware.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Workshop to create your first HLF network\n\nThis workshop is divided in this steps:\n\n1. [Create kubernetes cluster](#1-create-kubernetes-cluster)\n2. [Install and configure Istio](#2-install-and-configure-istio)\n3. [Install Hyperledger Fabric operator](#3-install-hyperledger-fabric-operator)\n4. [Deploy a peer organization](#4-deploy-a-peer-organization)\n5. [Deploy an orderer organization](#5-deploy-an-orderer-organization)\n6. [Create a channel](#6-create-a-channel)\n7. [Join peer to the channel](#7-join-peer-to-the-channel)\n8. [Install a chaincode](#8-install-a-chaincode)\n9. [Deploy chaincode container on cluster](#9-deploy-chaincode-container-on-cluster)\n10. [Approve chaincode](#10-approve-chaincode)\n11. [Commit chaincode](#11-commit-chaincode)\n12. [Invoke a transaction on the channel](#12-invoke-a-transaction-on-the-channel)\n13. [Query assets in the channel](#13-query-assets-in-the-channel)\n14. [Completion](#14-completion)\n\nIn order to follow the workshop, you have two options, follow the Loom video or follow the steps below.\n\nRun through the steps explaining what we are going to do and how to do it.\n\n## 1. Create kubernetes cluster\n\nTo start deploying our red fabric we have to have a Kubernetes cluster. For this we will use KinD.\n\nEnsure you have these ports available before creating the cluster:\n\n-   80\n-   443\n\nIf these ports are not available this tutorial will not work.\n\n### Using K3D\n\n```bash\nk3d cluster create  -p \"80:30949@agent:0\" -p \"443:30950@agent:0\" --agents 2 k8s-hlf\n```\n\n### Using KinD\n\n```bash\ncat \u003c\u003c EOF \u003e kind-config.yaml\nkind: Cluster\napiVersion: kind.x-k8s.io/v1alpha4\nnodes:\n- role: control-plane\n  image: kindest/node:v1.27.3\n  extraPortMappings:\n  - containerPort: 30949\n    hostPort: 80\n  - containerPort: 30950\n    hostPort: 443\nEOF\n\nkind create cluster --config=./kind-config.yaml\n\n```\n\n## 2. Install and configure Istio\n\nInstall Istio binaries on the machine:\n\n```bash\n# add TARGET_ARCH=x86_64 if you are using arm64\ncurl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.20.0 sh -\nexport PATH=\"$PATH:$PWD/istio-1.20.0/bin\"\n```\n\nInstall Istio on the Kubernetes cluster:\n\n```bash\n\nkubectl create namespace istio-system\n\nistioctl operator init\n\nkubectl apply -f - \u003c\u003cEOF\napiVersion: install.istio.io/v1alpha1\nkind: IstioOperator\nmetadata:\n  name: istio-gateway\n  namespace: istio-system\nspec:\n  addonComponents:\n    grafana:\n      enabled: false\n    kiali:\n      enabled: false\n    prometheus:\n      enabled: false\n    tracing:\n      enabled: false\n  components:\n    ingressGateways:\n      - enabled: true\n        k8s:\n          hpaSpec:\n            minReplicas: 2\n          resources:\n            limits:\n              cpu: 500m\n              memory: 512Mi\n            requests:\n              cpu: 100m\n              memory: 128Mi\n          service:\n            ports:\n              - name: http\n                port: 80\n                targetPort: 8080\n                nodePort: 30949\n              - name: https\n                port: 443\n                targetPort: 8443\n                nodePort: 30950\n            type: NodePort\n        name: istio-ingressgateway\n    pilot:\n      enabled: true\n      k8s:\n        hpaSpec:\n          minReplicas: 1\n        resources:\n          limits:\n            cpu: 300m\n            memory: 512Mi\n          requests:\n            cpu: 100m\n            memory: 128Mi\n  meshConfig:\n    accessLogFile: /dev/stdout\n    enableTracing: false\n    outboundTrafficPolicy:\n      mode: ALLOW_ANY\n  profile: default\n\nEOF\n```\n\n### Configure Internal DNS\n\nThis needs to be applied every time you restart the machine.\n\n```bash\nkubectl apply -f - \u003c\u003cEOF\nkind: ConfigMap\napiVersion: v1\nmetadata:\n  name: coredns\n  namespace: kube-system\ndata:\n  Corefile: |\n    .:53 {\n        errors\n        health {\n           lameduck 5s\n        }\n        rewrite name regex (.*)\\.localho\\.st istio-ingressgateway.istio-system.svc.cluster.local\n        hosts {\n          fallthrough\n        }\n        ready\n        kubernetes cluster.local in-addr.arpa ip6.arpa {\n           pods insecure\n           fallthrough in-addr.arpa ip6.arpa\n           ttl 30\n        }\n        prometheus :9153\n        forward . /etc/resolv.conf {\n           max_concurrent 1000\n        }\n        cache 30\n        loop\n        reload\n        loadbalance\n    }\nEOF\n```\n\n## 3. Install Hyperledger Fabric operator\n\nIn this step we are going to install the kubernetes operator for Fabric, this will install:\n\n-   CRD (Custom Resource Definitions) to deploy Certification Fabric Peers, Orderers and Authorities\n-   Deploy the program to deploy the nodes in Kubernetes\n\nTo install helm: [https://helm.sh/docs/intro/install/](https://helm.sh/docs/intro/install/)\n\n```bash\nhelm repo add kfs https://kfsoftware.github.io/hlf-helm-charts --force-update\n\nhelm upgrade --install hlf-operator --version=1.11.0-beta3 -- kfs/hlf-operator\n\n```\n\n\n### Install the Kubectl plugin\n\nTo install the kubectl plugin, you must first install Krew:\n[https://krew.sigs.k8s.io/docs/user-guide/setup/install/](https://krew.sigs.k8s.io/docs/user-guide/setup/install/)\n\nAfterwards, the plugin can be installed with the following command:\n\n```bash\nkubectl krew install hlf\n```\n\n## 4. Deploy a peer organization\n\n### Environment Variables for AMD and ARM\n\n```bash\nexport PEER_IMAGE=hyperledger/fabric-peer\nexport PEER_VERSION=3.0.0-preview\n\nexport ORDERER_IMAGE=hyperledger/fabric-orderer\nexport ORDERER_VERSION=3.0.0-preview\n\nexport CA_IMAGE=hyperledger/fabric-ca\nexport CA_VERSION=1.5.7\n```\n\n### Deploy a certificate authority\n\n```bash\nexport STORAGE_CLASS=local-path # k3d storage class, \"standard\" for KinD\nkubectl hlf ca create  --image=$CA_IMAGE --version=$CA_VERSION --storage-class=$STORAGE_CLASS --capacity=1Gi --name=org1-ca \\\n    --enroll-id=enroll --enroll-pw=enrollpw --hosts=org1-ca.localho.st --istio-port=443\n\nkubectl wait --timeout=180s --for=condition=Running fabriccas.hlf.kungfusoftware.es --all\n```\n\nCheck that the certification authority is deployed and works:\n\n```bash\ncurl -k https://org1-ca.localho.st:443/cainfo\n```\n\nRegister a user in the certification authority of the peer organization (Org1MSP)\n\n```bash\n# register user in CA for peers\nkubectl hlf ca register --name=org1-ca --user=peer --secret=peerpw --type=peer \\\n --enroll-id enroll --enroll-secret=enrollpw --mspid Org1MSP\n\n```\n\n### Deploy a peer \n\n```bash\n\nkubectl hlf peer create --statedb=leveldb --image=$PEER_IMAGE --version=$PEER_VERSION --storage-class=$STORAGE_CLASS --enroll-id=peer --mspid=Org1MSP \\\n        --enroll-pw=peerpw --capacity=5Gi --name=org1-peer0 --ca-name=org1-ca.default \\\n        --hosts=peer0-org1.localho.st --istio-port=443\n\n\nkubectl hlf peer create --statedb=leveldb --image=$PEER_IMAGE --version=$PEER_VERSION --storage-class=$STORAGE_CLASS --enroll-id=peer --mspid=Org1MSP \\\n        --enroll-pw=peerpw --capacity=5Gi --name=org1-peer1 --ca-name=org1-ca.default \\\n        --hosts=peer1-org1.localho.st --istio-port=443\n\n\nkubectl wait --timeout=180s --for=condition=Running fabricpeers.hlf.kungfusoftware.es --all\n```\n\nCheck that the peer is deployed and works:\n\n```bash\nopenssl s_client -connect peer0-org1.localho.st:443\nopenssl s_client -connect peer1-org1.localho.st:443\n```\n\n## 5. Deploy an orderer organization\n\nTo deploy an `Orderer` organization we have to:\n\n1. Create a certification authority\n2. Register user `orderer` with password `ordererpw`\n3. Create orderer\n\n### Create the certification authority\n\n```bash\n\nkubectl hlf ca create  --image=$CA_IMAGE --version=$CA_VERSION --storage-class=$STORAGE_CLASS --capacity=1Gi --name=ord-ca \\\n    --enroll-id=enroll --enroll-pw=enrollpw --hosts=ord-ca.localho.st --istio-port=443\n\nkubectl wait --timeout=180s --for=condition=Running fabriccas.hlf.kungfusoftware.es --all\n\n```\n\nCheck that the certification authority is deployed and works:\n\n```bash\ncurl -vik https://ord-ca.localho.st:443/cainfo\n```\n\n### Register user `orderer`\n\n```bash\nkubectl hlf ca register --name=ord-ca --user=orderer --secret=ordererpw \\\n    --type=orderer --enroll-id enroll --enroll-secret=enrollpw --mspid=OrdererMSP --ca-url=\"https://ord-ca.localho.st:443\"\n\n```\n\n### Deploy orderer\n\n```bash\n\nkubectl hlf ordnode create --image=$ORDERER_IMAGE --version=$ORDERER_VERSION \\\n    --storage-class=$STORAGE_CLASS --enroll-id=orderer --mspid=OrdererMSP \\\n    --enroll-pw=ordererpw --capacity=2Gi --name=ord-node1 --ca-name=ord-ca.default \\\n    --hosts=orderer0-ord.localho.st --admin-hosts=admin-orderer0-ord.localho.st --istio-port=443\n\n\nkubectl hlf ordnode create --image=$ORDERER_IMAGE --version=$ORDERER_VERSION \\\n    --storage-class=$STORAGE_CLASS --enroll-id=orderer --mspid=OrdererMSP \\\n    --enroll-pw=ordererpw --capacity=2Gi --name=ord-node2 --ca-name=ord-ca.default \\\n    --hosts=orderer1-ord.localho.st --admin-hosts=admin-orderer1-ord.localho.st --istio-port=443\n\nkubectl hlf ordnode create --image=$ORDERER_IMAGE --version=$ORDERER_VERSION \\\n    --storage-class=$STORAGE_CLASS --enroll-id=orderer --mspid=OrdererMSP \\\n    --enroll-pw=ordererpw --capacity=2Gi --name=ord-node3 --ca-name=ord-ca.default \\\n    --hosts=orderer2-ord.localho.st --admin-hosts=admin-orderer2-ord.localho.st --istio-port=443\n\n\nkubectl hlf ordnode create --image=$ORDERER_IMAGE --version=$ORDERER_VERSION \\\n    --storage-class=$STORAGE_CLASS --enroll-id=orderer --mspid=OrdererMSP \\\n    --enroll-pw=ordererpw --capacity=2Gi --name=ord-node4 --ca-name=ord-ca.default \\\n    --hosts=orderer3-ord.localho.st --admin-hosts=admin-orderer3-ord.localho.st --istio-port=443\n\n# 3/4\n\nkubectl wait --timeout=180s --for=condition=Running fabricorderernodes.hlf.kungfusoftware.es --all\n```\n\nCheck that the orderer is running:\n\n```bash\nkubectl get pods\n```\n\n```bash\nopenssl s_client -connect orderer0-ord.localho.st:443\n```\n\n## 6. Create a channel\n\nTo create the channel we need to first create the wallet secret, which will contain the identities used by the operator to manage the channel\n\n### Register and enrolling OrdererMSP identity\n\n```bash\n# register\nkubectl hlf ca register --name=ord-ca --user=admin --secret=adminpw \\\n    --type=admin --enroll-id enroll --enroll-secret=enrollpw --mspid=OrdererMSP\n\n\nkubectl hlf identity create --name orderer-admin-sign --namespace default \\\n    --ca-name ord-ca --ca-namespace default \\\n    --ca ca --mspid OrdererMSP --enroll-id admin --enroll-secret adminpw # sign identity\n\nkubectl hlf identity create --name orderer-admin-tls --namespace default \\\n    --ca-name ord-ca --ca-namespace default \\\n    --ca tlsca --mspid OrdererMSP --enroll-id admin --enroll-secret adminpw # tls identity\n\n```\n\n### Register and enrolling Org1MSP identity\n\n```bash\n# register\nkubectl hlf ca register --name=org1-ca --namespace=default --user=admin --secret=adminpw \\\n    --type=admin --enroll-id enroll --enroll-secret=enrollpw --mspid=Org1MSP\n\n# enroll\nkubectl hlf identity create --name org1-admin --namespace default \\\n    --ca-name org1-ca --ca-namespace default \\\n    --ca ca --mspid Org1MSP --enroll-id admin --enroll-secret adminpw\n\n```\n\n### Create main channel\n\n```bash\nexport IDENT_12=$(printf \"%16s\" \"\")\n# tls CA certificate\nexport ORDERER_TLS_CERT=$(kubectl get fabriccas ord-ca -o=jsonpath='{.status.tlsca_cert}' | sed -e \"s/^/${IDENT_12}/\" )\n\nexport ORDERER0_TLS_CERT=$(kubectl get fabricorderernodes ord-node1 -o=jsonpath='{.status.tlsCert}' | sed -e \"s/^/${IDENT_12}/\" )\nexport ORDERER1_TLS_CERT=$(kubectl get fabricorderernodes ord-node2 -o=jsonpath='{.status.tlsCert}' | sed -e \"s/^/${IDENT_12}/\" )\nexport ORDERER2_TLS_CERT=$(kubectl get fabricorderernodes ord-node3 -o=jsonpath='{.status.tlsCert}' | sed -e \"s/^/${IDENT_12}/\" )\nexport ORDERER3_TLS_CERT=$(kubectl get fabricorderernodes ord-node4 -o=jsonpath='{.status.tlsCert}' | sed -e \"s/^/${IDENT_12}/\" )\n\nexport ORDERER0_SIGN_CERT=$(kubectl get fabricorderernodes ord-node1 -o=jsonpath='{.status.signCert}' | sed -e \"s/^/${IDENT_12}/\" )\nexport ORDERER1_SIGN_CERT=$(kubectl get fabricorderernodes ord-node2 -o=jsonpath='{.status.signCert}' | sed -e \"s/^/${IDENT_12}/\" )\nexport ORDERER2_SIGN_CERT=$(kubectl get fabricorderernodes ord-node3 -o=jsonpath='{.status.signCert}' | sed -e \"s/^/${IDENT_12}/\" )\nexport ORDERER3_SIGN_CERT=$(kubectl get fabricorderernodes ord-node4 -o=jsonpath='{.status.signCert}' | sed -e \"s/^/${IDENT_12}/\" )\n\nkubectl apply -f - \u003c\u003cEOF\napiVersion: hlf.kungfusoftware.es/v1alpha1\nkind: FabricMainChannel\nmetadata:\n  name: demo\nspec:\n  name: demo\n  adminOrdererOrganizations:\n    - mspID: OrdererMSP\n  adminPeerOrganizations:\n    - mspID: Org1MSP\n  channelConfig:\n    application:\n      acls: null\n      capabilities:\n        - V2_5\n      policies: null\n    capabilities:\n      - V3_0\n    orderer:\n      batchSize:\n        absoluteMaxBytes: 1048576\n        maxMessageCount: 100\n        preferredMaxBytes: 524288\n      batchTimeout: 2s\n      capabilities:\n        - V2_0\n      smartBFT:\n        request_batch_max_count: 100\n        request_batch_max_bytes: 10485760\n        request_batch_max_interval: \"50ms\"\n        incoming_message_buffer_size: 200\n        request_pool_size: 100000\n        request_forward_timeout: \"2s\"\n        request_complain_timeout: \"20s\"\n        request_auto_remove_timeout: \"3m\"\n        view_change_resend_interval: \"5s\"\n        view_change_timeout: \"20s\"\n        leader_heartbeat_timeout: \"1m0s\"\n        leader_heartbeat_count: 10\n        collect_timeout: \"1s\"\n        sync_on_start: true\n        speed_up_view_change: false\n        leader_rotation: 2\n        decisions_per_leader: 3\n        request_max_bytes: 0\n\n      consenterMapping:\n      - host: orderer0-ord.localho.st\n        port: 443\n        id: 1\n        msp_id: OrdererMSP\n        client_tls_cert: |\n${ORDERER0_TLS_CERT}\n\n        server_tls_cert: |\n${ORDERER0_TLS_CERT}\n\n        identity: |\n${ORDERER0_SIGN_CERT}\n\n      - host: orderer1-ord.localho.st\n        port: 443\n        id: 2\n        msp_id: OrdererMSP\n        client_tls_cert: |\n${ORDERER1_TLS_CERT}\n\n        server_tls_cert: |\n${ORDERER1_TLS_CERT}\n\n        identity: |\n${ORDERER1_SIGN_CERT}\n\n      - host: orderer2-ord.localho.st\n        port: 443\n        id: 3\n        msp_id: OrdererMSP\n        client_tls_cert: |\n${ORDERER2_TLS_CERT}\n\n        server_tls_cert: |\n${ORDERER2_TLS_CERT}\n\n        identity: |\n${ORDERER2_SIGN_CERT}\n\n      - host: orderer3-ord.localho.st\n        port: 443\n        id: 4\n        msp_id: OrdererMSP\n        client_tls_cert: |\n${ORDERER3_TLS_CERT}\n\n        server_tls_cert: |\n${ORDERER3_TLS_CERT}\n\n        identity: |\n${ORDERER3_SIGN_CERT}\n\n      ordererType: BFT\n      policies: null\n      state: STATE_NORMAL\n    policies: null\n  externalOrdererOrganizations: []\n  peerOrganizations:\n    - mspID: Org1MSP\n      caName: \"org1-ca\"\n      caNamespace: \"default\"\n  identities:\n    OrdererMSP:\n      secretKey: user.yaml\n      secretName: orderer-admin-tls\n      secretNamespace: default\n    OrdererMSP-sign:\n      secretKey: user.yaml\n      secretName: orderer-admin-sign\n      secretNamespace: default\n    Org1MSP:\n      secretKey: user.yaml\n      secretName: org1-admin\n      secretNamespace: default\n  externalPeerOrganizations: []\n  ordererOrganizations:\n    - caName: \"ord-ca\"\n      caNamespace: \"default\"\n      externalOrderersToJoin:\n        - host: ord-node1\n          port: 7053\n        - host: ord-node2\n          port: 7053\n        - host: ord-node3\n          port: 7053\n        - host: ord-node4\n          port: 7053\n      mspID: OrdererMSP\n      ordererEndpoints:\n        - orderer0-ord.localho.st:443\n        - orderer1-ord.localho.st:443\n        - orderer2-ord.localho.st:443\n        - orderer3-ord.localho.st:443\n      orderersToJoin: []\n  orderers:\n    - host: ord-node1\n      port: 7050\n      tlsCert: |\n${ORDERER0_TLS_CERT}\n    - host: ord-node2\n      port: 7050\n      tlsCert: |-\n${ORDERER1_TLS_CERT}\n    - host: ord-node3\n      port: 7050\n      tlsCert: |-\n${ORDERER2_TLS_CERT}\n    - host: ord-node4\n      port: 7050\n      tlsCert: |-\n${ORDERER2_TLS_CERT}\n\nEOF\n```\n\n### Create main channel using ETCDRaft\n\n```bash\nexport PEER_ORG_SIGN_CERT=$(kubectl get fabriccas org1-ca -o=jsonpath='{.status.ca_cert}')\nexport PEER_ORG_TLS_CERT=$(kubectl get fabriccas org1-ca -o=jsonpath='{.status.tlsca_cert}')\nexport IDENT_8=$(printf \"%8s\" \"\")\nexport ORDERER_TLS_CERT=$(kubectl get fabriccas ord-ca -o=jsonpath='{.status.tlsca_cert}' | sed -e \"s/^/${IDENT_8}/\" )\nexport ORDERER0_TLS_CERT=$(kubectl get fabricorderernodes ord-node1 -o=jsonpath='{.status.tlsCert}' | sed -e \"s/^/${IDENT_8}/\" )\nexport ORDERER1_TLS_CERT=$(kubectl get fabricorderernodes ord-node2 -o=jsonpath='{.status.tlsCert}' | sed -e \"s/^/${IDENT_8}/\" )\nexport ORDERER2_TLS_CERT=$(kubectl get fabricorderernodes ord-node3 -o=jsonpath='{.status.tlsCert}' | sed -e \"s/^/${IDENT_8}/\" )\nexport ORDERER3_TLS_CERT=$(kubectl get fabricorderernodes ord-node4 -o=jsonpath='{.status.tlsCert}' | sed -e \"s/^/${IDENT_8}/\" )\n\nkubectl apply -f - \u003c\u003cEOF\napiVersion: hlf.kungfusoftware.es/v1alpha1\nkind: FabricMainChannel\nmetadata:\n  name: demo\nspec:\n  name: demo\n  adminOrdererOrganizations:\n    - mspID: OrdererMSP\n  adminPeerOrganizations:\n    - mspID: Org1MSP\n  channelConfig:\n    application:\n      acls: null\n      capabilities:\n        - V2_0\n      policies: null\n    capabilities:\n      - V2_0\n    orderer:\n      batchSize:\n        absoluteMaxBytes: 1048576\n        maxMessageCount: 10\n        preferredMaxBytes: 524288\n      batchTimeout: 2s\n      capabilities:\n        - V2_0\n      etcdRaft:\n        options:\n          electionTick: 10\n          heartbeatTick: 1\n          maxInflightBlocks: 5\n          snapshotIntervalSize: 16777216\n          tickInterval: 500ms\n      ordererType: etcdraft\n      policies: null\n      state: STATE_NORMAL\n    policies: null\n  externalOrdererOrganizations: []\n  peerOrganizations:\n    - mspID: Org1MSP\n      caName: \"org1-ca\"\n      caNamespace: \"default\"\n  identities:\n    OrdererMSP:\n      secretKey: user.yaml\n      secretName: orderer-admin-tls\n      secretNamespace: default\n    OrdererMSP-sign:\n      secretKey: user.yaml\n      secretName: orderer-admin-sign\n      secretNamespace: default\n    Org1MSP:\n      secretKey: user.yaml\n      secretName: org1-admin\n      secretNamespace: default\n  externalPeerOrganizations: []\n  ordererOrganizations:\n    - caName: \"ord-ca\"\n      caNamespace: \"default\"\n      externalOrderersToJoin:\n        - host: ord-node1\n          port: 7053\n        - host: ord-node2\n          port: 7053\n        - host: ord-node3\n          port: 7053\n        - host: ord-node4\n          port: 7053\n      mspID: OrdererMSP\n      ordererEndpoints:\n        - ord-node1:7050\n        - ord-node2:7050\n        - ord-node3:7050\n        - ord-node4:7050\n      orderersToJoin: []\n  orderers:\n    - host: ord-node1\n      port: 7050\n      tlsCert: |-\n${ORDERER0_TLS_CERT}\n    - host: ord-node2\n      port: 7050\n      tlsCert: |-\n${ORDERER1_TLS_CERT}\n    - host: ord-node3\n      port: 7050\n      tlsCert: |-\n${ORDERER2_TLS_CERT}\n    - host: ord-node4\n      port: 7050\n      tlsCert: |-\n${ORDERER3_TLS_CERT}\n\nEOF\n\n```\n\n\n## 7. Join peer to the channel\n\nTo join the peers from Org1MSP to the channel `demo` we need to create a `FabricFollowerChannel` resource:\n\n```bash\n\nexport IDENT_8=$(printf \"%8s\" \"\")\nexport ORDERER0_TLS_CERT=$(kubectl get fabricorderernodes ord-node1 -o=jsonpath='{.status.tlsCert}' | sed -e \"s/^/${IDENT_8}/\" )\n\nkubectl apply -f - \u003c\u003cEOF\napiVersion: hlf.kungfusoftware.es/v1alpha1\nkind: FabricFollowerChannel\nmetadata:\n  name: demo-org1msp\nspec:\n  anchorPeers:\n    - host: org1-peer0.default\n      port: 7051\n    - host: org1-peer1.default\n      port: 7051\n  hlfIdentity:\n    secretKey: user.yaml\n    secretName: org1-admin\n    secretNamespace: default\n  mspId: Org1MSP\n  name: demo\n  externalPeersToJoin: []\n  orderers:\n    - certificate: |\n${ORDERER0_TLS_CERT}\n      url: grpcs://ord-node1.default:7050\n  peersToJoin:\n    - name: org1-peer0\n      namespace: default\n    - name: org1-peer1\n      namespace: default\nEOF\n\n```\n\n## 8. Install a chaincode\n\n### Prepare connection string for a peer\n\nTo prepare the connection string, we have to:\n\n1. Create `FabricNetworkConfig` object in the Kubernetes cluster\n2. Fetch the connection string from the Kubernetes secret\n\n3. Get connection string without users for organization Org1MSP and OrdererMSP\n\n```bash\n\n# This identity will register and enroll the user\nkubectl hlf identity create --name org1-admin --namespace default \\\n    --ca-name org1-ca --ca-namespace default \\\n    --ca ca --mspid Org1MSP --enroll-id explorer-admin --enroll-secret explorer-adminpw \\\n    --ca-enroll-id=enroll --ca-enroll-secret=enrollpw --ca-type=admin\n\n\nkubectl hlf networkconfig create --name=org1-cp \\\n  -o Org1MSP -o OrdererMSP -c demo \\\n  --identities=org1-admin.default --secret=org1-cp\n```\n\n### Fetch the connection string from the Kubernetes secret\n\n```bash\nkubectl get secret org1-cp -o jsonpath=\"{.data.config\\.yaml}\" | base64 --decode \u003e org1.yaml\n```\n\n### Create metadata file\n\n```bash\n# remove the code.tar.gz chaincode.tgz if they exist\nrm code.tar.gz chaincode.tgz\nexport CHAINCODE_NAME=asset\nexport CHAINCODE_LABEL=asset\ncat \u003c\u003c METADATA-EOF \u003e \"metadata.json\"\n{\n    \"type\": \"ccaas\",\n    \"label\": \"${CHAINCODE_LABEL}\"\n}\nMETADATA-EOF\n```\n\n### Prepare connection file\n\n```bash\n## chaincode as a service\ncat \u003e \"connection.json\" \u003c\u003cCONN_EOF\n{\n  \"address\": \"${CHAINCODE_NAME}:7052\",\n  \"dial_timeout\": \"10s\",\n  \"tls_required\": false\n}\nCONN_EOF\n\ntar cfz code.tar.gz connection.json\ntar cfz chaincode.tgz metadata.json code.tar.gz\nexport PACKAGE_ID=$(kubectl hlf chaincode calculatepackageid --path=chaincode.tgz --language=node --label=$CHAINCODE_LABEL)\necho \"PACKAGE_ID=$PACKAGE_ID\"\n\nkubectl hlf chaincode install --path=./chaincode.tgz \\\n    --config=org1.yaml --language=golang --label=$CHAINCODE_LABEL --user=org1-admin-default --peer=org1-peer0.default\n\nkubectl hlf chaincode install --path=./chaincode.tgz \\\n    --config=org1.yaml --language=golang --label=$CHAINCODE_LABEL --user=org1-admin-default --peer=org1-peer1.default\n\n```\n\n### Check if the chaincode is installed\n\nTO check if the chaincode is installed, we can use the following command:\n\n```bash\nkubectl hlf chaincode queryinstalled --config=org1.yaml --user=org1-admin-default --peer=org1-peer0.default\n```\n\nIt should return something like this:\n\n```text\nPACKAGE ID                                                              LABEL   REFERENCES\nasset:f1056c50a23f901d2aa6893505eef057db548f0775003dabbfd1f500877acda8  asset   {\"demo\":[{\"name\":\"asset\",\"version\":\"1.0\"}]}\n```\n\n## 9. Deploy chaincode container on cluster\n\nThe following command will create or update the CRD based on the packageID, chaincode name, and docker image.\n\n```bash\nkubectl hlf externalchaincode sync --image=kfsoftware/chaincode-external:latest \\\n    --name=$CHAINCODE_NAME \\\n    --namespace=default \\\n    --package-id=$PACKAGE_ID \\\n    --tls-required=false \\\n    --replicas=1\n```\n\n## 10. Approve chaincode\n\nTo approve the chaincode definition for org1, run the following command:\n\n```bash\nexport SEQUENCE=1\nexport VERSION=\"1.0\"\nkubectl hlf chaincode approveformyorg --config=org1.yaml --user=org1-admin-default --peer=org1-peer0.default \\\n    --package-id=$PACKAGE_ID \\\n    --version \"$VERSION\" --sequence \"$SEQUENCE\" --name=asset \\\n    --policy=\"OR('Org1MSP.member')\" --channel=demo\n```\n\n## 11. Commit chaincode\n\nTo commit chaincode to the channel, run the following command:\n\n```bash\nkubectl hlf chaincode commit --config=org1.yaml --user=org1-admin-default --mspid=Org1MSP \\\n    --version \"$VERSION\" --sequence \"$SEQUENCE\" --name=asset \\\n    --policy=\"OR('Org1MSP.member')\" --channel=demo\n```\n\n## 12. Invoke a transaction on the channel\n\nNow that we have committed the chaincode to the channel, we can interact with it.\n\nWe will use the kubectl plugin to interact with the chaincode. The plugin is a wrapper around the go-fabric SDK and provides a more user-friendly interface.\n\n### Invoke a transaction on the channel\n\n```bash\nkubectl hlf chaincode invoke --config=org1.yaml \\\n    --user=org1-admin-default --peer=org1-peer0.default \\\n    --chaincode=asset --channel=demo \\\n    --fcn=initLedger\n\n```\n\n## 13. Query assets in the channel\n\nTo query the chaincode, run the following command:\n\n```bash\nkubectl hlf chaincode query --config=org1.yaml \\\n    --user=org1-admin-default --peer=org1-peer0.default \\\n    --chaincode=asset --channel=demo \\\n    --fcn=GetAllAssets -a '[]'\n```\n\n# 13.1 Create an asset\n\nCreate an asset\n```bash\nkubectl hlf chaincode invoke --config=org1.yaml \\\n    --user=org1-admin-default --peer=org1-peer0.default \\\n    --chaincode=asset --channel=demo \\\n    --fcn=CreateAsset -a \"asset7\" -a blue -a \"5\" -a \"tom\" -a \"100\"\n```\n\n# 13.2 Query the asset\n\nQuery the asset we just created\n```bash\nkubectl hlf chaincode query --config=org1.yaml \\\n    --user=org1-admin-default --peer=org1-peer0.default \\\n    --chaincode=asset --channel=demo \\\n    --fcn=ReadAsset -a asset7\n```\n\n## 14. Completion\n\nCongratulations! You have completed the workshop.\n\nAt this point, you must have:\n\n-   Ordering service with 3 nodes and a CA\n-   Peer organization with a peer and a CA\n-   A channel **demo**\n-   A chaincode install in peer0\n-   A chaincode approved and committed\n\nIf something went wrong or didn't work, please, open an issue.\n\n## Cleanup the environment\n\n```bash\nkubectl delete fabricorderernodes.hlf.kungfusoftware.es --all-namespaces --all\nkubectl delete fabricpeers.hlf.kungfusoftware.es --all-namespaces --all\nkubectl delete fabriccas.hlf.kungfusoftware.es --all-namespaces --all\nkubectl delete fabricchaincode.hlf.kungfusoftware.es --all-namespaces --all\nkubectl delete fabricmainchannels --all-namespaces --all\nkubectl delete fabricfollowerchannels --all-namespaces --all\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkfsoftware%2Fmeetup-hlf-3-0","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkfsoftware%2Fmeetup-hlf-3-0","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkfsoftware%2Fmeetup-hlf-3-0/lists"}