Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: dockerized deployment #386

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -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
22 changes: 12 additions & 10 deletions Dockerfiles/Dockerfile.dela
Original file line number Diff line number Diff line change
@@ -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 []
7 changes: 7 additions & 0 deletions Dockerfiles/Dockerfile.frontend
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
96 changes: 33 additions & 63 deletions README.docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -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=<path to Docker Compose file>
./scripts/run_docker.sh <subcommand>
```

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=<path to Docker 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.
128 changes: 128 additions & 0 deletions scripts/run_docker.sh
Original file line number Diff line number Diff line change
@@ -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
Loading