Chaincode launcher and builder for Hyperledger Fabric on Kubernetes
This project implements an external chaincode launcher and builder for Hyperledger Fabric. It talks directly to the Kubernetes API and doesn't depend on Docker which enables you to deploy a Hyperledger Fabric Peer on Kubernetes without exposing the Docker socket and therefore improve security and portability.
The following points have been addressed:
- Chaincode build runs separated from the peer
- Chaincode is launched separated from the peer
- The build and launch of chaincode is compatible with the default/internal system
- The chaincode must be usable without changes
- The used images for build and launch of the chaincode can be the same as in the internal system
- Kubernetes security mechanisms can be enforced (network policies, host isolation, etc.)
- There is no dependency on the Kubernetes CRI implementation (like Docker)
- There is no need for priviledged pods
- stdout and stderr of the chaincode is forwarded to the peer
- The peer notices when a chaincode fails
Requirements:
- The peer runs as a pod under a Kubernetes ServiceAccount that can manipulate pods
- The peer uses a
PersistentVolume
provided by aPersistentVolumeClaim
, which is used to exchange data between the peer, builder and launcher pods
The easiest way to use this project is by using the postfinance/hlfabric-k8scc
Docker image. It's based on the Hyperledger Fabric Peer image and extended with a default configuration.
When you have your peer running on Kubernetes, you need to ensure that the rbac are set and that the peer pod runs as a service account matching the rules. The following configuration must be done for the peer:
spec:
template:
spec:
serviceAccountName: peer # run peer as service account
containers:
- image: postfinance/hlfabric-k8scc:2.2.1-k8scc0.0.8 # use an appropriate image and tag
- name: K8SCC_CFGFILE
value: "/opt/k8scc/k8scc.yaml" # this points to the default configuration file
volumeMounts:
- mountPath: /var/lib/k8scc/transfer/ # here we mount our transfer PV
name: transfer-pv
volumes:
- name: transfer-pv
persistentVolumeClaim:
claimName: k8scc-transfer-pv # this is our default claim name for transfer PVs
You can have a look in the example directory for a more complete example.
If you want to customize the images or the resources, you need to use an own k8scc.yaml
configuration file.
And if you have an own core.yaml
, you need to configure the launcher. Have a look at this patch.
It is not possible to inject this data structure using environment variables.
The version tags are defined as follows This allows to create (hotfix) branches for different peer versions.
{{ peer version }}-k8scc{{ k8scc version }}
: recommended tag scheme for production usev{{ k8scc version }}
: tag scheme used internally for k8scc development
Examples:
2.2.1-k8scc0.0.8
: Peer v2.2.1, k8scc v0.0.8v0.0.8
: k8scc v0.0.8, peer at undefined version
If you want to release a new version of k8scc
, do the following:
- Set the desired peer version in
Dockerfile
- Run
prepare_release
- Commit changes of updated dependencies, if any
- Set the tags generated by
prepare_release
to the latest commit
This software implements the four parts of an external chaincode launcher and builder: detect
, build
, release
, run
.
The step detect
just checks the metadata.json
if the defined platform (e.g. golang
) is available in Hyperledger Fabric and if an appropriate image is configured in k8scc.yaml
The step build
is responsible for building the chaincode while ensuring compatibility of the chaincode with the internal builder process.
The preparation:
- Parse
metadata.json
and check if the plattform (e.g.golang
) is supported - Create a temporary directory on the transfer volume
- Inside this temporary directory, copy the provided chaincode source and create an empty directory for the build output
Next, a builder pod is created and has the following properties:
- The name is
{{ peer pod name}}-ccbuild-{{ short hash }}
- It has the temporary subdirectories of the transfer PV mounted
- The command is the same as the one used by Hyperledger Fabric on its internal builder
The created pod is watched until it finishes either successfully or not. Afterwards this procedure is executed:
- Write stdout and stderr of the builder pod to the peer log
- Only if the build failed: Remove all garbage (pod + temporary directory) and exit
- Copy output data from the temporary directory to the output directory on the peer
- Copy data from the
META-INF
in the source directory to the output directory on the peer - Write build information to the output directory, in order to use the same image for the launch as for the build
- Cleanup pod and remove the temporary directory
The step release
just copies the data from META-INF
to the output directory provided by the peer
The step run
responsible for launching the chaincode while ensuring compatibility of the chaincode with the internal launcher process.
The preparation:
- Parse build information to extract the used image
- Create a temporary directory on the transfer volume
- Inside this temporary directory, copy the build output and the artifacts like certificates extracted from
chaincode.json
Next, a launcher pod is created and has the following properties:
- The name is
{{ peer pod name}}-cc-{{ chaincode label }}-{{ short hash }}
- It has the temporary subdirectories of the transfer PV mounted
- The platform/language dependant command starts the chaincode
The created pod is watched until it exits. Afterwards this procedure is executed:
- Write stdout and stderr of the launcher pod to the peer log
- Remove all garbage (pod + temporary directory)