This folder contains scripts and utilities to build and run docker images for the SCITT application.
To build a docker image, run the following command from the root of the repository:
./docker/build.sh
To run a docker container using a built image, run the following command from the root of the repository:
./docker/run-dev.sh
Both scripts accept different variables for customization. Please refer to the corresponding scripts for the full list of available variables to use.
run-dev.sh starts a single node by default. Set NODE_COUNT to a value greater
than 1 and it delegates to run-dev-cluster.sh, which starts a CCF network of
that many nodes, opens the service, and transitions the joining nodes to
Trusted via a governance proposal:
NODE_COUNT=3 ./docker/run-dev.sh
Node i listens for client requests on https://localhost:$((CCF_PORT + 1 + i)),
so the default 3-node cluster is served by nodes on ports 8001, 8002 and 8003.
Every node is configured to redirect write requests to the primary, so clients
may submit to any of them. All containers use --network=host, matching the
single-node script.
Clients are not expected to address the nodes directly. An nginx container
listens on CCF_PORT (8000 by default) and distributes connections over the
nodes in round robin order, which is how the service is fronted in production:
client --> localhost:8000 (nginx) --> localhost:8001 node0
--> localhost:8002 node1
--> localhost:8003 node2
Points worth knowing:
stream
module and does not terminate TLS.redirections.to_primary is NodeByRole), so the client’s second attempt
goes directly to the primary rather than back through the load balancer.LB_FAIL_TIMEOUT and the connection is retried against the next node.The generated configuration is written to workspace/nginx.conf, so it can be
inspected or edited before a rerun.
The functional tests talk to whatever CCF_URL points at, so they can be run
against the cluster by setting NODE_COUNT:
DOCKER=1 NODE_COUNT=3 ./run_functional_tests.sh
CCF_URL then resolves to the load balancer, so the suite exercises requests
being spread over the nodes and writes being redirected to the primary, rather
than a single node serving everything.
Containers and the shared volume are removed when the script exits. Set
KEEP_CLUSTER=1 to leave the cluster running instead; the script then prints the
docker rm/docker volume rm command needed to tear it down later.
Note: joining nodes are configured with
join.fetch_recent_snapshotset tofalse(override withJOIN_FROM_SNAPSHOT=true), so they replay the whole ledger from the first transaction instead of bootstrapping from a snapshot of the primary. A node which joins from a snapshot holds no ledger below the snapshot seqno, and cannot serve historical queries such asGET /entries/{txid}, because the receipt lookup needs ledger secrets derived by reading back to seqno 1; requests to that node would poll with 302 forever. Replaying the ledger is cheap on a development cluster, keeps every node able to serve every read, and removes the need for theSnapshotReadandLedgerChunkReadoperator features on the client interface.