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

Lightnode docker #726

Merged
merged 23 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 21 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ coverage.*

contracts/broadcast

lightnode/docker/build-info.txt
lightnode/docker/args.sh

.idea
30 changes: 30 additions & 0 deletions lightnode/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
SHELL := /bin/bash

# Clean the light node build files.
clean:
rm -rf ./bin

# Build the light node.
build: clean
go mod tidy
go build -o ./bin/lnode ./main

# Run the light node.
run: build
./bin/lnode

# Delete the docker images for the light node.
clean-docker:
./docker/clean.sh

# Build the docker images for the light node.
build-docker:
./docker/build.sh

# Run the docker image for the light node.
run-docker:
./docker/run.sh

# Open an interactive bash shell inside the light node docker container. Useful for debugging issues with the image.
debug-docker:
./docker/debug.sh
69 changes: 69 additions & 0 deletions lightnode/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
FROM golang:1.21.12-bookworm AS base

# The url of the git repository to clone.
ARG GIT_URL
# The branch or commit to check out.
ARG BRANCH_OR_COMMIT

# Install core dependencies
RUN apt update
RUN apt install -y git build-essential bash

# Set up lnode user
RUN useradd -m -s /bin/bash lnode
USER lnode
WORKDIR /home/lnode
# Remove default crud
RUN rm .bashrc
RUN rm .bash_logout
RUN rm .profile

# Clone eigenda repository
RUN git clone $GIT_URL eigenda
WORKDIR /home/lnode/eigenda
RUN git checkout $BRANCH_OR_COMMIT
WORKDIR /home/lnode

# Download all go dependencies.
# This is done as a separate step to avoid repeat work every time the latest commit in the branch is updated.
WORKDIR /home/lnode/eigenda/lightnode
RUN go mod download
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think a worthwhile optimization would be the following sequence:

  1. copy go.mod
  2. Run go mod download
  3. Copy the remainder of source
  4. Run build

This would prevent having to redownload the go modules every time the source changes (as long as modules don't change)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Very good suggestion. Change made.

WORKDIR /home/lnode

# Copy a file containing build information. Useful for detective work on an otherwise unlabelled image.
# This is also useful for forcing docker to invalidate caches when a target branch is updated.
WORKDIR /home/lnode/eigenda/lightnode
COPY --chown=lnode build-info.txt /home/lnode
WORKDIR /home/lnode

# Just in case we are tracking the latest commit in a branch, pull again. This is a no-op if the target is a commit sha.
WORKDIR /home/lnode/eigenda
RUN git pull
WORKDIR /home/lnode

# Build the light node binary.
WORKDIR /home/lnode/eigenda/lightnode
RUN make build
WORKDIR /home/lnode

# In order to equip this image with a shell for debugging,
# swap out the "FROM scratch" below with "FROM golang:1.21.12-bookworm"
FROM scratch AS final

# Copy over files needed for lnode user.
COPY --from=base /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=base /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=base /etc/passwd /etc/passwd
COPY --from=base /etc/group /etc/group

USER lnode
WORKDIR /home/lnode

# Copy the executable binary.
COPY --from=base /home/lnode/eigenda/lightnode/bin/lnode /home/lnode/lnode

# Copy the build info file.
COPY --from=base /home/lnode/build-info.txt /home/lnode/build-info.txt

# Run the light node when the container starts.
CMD ["/home/lnode/lnode"]
40 changes: 40 additions & 0 deletions lightnode/docker/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash

# The location where this script can be found.
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd "${SCRIPT_DIR}"

source default-args.sh
# Create a file called args.sh to override the default values of GIT_URL and BRANCH_OR_COMMIT.
source args.sh

echo "git url: ${GIT_URL}"
echo "branch or commit: ${BRANCH_OR_COMMIT}"

# Create a file with information about this build. This file will be copied into the docker image.
rm build-info.txt 2> /dev/null || true
touch build-info.txt
echo "git URL: ${GIT_URL}" >> build-info.txt

# This will return an empty string if a git sha is provided. Will return sha and branch name if a branch is provided.
COMMIT_SHA=$(git ls-remote $GIT_URL $BRANCH_OR_COMMIT)
if [ -z "$COMMIT_SHA" ]; then
echo "target: ${BRANCH_OR_COMMIT}" >> build-info.txt
else
echo "target: ${COMMIT_SHA}" >> build-info.txt
fi

echo "docker build commit: $(git rev-parse HEAD)" >> build-info.txt

# Add the --no-cache flag to force a rebuild.
# Add the --progress=plain flag to show verbose output during the build.

docker build \
--build-arg="GIT_URL=${GIT_URL}" \
--build-arg="BRANCH_OR_COMMIT=${BRANCH_OR_COMMIT}" \
-f Dockerfile \
--tag lnode:latest \
.

# Don't leave trash on the filesystem.
rm build-info.txt 2> /dev/null || true
5 changes: 5 additions & 0 deletions lightnode/docker/clean.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash

# Cleans the docker image and all cached steps.
docker image rm lnode 2> /dev/null || true
docker builder prune -f
13 changes: 13 additions & 0 deletions lightnode/docker/debug.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash

# Starts the container with an interactive bash shell. This is useful for debugging the container.

# Do setup for the data directory. This is a directory where data that needs
# to persist in-between container runs is stored.
source ./docker/setup-data-dir.sh

docker container run \
--mount "type=bind,source=${DATA_PATH},target=/home/lnode/data" \
--rm \
-it \
lnode bash
11 changes: 11 additions & 0 deletions lightnode/docker/default-args.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Default arguments for building the docker image.
# To override these values locally, create a file named `args.sh` in the same directory. 'args.sh' is ignored by git.

# The location of the code to clone.
export GIT_URL=https://github.com/Layr-Labs/eigenda.git

# The name of the branch or the commit sha to clone.
export BRANCH_OR_COMMIT=master
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it make sense to use the commit that is currently checked out? Curious about the thought process here

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 open to that idea, but we should weigh pros and cons.

This build process clones the repo into the docker image, as opposed to using the copy on the host file system. This adds extra overhead. The reason I took this step was that I wanted to avoid uncommitted local changes accidentally making their way into the resulting docker file, as well as requiring an explicit choice when it comes to choosing which version to build. But there is certainly additional friction to the developer in doing it this way. Let's discuss.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Per our discussion, I've changed this so that it instead builds against the code that is checked out locally (as opposed to cloning the code inside the docker file).


# The location on the host file system where light node data will be stored.
export DATA_PATH=~/.lnode-data
12 changes: 12 additions & 0 deletions lightnode/docker/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

# Starts the container and runs the light node.

# Do setup for the data directory. This is a directory where data that needs
# to persist in-between container runs is stored.
source ./docker/setup-data-dir.sh

docker run \
--rm \
--mount "type=bind,source=${DATA_PATH},target=/home/lnode/data" \
lnode
13 changes: 13 additions & 0 deletions lightnode/docker/setup-data-dir.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash

# Sets up the data directory for the light node container.

# Default arguments.
source docker/default-args.sh
# Local overrides for arguments.
source docker/args.sh

# Create the data directory if it doesn't exist.
mkdir -p $DATA_PATH

echo "Using data directory $DATA_PATH"
8 changes: 8 additions & 0 deletions lightnode/main/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package main

import "fmt"

// main is the entrypoint for the light node.
func main() {
fmt.Println("Hello world")
}
Loading