github.com/kaituanwang/hyperledger@v2.0.1+incompatible/docs/source/cc_service.md (about)

     1  # Chaincode as an external service
     2  
     3  Fabric v2.0 supports chaincode deployment and execution outside of Fabric that enables users to manage a chaincode runtime independently of the peer. This facilitates deployment of chaincode on Fabric cloud deployments such as Kubernetes. Instead of building and launching the chaincode on every peer, chaincode can now run as a service whose lifecycle is managed outside of Fabric. This capability leverages the Fabric v2.0 external builder and launcher functionality which enables operators to extend a peer with programs to build, launch, and discover chaincode. Before reading this topic you should become familiar with the [External Builder and Launcher](./cc_launcher.html) content.
     4  
     5  Prior to the availability of the external builders, the chaincode package content was required to be a set of source code files for a particular language which could be built and launched as a chaincode binary. The new external build and launcher functionality now allows users to optionally customize the build process. With respect to running the chaincode as an external service, the build process allows you to specify the endpoint information of the server where the chaincode is running. Hence the package simply consists of the externally running chaincode server endpoint information and TLS artifacts for secure connection. TLS is optional but highly recommended for all environments except a simple test environment.
     6  
     7  The rest of this topic describes how to configure chaincode as an external service:
     8  
     9  * [Packaging chaincode](#packaging-chaincode)
    10  * [Configuring a peer to process external chaincode](#configuring-a-peer-to-process-external-chaincode)
    11  * [External builder and launcher sample scripts](#external-builder-and-launcher-sample-scripts)
    12  * [Writing chaincode to run as an external service](#writing-chaincode-to-run-as-an-external-service)
    13  * [Deploying the chaincode](#deploying-the-chaincode)
    14  * [Running the chaincode as an external service](#running-the-chaincode-as-an-external-service)
    15  
    16  ## Packaging chaincode
    17  
    18  With the Fabric v2.0 chaincode lifecycle, chaincode is [packaged](./cc_launcher.html#chaincode-packages) and installed in a `.tar.gz` format. The following `myccpackage.tgz` archive  demonstrates the required structure:
    19  
    20  ```sh
    21  $ tar xvfz myccpackage.tgz
    22  metadata.json
    23  code.tar.gz
    24  ```
    25  
    26  The chaincode package should be used to provide two pieces of information to the external builder and launcher process
    27  * identify if the chaincode is an external service. The `bin/detect` section describes an approach using the `metadata.json` file
    28  * provide chaincode endpoint information in a `connection.json` file placed in the release directory. The `bin/run` section describes the `connection.json` file
    29  
    30  There is plenty of flexibility to gathering the above information. The sample scripts in the [External builder and launcher sample scripts](#external-builder-and-launcher-sample-scripts) illustrate a simple approach to providing the information.
    31  As an example of flexibility, consider packaging couchdb index files (see [Add the index to your chaincode folder](couchdb_tutorial.html#add-the-index-to-your-chaincode-folder)). Sample scripts below describe an approach to packaging the files into code.tar.gz.
    32  
    33  ```
    34  tar cfz code.tar.gz connection.json metadata
    35  tar cfz $1-pkg.tgz metadata.json code.tar.gz
    36  ```
    37  
    38  ## Configuring a peer to process external chaincode
    39  
    40  In this section we go over the configuration needed
    41  * to detect if the chaincode package identifies an external chaincode service
    42  * to create the `connection.json` file in the release directory
    43  
    44  ### Modify the peer core.yaml to include the externalBuilder
    45  
    46  Assume the scripts are on the peer in the `bin` directory as follows
    47  ```
    48      <fully qualified path on the peer's env>
    49      └── bin
    50          ├── build
    51          ├── detect
    52          └── release
    53  ```
    54  
    55  Modify the `chaincode` stanza of the peer `core.yaml` file to include the `externalBuilders` configuration element:
    56  
    57  ```yaml
    58  externalBuilders:
    59       - name: myexternal
    60         path: <fully qualified path on the peer's env>   
    61  ```
    62  
    63  ### External builder and launcher sample scripts
    64  
    65  To help understand what each script needs to contain to work with the chaincode as an external service, this section contains samples of  `bin/detect` `bin/build`, `bin/release`, and `bin/run` scripts.
    66  
    67  **Note:** These samples use the `jq` command to parse json. You can run `jq --version` to check if you have it installed. Otherwise, install `jq` or suitably modify the scripts.
    68  
    69  #### bin/detect
    70  
    71  The `bin/detect script` is responsible for determining whether or not a buildpack should be used to build a chaincode package and launch it.  For chaincode as an external service, the sample script looks for a `type` property set to `external` in the `metadata.json` file:
    72  
    73  ```json
    74  {"path":"","type":"external","label":"mycc"}
    75  ```
    76  
    77  The peer invokes detect with two arguments:
    78  
    79  ```
    80  bin/detect CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR
    81  ```
    82  
    83  A sample `bin/detect` script could contain:
    84  
    85  ```sh
    86  
    87  #!/bin/bash
    88  
    89  set -euo pipefail
    90  
    91  METADIR=$2
    92  #check if the "type" field is set to "external"
    93  if [ "$(jq -r .type "$METADIR/metadata.json")" == "external" ]; then
    94      exit 0
    95  fi
    96  
    97  exit 1
    98  
    99  ```
   100  
   101  #### bin/build
   102  
   103  For chaincode as an external service, the sample build script assumes the chaincode package's `code.tar.gz` file contains `connection.json` which it simply copies to the `BUILD_OUTPUT_DIR`. The peer invokes the build script with three arguments:
   104  
   105  ```
   106  bin/build CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR BUILD_OUTPUT_DIR
   107  ```
   108  
   109  A sample `bin/build` script could contain:
   110  
   111  ```sh
   112  
   113  #!/bin/bash
   114  
   115  set -euo pipefail
   116  
   117  SOURCE=$1
   118  OUTPUT=$3
   119  
   120  #external chaincodes expect connection.json file in the chaincode package
   121  if [ ! -f "$SOURCE/connection.json" ]; then
   122      >&2 echo "$SOURCE/connection.json not found"
   123      exit 1
   124  fi
   125  
   126  #simply copy the endpoint information to specified output location
   127  cp $SOURCE/connection.json $OUTPUT/connection.json
   128  
   129  if [ -d "$SOURCE/metadata" ]; then
   130      cp -a $SOURCE/metadata $OUTPUT/metadata
   131  fi
   132  
   133  exit 0
   134  
   135  ```
   136  
   137  #### bin/release
   138  
   139  For chaincode as an external service, the `bin/release` script is responsible for providing the `connection.json` to the peer by placing it in the `RELEASE_OUTPUT_DIR`.  The `connection.json` file has the following JSON structure
   140  
   141  * **address** - chaincode server endpoint accessible from peer. Must be specified in “<host>:<port>” format.
   142  * **dial_timeout** - interval to wait for connection to complete. Specified as a string qualified with time units (e.g, "10s", "500ms", "1m"). Default is “3s” if not specified.
   143  * **tls_required** - true or false. If false, "client_auth_required", "client_key", "client_cert", and "root_cert" are not required. Default is “true”.
   144  * **client_auth_required** - if true, "client_key" and "client_cert" are required. Default is false. It is ignored if tls_required is false.
   145  * **client_key** - PEM encoded string of the client private key.
   146  * **client_cert**  - PEM encoded string of the client certificate.
   147  * **root_cert**  - PEM encoded string of the server (peer) root certificate.
   148  
   149  For example:
   150  
   151  ```json
   152  {
   153    "address": "your.chaincode.host.com:9999",
   154    "dial_timeout": "10s",
   155    "tls_required": "true",
   156    "client_auth_required": "true",
   157    "client_key": "-----BEGIN EC PRIVATE KEY----- ... -----END EC PRIVATE KEY-----",
   158    "client_cert": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----",
   159    "root_cert": "-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----"
   160  }
   161  ```
   162  
   163  As noted in the `bin/build` section, this sample assumes the chaincode package directly contains the `connection.json` file which the build script copies to the `BUILD_OUTPUT_DIR`. The peer invokes the release script with two arguments:
   164  
   165  ```
   166  bin/release BUILD_OUTPUT_DIR RELEASE_OUTPUT_DIR
   167  ```
   168  
   169  A sample `bin/release` script could contain:
   170  
   171  
   172  ```sh
   173  
   174  #!/bin/bash
   175  
   176  set -euo pipefail
   177  
   178  BLD="$1"
   179  RELEASE="$2"
   180  
   181  if [ -d "$BLD/metadata" ]; then
   182     cp -a "$BLD/metadata/"* "$RELEASE/"
   183  fi
   184  
   185  #external chaincodes expect artifacts to be placed under "$RELEASE"/chaincode/server
   186  if [ -f $BLD/connection.json ]; then
   187     mkdir -p "$RELEASE"/chaincode/server
   188     cp $BLD/connection.json "$RELEASE"/chaincode/server
   189  
   190     #if tls_required is true, copy TLS files (using above example, the fully qualified path for these fils would be "$RELEASE"/chaincode/server/tls)
   191  
   192     exit 0
   193  fi
   194  
   195  exit 1
   196  ```    
   197  
   198  ## Writing chaincode to run as an external service
   199  
   200  Currently, the chaincode as an external service model is only supported by GO chaincode shim. In Fabric v2.0, the GO shim API adds a `ChaincodeServer` type that developers should use to create a chaincode server.  The `Invoke` and `Query` APIs are unaffected. Developers should write to the `shim.ChaincodeServer` API, then build the chaincode and run it in the external environment of choice. Here is a simple sample chaincode program to illustrate the pattern:
   201  
   202  ```go
   203  
   204  package main
   205  
   206  import (
   207          "fmt"
   208  
   209          "github.com/hyperledger/fabric-chaincode-go/shim"
   210          pb "github.com/hyperledger/fabric-protos-go/peer"
   211  )
   212  
   213  // SimpleChaincode example simple Chaincode implementation
   214  type SimpleChaincode struct {
   215  }
   216  
   217  func (s *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
   218          // init code
   219  }
   220  
   221  func (s *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
   222          // invoke code
   223  }
   224  
   225  //NOTE - parameters such as ccid and endpoint information are hard coded here for illustration. This can be passed in in a variety of standard ways
   226  func main() {
   227         //The ccid is assigned to the chaincode on install (using the “peer lifecycle chaincode install <package>” command) for instance
   228          ccid := "mycc:fcbf8724572d42e859a7dd9a7cd8e2efb84058292017df6e3d89178b64e6c831"
   229  
   230          server := &shim.ChaincodeServer{
   231                          CCID: ccid,
   232                          Address: "myhost:9999"
   233                          CC: new(SimpleChaincode),
   234                          TLSProps: shim.TLSProperties{
   235                                  Disabled: true,
   236                          },
   237                  }
   238          err := server.Start()
   239          if err != nil {
   240                  fmt.Printf("Error starting Simple chaincode: %s", err)
   241          }
   242  }
   243  ```
   244  The key to running the chaincode as an external service is the use of `shim.ChaincodeServer`. This uses the new shim API `shim.ChaincodeServer` with the chaincode service properties described below:
   245  
   246  * **CCID** (string)- CCID should match chaincode's package name on peer. This is the `CCID` associated with the installed chaincode as returned by the `peer lifecycle chaincode install <package>` CLI command. This can be obtained post-install using the "peer lifecycle chaincode queryinstalled" command.
   247  * **Address** (string) - Address is the listen address of the chaincode server
   248  * **CC** (Chaincode) -  CC is the chaincode that handles Init and Invoke
   249  * **TLSProps** (TLSProperties) - TLSProps is the TLS properties passed to chaincode server
   250  * **KaOpts** (keepalive.ServerParameters) -  KaOpts keepalive options, sensible defaults provided if nil
   251  
   252  Then build the chaincode as suitable to your GO environment.
   253  
   254  ## Deploying the chaincode
   255  
   256  When the GO chaincode is ready for deployment, you can package the chaincode as explained in the [Packaging chaincode](#packaging-chaincode) section and deploy the chaincode as explained in the [chaincode lifecycle](./chaincode4noah.html#chaincode-lifecycle) documentation.
   257  
   258  ## Running the chaincode as an external service
   259  
   260  Create the chaincode as specified in the [Writing chaincode to run as an external service](#writing-chaincode-to-run-as-an-external-service) section. Run the built executable in your environment of choice, such as Kubernetes or directly as a process on the peer machine.
   261  
   262  Using this chaincode as an external service model, installing the chaincode on each peer is no longer required. With the chaincode endpoint deployed to the peer instead and the chaincode running, you can continue the normal process of committing the
   263  chaincode definition to the channel and invoking the chaincode.
   264  
   265  <!---
   266  Licensed under Creative Commons Attribution 4.0 International License https://creativecommons.org/licenses/by/4.0/
   267  -->