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

Consensus node Dockerfile for test framework (BFT-398) #57

Merged
merged 31 commits into from
Jan 22, 2024

Conversation

IAvecilla
Copy link
Contributor

What ❔

Add Dockerfile to create a container with a consensus node running in it.

Why ❔

This introduces a Dockerfile for the test framework proposal, enabling the execution of a node in isolation for potential use in future consensus among N nodes in the network. Additionally, a compose file is included for testing purposes, facilitating the simultaneous launch of two nodes that can initiate consensus, each running in a separate container. This file might be replaced in the future with a script that initializes N nodes, allowing for easier management, potentially with Kubernetes or a similar tool.

@IAvecilla IAvecilla marked this pull request as ready for review January 12, 2024 17:12
node/compose.yaml Outdated Show resolved Hide resolved
node/tools/Makefile Outdated Show resolved Hide resolved
node/tools/Makefile Outdated Show resolved Hide resolved
node/Dockerfile Outdated Show resolved Hide resolved
node/Dockerfile Outdated
@@ -0,0 +1,23 @@
# Build Stage
FROM rust:1.72.1 as build
COPY . /node/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a bad idea, because node/target contains the local build artifacts which can be enormous.

Copy link
Collaborator

@pompon0 pompon0 Jan 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be nice to have it rebuilt only if the code changes, so perhaps all the docker-related configuration (and makefiles) would be better off outside of node/ dir?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure if I grasp this correctly. I completely agree that copying the entire node crate into Docker could lead to problems. Would moving everything outside the node directory help alleviate this? Currently, the entire crate is built within a Docker image, and the final image only includes the generated binaries. I attempted to compile everything outside Docker and only copy the target directory, but that requires cross-compilation to x86_64 architecture if run on a Mac or another ARM machine. It's technically feasible, but I'm uncertain if we intend to pursue this, considering potential additional dependencies. Let me know if my understanding is accurate or if there's something I might be overlooking.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend copying everything EXCEPT the target directory to avoid pulling in local artifacts. Alternatively you can try to pull in only files tracked by git (git ls-tree) but I don't know if that's an easy thing to do.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moving your docker-related configs outside of the node directory will prevent rebuilding the image when you change the config. Ideally it would be great to have the "cargo build" command split into building dependencies and the local code, in a way that the image layer with dependencies' artifacts is not rebuilt every time you update the local code (I don't know how to do that though without changing the build system, so this is just a thought for the future).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay got it. I added the node/target dir to the .dockerignore file so it should not be cloned inside the containers. Also I moved every docker related file and the makefile to the root of the project and adapted every script and command to work with the new paths. Let me know if I missed something

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding incorporating dependencies and local code in different Docker layers to cache the initial ones, it seems feasible. However, as you mentioned, this would entail altering the structure of the Cargo.toml. My initial thought on achieving this is to include only external dependencies in the Cargo.toml of the node crate. Then, within the Cargo.toml of each distinct crate, build every member of the workspace. This way, we could initially build all the external dependencies to cache them and subsequently build the actual node code. I plan to explore this in a separate pull request to avoid making unnecessary changes for this one.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi node/ is not a crate, but a workspace. Mind that we shouldn't downgrade the quality of our Cargo.toml files when improving the Dockerfiles, as regular rust development experience is more important here. Other than that feel free to experiment if you have some time.

node/tools/Makefile Outdated Show resolved Hide resolved
node/tools/Makefile Outdated Show resolved Hide resolved
node/compose.yaml Outdated Show resolved Hide resolved
node/Dockerfile Outdated Show resolved Hide resolved
node/Dockerfile Outdated Show resolved Hide resolved
node/tools/README.md Outdated Show resolved Hide resolved
Dockerfile Outdated Show resolved Hide resolved
Copy link
Contributor

@moshababo moshababo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good in the overall!


1. Generate a file named `addresses.txt` in the root directory of the tools crate, containing node addresses in the format `IP:PORT`, with each address on a separate line.
2. Run `make node-configs`. This command will establish a directory named `node-configs` and create a folder for each address listed in the `.txt` file, providing the necessary configuration files for the respective node.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not totally clear that the Makefile is located in a parent directory, and running make commands from this location would fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, with new changes in the directories and overall structure I forgot to update the README. Now it should be updated including the last changes added from this comments. Let me know if it's more clear now.

# Running a test node
# Running a test consensus node

## Local

1. Generate a file named `addresses.txt` in the root directory of the tools crate, containing node addresses in the format `IP:PORT`, with each address on a separate line.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be beneficial to start with a template file which can be seen and just modified.


1. Generate a file named `addresses.txt` in the root directory of the tools crate, containing node addresses in the format `IP:PORT`, with each address on a separate line.
2. Run `make node-configs`. This command will establish a directory named `node-configs` and create a folder for each address listed in the `.txt` file, providing the necessary configuration files for the respective node.
3. Execute `make run-node IP=<NODE_IP>`. The default value for this command would be `127.0.0.1:3054`. Note that running this command will take control of the terminal.
2. Run `make node_configs`. This command will establish a directory named `node-configs` and create a folder for each address listed in the `.txt` file, providing the necessary configuration files for the respective node.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this a bit confusing given the header "Running a test consensus node", while both this step and the previous one are intended for running multiple nodes. Perhaps add some clarification about that.


# Docker commands

docker_node_configs:
Copy link
Contributor

@moshababo moshababo Jan 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command doesn't work from outside the container, as well as being undocumented (also in the /node/tools/ README file).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command shouldn't be important for the user. It is used by Docker in the initial phase of the image building process to generate the configuration. However, I added a comment above the command with this disclaimer.

Makefile Outdated
node:
export RUST_LOG=INFO && cd ${EXECUTABLE_NODE_DIR}/node-configs/${IP} && cargo run -- --database ../../database/${IP}

node_configs:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe nodes_config instead? To clarify that this is not associated with a single node.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I also changed the generated directory where the configs will be.

ipv4_address: 172.12.0.10
node-2:
image: consensus-node
container_name: consensus-node-2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you check the scale feature for docker-compose services, for supporting a dynamic set of nodes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked it, and it was my initial choice. The thing about that feature is that it duplicates the exact same container, and I needed to manually assign IPs to the containers to run the example in a single command where I can write the IPs in the config file, knowing them before running the container. Perhaps I overlooked something, and it's still feasible to use it.

Dockerfile Outdated
@@ -0,0 +1,22 @@
# Build Stage
FROM rust:1.72.1 as build
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rust:latest?


cd $(hostname -i):3054
export RUST_LOG=INFO
../executor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this "../" path is a bit confusing, considering it's located at the top-level folder. Perhaps add some comments that this is to be used within the docker container, or put it within the Dockerfile altogether.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed the file to docker-entrypoint and be more clear about what is its purpose. I added a comment anyways to explain how it is used

rm -rf ${EXECUTABLE_NODE_DIR}/node-configs
rm -rf ${EXECUTABLE_NODE_DIR}/database

clean_docker:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about a command for stopping the container(s), without a full cleanup (which currently also removes the image build)?

COPY Makefile .
WORKDIR /node
RUN apt-get update && apt-get install -y libclang-dev
RUN cargo build --release
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following the discussion you had about caching:
The image build runs line 6 and 7 on every code change, which takes very long time.
I think it's possible to better use layer caching so that at least line 6 won't be repeated (I'm not sure why it does).

As for line 7, as you already mentioned, it should be possible to avoid the reinstalling of dependencies, by only copying Cargo.toml and Cargo.lock files, then create a dummy main.rs (RUN echo "fn main() {println!(\"dummy\")}" > src/main.rs) and do cargo build to cache the dependencies. Then, copy the rest of the source code and build again.

This is not critical for now, but might worth trying.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cargo.toml is a workspace manifest, so it would need to be converted to a crate manifest.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, that was my initial approach for caching external dependencies but since it works as a workspace manifest all the local code would be necessary to build along them.

@brunoffranca brunoffranca merged commit 57f037d into main Jan 22, 2024
4 checks passed
@brunoffranca brunoffranca deleted the standalone_node_dockerfile branch January 22, 2024 16:31
@brunoffranca brunoffranca changed the title Consensus node Dockerfile for test framework Consensus node Dockerfile for test framework (BFT-398) Feb 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants