Getting your CorDapps running in Docker
August 19, 2020
It’s easier than you think.
If you’ve read this blog recently you know that we’ve had a bit of an emphasis lately on making it easier to use docker when working with Corda.
One of the ways that the Corda engineering team has done this is using the dockerform task. What this will do is reproduce your normal local Corda environment with a docker-compose file.
The dockerform gradle task
You’ve probably seen many corDapp examples that use the cordform gradle task.
In our case, we actually can use essentially the same node configuration and feed it to the Dockerform task to make this work.
We just need to add two things to make this work well.
- We’ll need ssh access to use the Corda shell
- We’ll need to specify the docker image: corda/corda-zulu-java1.8–4.5
If your CorDapp already works, you won’t have problems with this, so here’s an example node configuration specifying those things.
task prepareDockerNodes(type: net.corda.plugins.Dockerform, dependsOn: ['jar']) {dockerImage="corda/corda-zulu-java1.8-4.5:latest"nodeDefaults { projectCordapp { deploy = false } cordapp project(':contracts') cordapp project(':workflows') }node { name "O=Notary,L=London,C=GB" notary = [validating : false] p2pPort 10002 rpcSettings { address("localhost:10003") adminAddress("localhost:10043") } }node { name "O=PartyA,L=London,C=GB" p2pPort 10002 rpcSettings { address("localhost:10006") adminAddress("localhost:10046") } sshdPort 2223 rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]] }node { name "O=PartyB,L=New York,C=US" p2pPort 10008 rpcSettings { address("localhost:10009") adminAddress("localhost:10049") } sshdPort 2224 rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]] } }
Side note: This configuration is from the yo cordapp.
Outlining your container cluster
Once you’ve modified the build.gradle you can run the nodes with ./gradlew.
dev@corda ~/D/s/B/yo-cordapp>master> ./gradlew prepareDockerNodes Starting a Gradle Daemon (subsequent builds will be faster)> Task :deployNodesJava Running DockerForm task Deleting /Users/davidawad/Desktop/samples-java/Basic/yo-cordapp/build/nodes Bootstrapping local test network in /Users/davidawad/Desktop/samples-java/Basic/yo-cordapp/build/nodes Generating node directory for PartyA Generating node directory for Notary Generating node directory for PartyB Waiting for all nodes to generate their node-info files... Distributing all node-info files to all nodes Loading existing network parameters... none found Gathering notary identities Generating contract implementations whitelist New NetworkParameters { minimumPlatformVersion=7 notaries=[NotaryInfo(identity=O=Notary, L=London, C=GB, validating=false)] maxMessageSize=10485760 maxTransactionSize=524288000 whitelistedContractImplementations {} eventHorizon=PT720H packageOwnership {} modifiedTime=2020-08-10T19:21:20.827Z epoch=1 } Bootstrapping complete!BUILD SUCCESSFUL in 43s 11 actionable tasks: 11 executed
If you go into the build directory you’ll actually see a completed and working docker-compose file that used your node configuration as a source.
dev@corda ~/D/s/B/yo-cordapp>master>cd build/nodes/ dev@corda ~/D/s/B/y/b/nodes>master>ls Notary/ PartyA/ PartyB/ docker-compose.yml dev@corda ~/D/s/B/y/b/nodes>master>cat docker-compose.yml version: '3' services: [ . . . ] partyb: volumes: - /Users/davidawad/Desktop/samples-java/Basic/yo-cordapp/build/nodes/PartyB/node.conf:/etc/corda/node.conf [ . . . ] environment: - ACCEPT_LICENSE=${ACCEPT_LICENSE} ports: - 10009 - 2224 image: corda/corda-zulu-java1.8-4.5:latest
I’ve clipped out some of the files for legibility but you can see how this all works out.
Running the network
Now we’ll just run the nodes!
We can do that quite easily with a quick docker-compose up and trigger a flow on the corda shell.
dev@corda ~/D/s/B/yo-cordapp>master>docker-compose -f ./build/nodes/docker-compose.yml up
WARNING: The ACCEPT_LICENSE variable is not set. Defaulting to a blank string.
Recreating nodes_partya_1 ...
Recreating nodes_notary_1 ...
Recreating nodes_partyb_1 ...
Once the nodes are running we’ll need to get the docker port number forwarding to port 2224 on the machine.
dev@corda ~/D/s/B/yo-cordapp>master>docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
400636e89ddc corda/corda-zulu-java1.8-4.5:latest "run-corda" 36 seconds ago Up 34 seconds 10200-10202/tcp, 0.0.0.0:32773->2223/tcp, 0.0.0.0:32772->10006/tcp nodes_partya_1
Now that we know the port number, we can use that to connect to the node (in this case the node is running on localhost, hence the 0.0.0.0).
dev@corda ~/D/s/B/y/b/nodes>master>ssh [email protected] -p 32773 The authenticity of host '[0.0.0.0]:32773 ([0.0.0.0]:32773)' can't be established. RSA key fingerprint is SHA256:<you'll see a signature here>. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '[0.0.0.0]:32773' (RSA) to the list of known hosts. Password authentication Password:Welcome to the Corda interactive shell. You can see the available commands by typing 'help'.Mon Aug 10 20:21:50 GMT 2020>>> flow list net.corda.core.flows.ContractUpgradeFlow$Authorise net.corda.core.flows.ContractUpgradeFlow$Deauthorise net.corda.core.flows.ContractUpgradeFlow$Initiate net.corda.examples.yo.flows.YoFlowMon Aug 10 20:21:53 GMT 2020>>>
Once we’re in the Corda shell we have all the normal tools we’d expect and we can get some transactions going.
Mon Aug 10 20:24:54 GMT 2020>>> flow start YoFlow target: Partyb✓ Starting ✓ Creating a new Yo! ✓ Signing the Yo! ✓ Verifying the Yo! ✓ Sending the Yo! Requesting signature by notary service Requesting signature by Notary service Validating response from Notary service ✓ Broadcasting transaction to participants ▶︎ Done Flow completed with result: SignedTransaction(id=A4050165C5795EEF852F94654091954FD8983C3641358BB724CE9D6D16A018B4)Mon Aug 10 20:25:08 GMT 2020>>>
One note worth making is on the ssh port. Typically you’ll need to use docker ps to find the port on your local machine that’s forwarding to the ssh port on the container.
We’re actually working on adjusting dockerform to pin the port numbers to the host machine so you won’t have to find the port number every time.
(stay tuned for that!)
Now that you’ve got your CorDapp running with docker-compose, you’ve got a very robust setup. All you need to do is make your code changes and you can instantly rebuild and iterate on your Corda network.
If you were able to follow all this you’ll have no problems getting your corDapps ready for prime time!
Want to learn more about building awesome blockchain applications on Corda? Be sure to visit https://corda.net, check out our community page to learn how to connect with other Corda developers, and sign up for one of our newsletters for the latest updates.
— David Awad is a Developer Evangelist at R3, an enterprise blockchain software firm working with a global ecosystem of more than 350 participants across multiple industries from both the private and public sectors to develop on Corda, its open-source blockchain platform, and Corda Enterprise, a commercial version of Corda for enterprise usage.
Follow David on Twitter here.