Getting your CordApps running in Docker

August 19, 2020

Getting your CorDapps running in Docker

It’s easier than you think.

Business networks using Corda

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 user1@0.0.0.0 -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.YoFlow
Mon 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>>>
Docker containers “composed”

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 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.


Getting your CordApps running in Docker was originally published in Corda on Medium, where people are continuing the conversation by highlighting and responding to this story.