How to use the Ledger API with the Docker version of Canton?

I’m running the Docker version of Canton, with the Docker flag -p 5011:5011 which is supposed to guarantee that Docker publishes the port 5011 to the host machine, as per the documentation, see https://www.canton.io/docs/stable/user-manual/usermanual/docker.html?highlight=docker#exposing-the-ledger-api-to-the-host-machine.

balazsigyorgy@Orss-MacBook-Air canton-0.18.2 % docker run --rm -it \
   -p 5011:5011 \
   digitalasset/canton \
   --config examples/01-simple-topology/simple-topology.conf \
   --bootstrap examples/01-simple-topology/simple-ping.canton

After I run the above command, something starts running on localhost:5011 (I don’t know what telelpathattack is, but it starts running after the command, and stops after I stop Docker):

balazsigyorgy@Orss-MacBook-Air ~ % lsof -i :5011                                                                                                                           
COMMAND     PID          USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
com.docke 51326 balazsigyorgy   55u  IPv6 0x4806ba5767e0d18f      0t0  TCP *:telelpathattack (LISTEN)

But the Ledger API is not accepting the connection:

balazsigyorgy@Orss-MacBook-Air ~ % daml repl --ledger-host=localhost --ledger-port=5011 /Users/balazsigyorgy/canton-0.18.2/dars/CantonExamples.dar  --import CantonExamples
Exception in thread "main" io.grpc.StatusRuntimeException: UNAVAILABLE: Network closed for unknown reason
	at io.grpc.Status.asRuntimeException(Status.java:533)
	at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:501)
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:426)
	at io.grpc.internal.ClientCallImpl.access$500(ClientCallImpl.java:66)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:689)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$900(ClientCallImpl.java:577)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:751)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:740)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

Where is my mistake?

1 Like

I’m not seeing any obvious issue in your commands; per the Docker documentation this should be working. However, Docker on macOS can be a bit fiddly as it’s really running in a VM but trying to lie about it. I am intrigued by the fact that the lsof entry you have there mentions IPv6 as its underlying connection type.

The first thing that comes to mind is to check the logs of the canton Docker container for any error message. Assuming you’ve done that and would have mentioned any error message from there, the next step would be to remove Canton from the equation and just test whether your Docker network configuration is working as expected.

To do that, you can run the following command:

$ docker run -p 5678:5678 hashicorp/http-echo -text "hello"

and, in another terminal, check that you can talk to it:

$ curl http://localhost:5678
hello

If that works, then at least we know Docker itself is not the issue.

1 Like

Thank you, this works, so Docker seems to be ok:

balazsigyorgy@Orss-MacBook-Air canton-0.18.2 % docker run -p 5678:5678 hashicorp/http-echo -text "hello"
Unable to find image 'hashicorp/http-echo:latest' locally
latest: Pulling from hashicorp/http-echo
86399148984b: Pull complete 
Digest: sha256:ba27d460cd1f22a1a4331bdf74f4fccbc025552357e8a3249c40ae216275de96
Status: Downloaded newer image for hashicorp/http-echo:latest
2020/10/01 14:17:43 Server is listening on :5678
2020/10/01 14:18:10 localhost:5678 172.17.0.1:49614 "GET / HTTP/1.1" 200 6 "curl/7.64.1" 132.6µs

And in the other Terminal:

balazsigyorgy@Orss-MacBook-Air canton-0.18.2 % curl http://localhost:5678
hello

Right, so we’re not off the hook. Shame.

I know nothing of Canton, so I can’t help you further, but I’ll ping the relevant team.

1 Like

I suspect it might be a case of canton only listening on localhost but I’m not sufficiently familiar with Canton to know how to change that.

2 Likes

Thank you!

Hi @gyorgybalazsi,

Yep, we recently updated the default canton configs to only listen on localhost rather than all interface, so it’s not being exposed on the interface docker then exposes to the host. So the docs are incorrect - sorry!

You can adjust this by passing the following property value:

docker run --rm -it \
   -p 5011:5011 \
   digitalasset/canton \
   --config examples/01-simple-topology/simple-topology.conf \
   --bootstrap examples/01-simple-topology/simple-ping.canton \
   -Dcanton.participants.participant1.ledger-api.address=0.0.0.0

If you’re doing much more than this it may make sense to download the canton release from github and make a copy of the example config so you can make your own changes to the file. (remember to mount this to the container and update the config path used for canton accordingly)

I’ll go update the docker docs so reflect this. Thanks for pointing out!

3 Likes

Thank you, David!