From 4b61aa4236c3ed16dbcaccacdd1a295f88dd1f92 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Wed, 3 Apr 2024 15:48:23 +0200 Subject: [PATCH] feat: dockerized deployment, including helper script to set up/tear down Docker development environment --- .env.example | 21 ++++++ Dockerfiles/Dockerfile.dela | 22 +++--- Dockerfiles/Dockerfile.frontend | 7 ++ README.docker.md | 96 ++++++++---------------- scripts/run_docker.sh | 128 ++++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+), 73 deletions(-) create mode 100644 .env.example create mode 100755 scripts/run_docker.sh diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..efbaf54ca --- /dev/null +++ b/.env.example @@ -0,0 +1,21 @@ +# This is an example .env file with default passwords and private keys. +# Do not use this in production or with any public-facing ports! +BACKEND_HOST=backend # name of the 'backend' container +BACKEND_PORT=5000 # port of the 'backend' container +COMPOSE_FILE=./docker-compose/docker-compose.yml # Docker Compose configuration file to use +DATABASE_HOST=db # name of the PostgreSQL container +DATABASE_PASSWORD=Ohw0phoa # choose any PostgreSQL password +DATABASE_PORT=5432 # port of the PostgreSQL container +DATABASE_USERNAME=dvoting +DB_PATH=dvoting # LMDB database path +DELA_PROXY_URL=http://172.19.44.254:8080 # IP and port of one of the DELA containers +FRONT_END_URL=http://127.0.0.1:3000 # the automated frontend tests expect this value do not change it +NODEPORT=2000 # DELA node port +# For public-facing services and production, this key needs to be changed! +PRIVATE_KEY=6aadf480d068ac896330b726802abd0da2a5f3824f791fe8dbd4cd555e80b809 +PROXYPORT=8080 # DELA proxy port +PUBLIC_KEY=3e5fcaed4c5d79a8eccceeb087ee0a13b8f91d917ed62017a9cd28e13b228389 +REACT_APP_DEV_LOGIN=true # debugging admin login /!\ disable in production /!\ +REACT_APP_RANDOMIZE_VOTE_ID=true # randomize voter ID for debugging /!\ disable in production /!\ +REACT_APP_SCIPER_ADMIN=123456 # debugging admin ID /!\ disable in production /!\ +SESSION_SECRET=kaibaaF9 # choose any secret diff --git a/Dockerfiles/Dockerfile.dela b/Dockerfiles/Dockerfile.dela index 5535c8dbd..2f93c5ff5 100644 --- a/Dockerfiles/Dockerfile.dela +++ b/Dockerfiles/Dockerfile.dela @@ -1,17 +1,19 @@ FROM golang:1.20.6-bookworm AS base RUN apt-get update && apt-get install git -# make sure we're using the same head as d-voting -RUN git clone https://github.com/c4dt/dela.git -WORKDIR /go/dela/cli/crypto -RUN go install WORKDIR /go/d-voting +COPY go.mod . +COPY go.sum . +RUN go mod download COPY . . - -FROM base AS build -COPY --from=base /go/dela . -COPY --from=base /go/d-voting . +ENV GOCACHE=/root/.cache/go-build WORKDIR /go/d-voting/cli/dvoting -RUN go build -ENV PATH=/go/dela/cli/crypto:/go/d-voting/cli/dvoting:${PATH} +RUN --mount=type=cache,target="/root/.cache/go-build" go install +# make sure we're using the same head as d-voting +RUN --mount=type=cache,target="/root/.cache/go-build" cd $( go list -f '{{.Dir}}' go.dedis.ch/dela )/cli/crypto && go install + +FROM golang:1.20.6-bookworm AS build +WORKDIR /usr/local/bin +COPY --from=base /go/bin/crypto . +COPY --from=base /go/bin/dvoting . ENTRYPOINT ["/bin/bash", "-c", "dvoting --config /data/node start --postinstall --proxyaddr :$PROXYPORT --proxykey $PROXYKEY --listen tcp://0.0.0.0:2000 --public $PUBLIC_URL --routing tree --noTLS"] CMD [] diff --git a/Dockerfiles/Dockerfile.frontend b/Dockerfiles/Dockerfile.frontend index 77376ff36..46457046d 100644 --- a/Dockerfiles/Dockerfile.frontend +++ b/Dockerfiles/Dockerfile.frontend @@ -5,5 +5,12 @@ ENV REACT_APP_NOMOCK=on WORKDIR /web/frontend COPY ../web/frontend . RUN npm install +ARG REACT_APP_VERSION=unknown +ARG REACT_APP_BUILD=unknown +ARG REACT_APP_BUILD_TIME=after_2024_03 +ENV REACT_APP_VERSION=$REACT_APP_VERSION +ENV REACT_APP_BUILD=$REACT_APP_BUILD +ENV REACT_APP_BUILD_TIME=$REACT_APP_BUILD_TIME + ENTRYPOINT ["npm"] CMD ["start"] diff --git a/README.docker.md b/README.docker.md index bc66a08f9..dce48973d 100644 --- a/README.docker.md +++ b/README.docker.md @@ -8,96 +8,66 @@ The files related to the Docker environment can be found in * `Dockerfiles/` (Dockerfiles) * `scripts/` (helper scripts) -You also need to either create a `.env` file in the project's root -or point to another environment file using the `--env-file` flag -when running `docker compose`. +### Setup -The environment file needs to contain +It is recommended to use the `run_docker.sh` helper script for setting up and +tearing down the environment as it handles all the necessary intermediary steps +to have a working D-Voting application. -``` -DELA_NODE_URL=http://172.19.44.254:8080 -DATABASE_USERNAME=dvoting -DATABASE_PASSWORD=XXX # choose any PostgreSQL password -DATABASE_HOST=db -DATABASE_PORT=5432 -DB_PATH=dvoting # LMDB database path -FRONT_END_URL=http://127.0.0.1:3000 -BACKEND_HOST=backend -BACKEND_PORT=5000 -SESSION_SECRET=XXX # choose any secret -PUBLIC_KEY=XXX # public key of pre-generated key pair -PRIVATE_KEY=XXX # private key of pre-generated key pair -PROXYPORT=8080 -NODEPORT=2000 # DELA node port -``` +This script needs to be executed at the project's root. -For the `PUBLIC_KEY` and `PRIVATE_KEY`, you need to run the following commands: +To set up the environment: -```bash -cd web/backend -npm ci -npm run keygen +``` +./scripts/run_docker.sh ``` -And then copy the two lines to the `.env` file. - -There are two Docker Compose file you may use: +This will run the subcommands: -* `docker-compose/docker-compose.yml` for the preprod version, or -* `docker-compose/docker-compose.debug.yml` for the development/debugging version +- `setup` which will build the images and start the containers +- `init_dela` which will initialize the DELA network +- `local_admin` which will add local admin accounts for testing and debugging +- `local_login` which will set a local cookie that allows for interacting w/ the API via command-line +- `add_proxies` which will set up the DELA node proxies -You run +Each of these subcommands can also be run by invoking the script w/ the subcommand: ``` -export COMPOSE_FILE= +./scripts/run_docker.sh ``` -The preprod version will create an environment without any debugging tools that's as close as possible to a real environment. -It is meant to be used to test the `main` branch before deploying it to production. Use the development/debugging version -for setting up your local development environment. +/!\ The `init_dela` subcommand must only be run exactly **once**. -Run +To tear down the environment: ``` -docker compose build -docker compose up +./scripts/run_docker.sh teardown ``` -to set up the environment. - -/!\ Any subsequent `docker compose` commands must be run with `COMPOSE_FILE` being -set to the Docker Compose file that defines the current environment. - -Use +This will: -``` -docker compose down -``` +- remove the local cookie +- stop and remove the containers and their attached volumes +- remove the images -to shut off, and +/!\ This command is meant to reset your environment. If you want to stop one or more +containers, use the appropriate `docker compose` commands (see below for using the correct `docker-compose.yml`). -``` -docker compose down -v -``` +### Docker environment -to delete the volumes and reset your instance. +There are two Docker Compose file you may use: -## Post-install commands +* `docker-compose/docker-compose.yml` (recommended, default in `.env.example` and `run_docker.sh`), or +* `docker-compose/docker-compose.debug.yml`, which contains some additional debugging tools -To set up the DELA network, go to `scripts/` and run +To run `docker compose` commands w/ the right `docker-compose.yml`, you need to either run ``` -./init_dela.sh +export COMPOSE_FILE= ``` -/!\ This script uses `docker compose` as well, so make sure that the `COMPOSE_FILE` variable is -set to the right value. - -To set up the permissions, run +or ``` -docker compose exec backend npx cli addAdmin --sciper XXX -docker compose down && docker compose up -d +source .env ``` - -to add yourself as admin and clear the cached permissions. diff --git a/scripts/run_docker.sh b/scripts/run_docker.sh new file mode 100755 index 000000000..c256ff141 --- /dev/null +++ b/scripts/run_docker.sh @@ -0,0 +1,128 @@ +#!/bin/bash -e + +# The script must be called from the root of the github tree, else it returns an error. +# This script currently only works on Linux due to differences in network management on Windows/macOS. + +if [[ $(git rev-parse --show-toplevel) != $(pwd) ]]; then + echo "ERROR: This script must be started from the root of the git repo"; + exit 1; +fi + +if [[ ! -f .env ]]; then + cp .env.example .env +fi + +source ./.env; +export COMPOSE_FILE=${COMPOSE_FILE:-./docker-compose/docker-compose.yml}; + + +function setup() { + docker compose build; + docker compose up -d; +} + +function teardown() { + rm -f cookies.txt; + docker compose down -v; + docker image rm ghcr.io/c4dt/d-voting-frontend:latest ghcr.io/c4dt/d-voting-backend:latest ghcr.io/c4dt/d-voting-dela:latest; +} + +function init_dela() { + LEADER=dela-worker-0; + echo "$LEADER is the initial leader node"; + + echo "add nodes to the chain"; + MEMBERS="" + for node in $(seq 0 3); do + MEMBERS="$MEMBERS --member $(docker compose exec dela-worker-$node /bin/bash -c 'LLVL=error dvoting --config /data/node ordering export')"; + done + docker compose exec "$LEADER" dvoting --config /data/node ordering setup $MEMBERS; + + echo "authorize signers to handle access contract on each node"; + for signer in $(seq 0 3); do + IDENTITY=$(docker compose exec "dela-worker-$signer" crypto bls signer read --path /data/node/private.key --format BASE64_PUBKEY); + for node in $(seq 0 3); do + docker compose exec "dela-worker-$node" dvoting --config /data/node access add --identity "$IDENTITY"; + done + done + + echo "update the access contract"; + for node in $(seq 0 3); do + IDENTITY=$(docker compose exec dela-worker-"$node" crypto bls signer read --path /data/node/private.key --format BASE64_PUBKEY); + docker compose exec "$LEADER" dvoting --config /data/node pool add\ + --key /data/node/private.key\ + --args go.dedis.ch/dela.ContractArg\ + --args go.dedis.ch/dela.Access\ + --args access:grant_id\ + --args 45564f54\ + --args access:grant_contract\ + --args go.dedis.ch/dela.Evoting \ + --args access:grant_command\ + --args all\ + --args access:identity\ + --args $IDENTITY\ + --args access:command\ + --args GRANT + done +} + + +function local_admin() { + echo "adding local user $REACT_APP_SCIPER_ADMIN to admins"; + docker compose exec backend npx cli addAdmin --sciper "$REACT_APP_SCIPER_ADMIN"; + docker compose exec backend npx cli addAdmin --sciper 987654; + docker compose restart backend; +} + + +function local_login() { + if ! [ -f cookies.txt ]; then + echo "getting dummy login cookie"; + curl -k "$FRONT_END_URL/api/get_dev_login/$REACT_APP_SCIPER_ADMIN" -c cookies.txt -o /dev/null -s; + fi +} + +function add_proxies() { + + echo "adding proxies"; + + for node in $(seq 0 3); do + echo "adding proxy for node dela-worker-$node"; + curl -sk "$FRONT_END_URL/api/proxies/" -X POST -H 'Content-Type: application/json' -b cookies.txt --data "{\"NodeAddr\":\"grpc://dela-worker-$node:$NODEPORT\",\"Proxy\":\"http://172.19.44.$((254 - node)):$PROXYPORT\"}"; + done +} + +case "$1" in + +setup) + setup; + ;; + +init_dela) + init_dela; + ;; + +teardown) + teardown; + exit + ;; + +local_admin) + local_admin; + ;; + +add_proxies) + local_login; + add_proxies; + ;; + +*) + setup; + sleep 16; # give DELA nodes time to start up + init_dela; + local_admin; + sleep 8; # give backend time to restart + local_login; + add_proxies; + ;; +esac