Dockerized JSON-API

Hi team,

I am building a canton setup in Docker, and therefore wish to create container for json-api, instead of running it as a process.

I use “openjdk:11” docker image, and inside the container, I run this command
java -jar http-json-1.15.0.jar --ledger-host <canton_container_name> --ledger-port 5011 --address 0.0.0.0 --http-port 7575 --allow-insecure-tokens.

It fails, as the json-api keep pinging the canton_container_name:5011.

If I change the name to the actual IP (172.18.0.3) the json-api works well. So I assume my problem is due to the json-api unable to convert the container name into the IP.

However, inside the “json-api” container I can ping canton_container_name which results the right IP (i.e. 172.18.0.3).

Can anyone shed some light on anything wrong in this setting? Or do we have any suggestion in dockerized the json-api in general?

Thanks in advance.

kc

I had a look at this error and I’m a bit surprised. It looks as if domain resolution follows different paths for ping and java. I’ll look into it. For the time being, the only way to get the full error spelled out is to let it run out of attempts (should take around 10 minutes, if you can let the process run in the background for that long). This is not very reasonable, but I just opened a PR to make sure the error message is printed after every failed connection attempt, so that in the future diagnosing connection errors should become a bit easier.

I had a look at the Docker networking documentation but nothing there looks like there should be reasons why domain resolution works for ping but fails for java.

Docker has a bunch of different networking modes, which one are you using? I used a user-defined bridge network for the JSON API in the past and that allowed me to pass in container names to the JSON API.

Also which docker container are you using?

Hi @stefanobaghino-da , just wait for 10 minutes and here is the error message.

16-08-2021 07:55:58.934 [timer-utils] INFO  com.daml.http.LedgerClient$ - Attempting to connect to the ledger 98-alldocker_canton_1:5011
 (attempt 599/600)
16-08-2021 07:55:59.935 [timer-utils] INFO  com.daml.http.LedgerClient$ - Attempting to connect to the ledger 98-alldocker_canton_1:5011
 (attempt 600/600)
16-08-2021 07:55:59.958 [http-json-ledger-api-akka.actor.default-dispatcher-7] ERROR com.daml.http.Main - Cannot start server: Error(Maximum initial connection retry attempts(600) reached,
 Cannot connect to ledger server: java.lang.IllegalArgumentException: Invalid host or port: 98-alldocker_canton_1 5011) , context: {instance_uuid: "e87d45ea-a0b4-4916-ad09-f01b7b61a6f3"}
16-08-2021 07:56:00.088 [shutdownHook1] INFO  com.daml.http.HttpService - Stopping server... , context: {instance_uuid: "e87d45ea-a0b4-4916-ad09-f01b7b61a6f3"}

cheers,
kc

Hi @stefanobaghino-da I just replicate this again.
I just create a openjdk:11 container, and issue java command for json-api.

(1) if I use canton container name in --ledger-host, timeout after 600 attempts and container down.
(2) if I ping the canton container name, the IP address is correctly resolved, and ping is successful.
(3) if I use IP of the canton container in --ledger-host, json-api is started and working well.

Thanks again.
cheers,
kc

Seconding that question. I’ve had working setups using the --link option in the past.

Hi @cocreature I’m using the bridge. In fact my setup I have three containers (1) Canton community, (2) PostgresDB and (3) json-api. All are in the same bridge network. In fact the (1) and (2) are working well, and i’m adding (3) to make a all-docker setup.

hi @Gary_Verhaegen , i just use the image from openjdk:11 and copy http-json-1.15.0.jar from our release. Again if you have tried other container kindly let me know.
cheers,
kc

Could you share your entire process?

  1. All involved Docker files.
  2. Commands used to build the images.
  3. Commands used to start containers.

Here they are.
1 Dockerfile (only one)

FROM openjdk:11
COPY http-json-1.15.0.jar /usr/src
WORKDIR /usr/src
#CMD ["java", "-jar", "http-json-1.15.0.jar", "--ledger-host", "98-alldocker_canton_1", "--ledger-port", "5011", "--address", "0.0.0.0", "--http-port", "7575", "--allow-insecure-tokens"]

I commented out CMD as I’m issuing command directly in the container and perform various tests (using canton community container name and IP).

  1. Command to build the image
docker build -t canton-jsonapi .
  1. Commands used to start containers. Here is the docker-compose.yaml for my three containers.
version: '3'

services:

  cantondb:
    image: "postgres:11"
    hostname: canton-database
    environment:
      - POSTGRES_USER=test-user
      - POSTGRES_PASSWORD=test-password
    shm_size: 256mb
    volumes:
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - 5432:5432

  canton:
    image: digitalasset/canton-community:latest
    hostname: canton
    entrypoint: []
    tty: true
    command: >
      sh -c "
      bin/canton -c $CANTON_CONF --bootstrap /config/bootstrap.canton"
    volumes:
      - ./config:/config:ro
    ports:
      - "5011:5011"
      - "5012:5012"
      - "5018:5018"
      - "5019:5019"
    depends_on:
      - cantondb

  canton-json:
    image: canton-jsonapi:latest
    hostname: canton-jsonapi
    tty: true
    ports:
      - 7575:7575
    depends_on:
      - canton

Thanks.
kc

I’m not that much of an expert on docker-compose, but why is the hostname canton-jsonapi in the docker-compose.yaml file and 98-alldocker_canton_1 in the error logs (and CMD directive)?

It’s been a very long time since I last used docker-compose, and they seem to have added networking magic to it. Without a self-contained example I’m reduced to guessing a bit, but from that compose file (and the compose documentation) it looks like the DNS name you should use from the canton-json container is canton, not 98-alldocker_canton_1, wherever that comes from.

Hi @Gary_Verhaegen , @stefanobaghino-da and @cocreature ,

Thanks for your hints. Yes, it is docker-compose adding this as the container name. After using canton instead of the full name it works.

Interesting enough, when I configure the postgresDB into canton configuration, I have to use that full name. For example here is what I did on canton.conf,

canton {
  participants {
    p1 {
      storage {
        type = postgres
        config {
          dataSourceClass = "org.postgresql.ds.PGSimpleDataSource"
          properties = {
            serverName = "98-alldocker_cantondb_1"
            portNumber = "5432"
            databaseName = "cantondb"
            user = "test-user"
            password = "test-password"
          }
          numThreads = 8
        }
      }

      admin-api {
        port = 5012
        address = 0.0.0.0 // default value if omitted
      }
      ledger-api {
        port = 5011
        address = 0.0.0.0 // default value if omitted
      }
    }
  }
}

And not to mention that the full name is ping-able inside the container. This distracts me in the configuration and troubleshooting.

Once again, thanks a ton!

Have a great day.

cheers,
kc

2 Likes

Glad you got it working!

2 Likes