From 213d17a9fc0d4bf9c07cb3ac8bd4362349947efe Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Tue, 4 Feb 2025 11:57:22 -0500 Subject: [PATCH 1/4] Add docker image for example MorpheusVM --- Dockerfile | 40 ++++++++++++++++ examples/morpheusvm/scripts/run.sh | 19 ++++---- scripts/build_docker_image.sh | 77 ++++++++++++++++++++++++++++++ scripts/constants.sh | 49 ++++++++++++++++++- 4 files changed, 172 insertions(+), 13 deletions(-) create mode 100644 Dockerfile create mode 100755 scripts/build_docker_image.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..614a670e94 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +# syntax=docker/dockerfile:experimental + +# ============= Setting up base Stage ================ +# AVALANCHEGO_NODE_IMAGE needs to identify an existing node image and should include the tag +ARG AVALANCHEGO_NODE_IMAGE +ARG VM_ID +ARG VM_COMMIT +ARG CURRENT_BRANCH + +# ============= Compilation Stage ================ +FROM --platform=$BUILDPLATFORM golang:1.22.8-bullseye AS builder + +WORKDIR /build + +# Copy avalanche dependencies first (intermediate docker image caching) +# Copy avalanchego directory if present (for manual CI case, which uses local dependency) +COPY go.mod go.sum avalanchego* ./ + +# Download avalanche dependencies using go mod +RUN go mod download && go mod tidy + +# Copy the code into the container +COPY . . + + +# Ensure pre-existing builds are not available for inclusion in the final image +RUN [ -d ./build ] && rm -rf ./build/* || true + +ARG VM_NAME + +WORKDIR /build/examples/$VM_NAME/ + +RUN export VM_COMMIT=$VM_COMMIT && export CURRENT_BRANCH=$CURRENT_BRANCH && ./scripts/build.sh /build/build/vm + +# ============= Cleanup Stage ================ +FROM $AVALANCHEGO_NODE_IMAGE AS builtImage + +# Copy the evm binary into the correct location in the container +ARG VM_ID +COPY --from=builder /build/build/vm /avalanchego/build/plugins/$VM_ID diff --git a/examples/morpheusvm/scripts/run.sh b/examples/morpheusvm/scripts/run.sh index cf9ee0152b..3143468969 100755 --- a/examples/morpheusvm/scripts/run.sh +++ b/examples/morpheusvm/scripts/run.sh @@ -17,25 +17,22 @@ source ../../scripts/constants.sh # shellcheck source=/scripts/common/utils.sh source ../../scripts/common/utils.sh -VERSION=13c08681c17d0790a94ed8c8ef8a3c88f8bb196d - -############################ # build avalanchego # https://github.com/ava-labs/avalanchego/releases HYPERSDK_DIR=$HOME/.hypersdk echo "working directory: $HYPERSDK_DIR" -AVALANCHEGO_PATH=${HYPERSDK_DIR}/avalanchego-${VERSION}/avalanchego -AVALANCHEGO_PLUGIN_DIR=${HYPERSDK_DIR}/avalanchego-${VERSION}/plugins +AVALANCHEGO_PATH=${HYPERSDK_DIR}/avalanchego-${AVALANCHE_VERSION}/avalanchego +AVALANCHEGO_PLUGIN_DIR=${HYPERSDK_DIR}/avalanchego-${AVALANCHE_VERSION}/plugins if [ ! -f "$AVALANCHEGO_PATH" ]; then echo "building avalanchego" CWD=$(pwd) # Clear old folders - rm -rf "${HYPERSDK_DIR}"/avalanchego-"${VERSION}" - mkdir -p "${HYPERSDK_DIR}"/avalanchego-"${VERSION}" + rm -rf "${HYPERSDK_DIR}"/avalanchego-"${AVALANCHE_VERSION}" + mkdir -p "${HYPERSDK_DIR}"/avalanchego-"${AVALANCHE_VERSION}" rm -rf "${HYPERSDK_DIR}"/avalanchego-src mkdir -p "${HYPERSDK_DIR}"/avalanchego-src @@ -43,11 +40,11 @@ if [ ! -f "$AVALANCHEGO_PATH" ]; then cd "${HYPERSDK_DIR}"/avalanchego-src git clone https://github.com/ava-labs/avalanchego.git cd avalanchego - git checkout "${VERSION}" + git checkout "${AVALANCHE_VERSION}" # Build avalanchego ./scripts/build.sh - mv build/avalanchego "${HYPERSDK_DIR}"/avalanchego-"${VERSION}" + mv build/avalanchego "${HYPERSDK_DIR}"/avalanchego-"${AVALANCHE_VERSION}" cd "${CWD}" @@ -62,11 +59,11 @@ fi echo "building morpheusvm" # delete previous (if exists) -rm -f "${HYPERSDK_DIR}"/avalanchego-"${VERSION}"/plugins/qCNyZHrs3rZX458wPJXPJJypPf6w423A84jnfbdP2TPEmEE9u +rm -f "${HYPERSDK_DIR}"/avalanchego-"${AVALANCHE_VERSION}"/plugins/qCNyZHrs3rZX458wPJXPJJypPf6w423A84jnfbdP2TPEmEE9u # rebuild with latest code go build \ --o "${HYPERSDK_DIR}"/avalanchego-"${VERSION}"/plugins/qCNyZHrs3rZX458wPJXPJJypPf6w423A84jnfbdP2TPEmEE9u \ +-o "${HYPERSDK_DIR}"/avalanchego-"${AVALANCHE_VERSION}"/plugins/qCNyZHrs3rZX458wPJXPJJypPf6w423A84jnfbdP2TPEmEE9u \ ./cmd/morpheusvm ############################ diff --git a/scripts/build_docker_image.sh b/scripts/build_docker_image.sh new file mode 100755 index 0000000000..d21d9662e4 --- /dev/null +++ b/scripts/build_docker_image.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# If set to non-empty, prompts the building of a multi-arch image when the image +# name indicates use of a registry. +# +# A registry is required to build a multi-arch image since a multi-arch image is +# not really an image at all. A multi-arch image (also called a manifest) is +# basically a list of arch-specific images available from the same registry that +# hosts the manifest. Manifests are not supported for local images. +# +# Reference: https://docs.docker.com/build/building/multi-platform/ +PLATFORMS="${PLATFORMS:-}" + +# If set to non-empty, the image will be published to the registry. +PUBLISH="${PUBLISH:-}" + +# The name of the VM to build. Defaults to build morpheusvm in examples/morpheusvm/ +VM_NAME=${VM_NAME:-"morpheusvm"} + +# Directory above this script +HYPERSDK_PATH=$( + cd "$(dirname "${BASH_SOURCE[0]}")" + cd .. && pwd +) +VM_PATH=${VM_PATH:-"${HYPERSDK_PATH}/examples/${VM_NAME}"} + +# Load the constants +source "$HYPERSDK_PATH"/scripts/constants.sh + +# WARNING: this will use the most recent commit even if there are un-committed changes present +BUILD_IMAGE_ID=${BUILD_IMAGE_ID:-"${CURRENT_BRANCH}"} + +# buildx (BuildKit) improves the speed and UI of builds over the legacy builder and +# simplifies creation of multi-arch images. +# +# Reference: https://docs.docker.com/build/buildkit/ +DOCKER_CMD="docker buildx build" + +if [[ -n "${PUBLISH}" ]]; then + DOCKER_CMD="${DOCKER_CMD} --push" + + echo "Pushing $DOCKERHUB_REPO:$BUILD_IMAGE_ID" + + # A populated DOCKER_USERNAME env var triggers login + if [[ -n "${DOCKER_USERNAME:-}" ]]; then + echo "$DOCKER_PASS" | docker login --username "$DOCKER_USERNAME" --password-stdin + fi +fi + +# Build a multi-arch image if requested +if [[ -n "${PLATFORMS}" ]]; then + DOCKER_CMD="${DOCKER_CMD} --platform=${PLATFORMS}" +fi + +VM_ID=${VM_ID:-"${DEFAULT_VM_ID}"} +if [[ "${VM_ID}" != "${DEFAULT_VM_ID}" ]]; then + DOCKERHUB_TAG="${VM_ID}-${DOCKERHUB_TAG}" +fi + +# Default to the release image. Will need to be overridden when testing against unreleased versions. +AVALANCHEGO_NODE_IMAGE="${AVALANCHEGO_NODE_IMAGE:-${AVALANCHEGO_IMAGE_NAME}:${AVALANCHE_VERSION}}" + +echo "Building Docker Image: $DOCKERHUB_REPO:$BUILD_IMAGE_ID based off AvalancheGo@$AVALANCHE_VERSION" +${DOCKER_CMD} -t "$DOCKERHUB_REPO:$BUILD_IMAGE_ID" \ + "$HYPERSDK_PATH" -f "$HYPERSDK_PATH/Dockerfile" \ + --build-arg AVALANCHEGO_NODE_IMAGE="$AVALANCHEGO_NODE_IMAGE" \ + --build-arg VM_COMMIT="$VM_COMMIT" \ + --build-arg CURRENT_BRANCH="$CURRENT_BRANCH" \ + --build-arg VM_ID="$VM_ID" \ + --build-arg VM_NAME="$VM_NAME" + +if [[ -n "${PUBLISH}" && $CURRENT_BRANCH == "master" ]]; then + echo "Tagging current image as $DOCKERHUB_REPO:latest" + docker buildx imagetools create -t "$DOCKERHUB_REPO:latest" "$DOCKERHUB_REPO:$BUILD_IMAGE_ID" +fi diff --git a/scripts/constants.sh b/scripts/constants.sh index a2e7bf9257..5e4ca46600 100755 --- a/scripts/constants.sh +++ b/scripts/constants.sh @@ -1,10 +1,55 @@ #!/usr/bin/env bash # Copyright (C) 2023, Ava Labs, Inc. All rights reserved. # See the file LICENSE for licensing terms. +# Ignore warnings about variables appearing unused since this file is not the consumer of the variables it defines. +# shellcheck disable=SC2034 + +set -euo pipefail + +AVALANCHE_VERSION=${AVALANCHE_VERSION:-'13c08681c17d0790a94ed8c8ef8a3c88f8bb196d'} + +# Set the PATHS +GOPATH="$(go env GOPATH)" +DEFAULT_VM_ID="pkEmJQuTUic3dxzg8EYnktwn4W7uCHofNcwiYo458vodAUbY7" + +# Avalabs docker hub +# avaplatform/avalanchego - defaults to local as to avoid unintentional pushes +# You should probably set it - export DOCKER_REPO='avaplatform/subnet-evm' +DOCKERHUB_REPO=${DOCKER_REPO:-"morpheusvm"} + +# Shared between ./scripts/build_docker_image.sh +AVALANCHEGO_IMAGE_NAME="${AVALANCHEGO_IMAGE_NAME:-avaplatform/avalanchego}" + +# set git constants if available, otherwise set to empty string (say building from a release) +if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then + # Current branch + CURRENT_BRANCH=${CURRENT_BRANCH:-$(git describe --tags --exact-match 2>/dev/null || git symbolic-ref -q --short HEAD || git rev-parse --short HEAD || :)} + + # Image build id + # + # Use an abbreviated version of the full commit to tag the image. + # WARNING: this will use the most recent commit even if there are un-committed changes present + VM_COMMIT="$(git rev-parse HEAD || :)" +else + CURRENT_BRANCH="" + VM_COMMIT="" +fi + +# Shared between ./scripts/build_docker_image.sh +DOCKERHUB_TAG=${VM_COMMIT::8} + +echo "Using branch: ${CURRENT_BRANCH}" + +# Static compilation +STATIC_LD_FLAGS='' +if [ "${STATIC_COMPILATION:-}" = 1 ]; then + export CC=musl-gcc + command -v $CC || (echo $CC must be available for static compilation && exit 1) + STATIC_LD_FLAGS=' -extldflags "-static" -linkmode external ' +fi # Set the CGO flags to use the portable version of BLST # # We use "export" here instead of just setting a bash variable because we need # to pass this flag to all child processes spawned by the shell. - -export CGO_CFLAGS="-O -D__BLST_PORTABLE__" +export CGO_CFLAGS="-O2 -D__BLST_PORTABLE__" From 7a239577cf1a083ea8ad604e5212abde2975acee Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Tue, 4 Feb 2025 13:53:26 -0500 Subject: [PATCH 2/4] add license to build docker image script --- scripts/build_docker_image.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/build_docker_image.sh b/scripts/build_docker_image.sh index d21d9662e4..923afbbcd2 100755 --- a/scripts/build_docker_image.sh +++ b/scripts/build_docker_image.sh @@ -1,4 +1,6 @@ #!/usr/bin/env bash +# Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +# See the file LICENSE for licensing terms. set -euo pipefail From 1c9fa72e0407200648e2a5d0c26b606b9642c9f6 Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Tue, 4 Feb 2025 14:30:26 -0500 Subject: [PATCH 3/4] Add CI job for building docker image --- .github/workflows/hypersdk-ci.yml | 13 +++++++++++++ scripts/build_docker_image.sh | 4 ++-- scripts/constants.sh | 11 +++-------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/workflows/hypersdk-ci.yml b/.github/workflows/hypersdk-ci.yml index cc4abc2ca6..614cdb6ec2 100644 --- a/.github/workflows/hypersdk-ci.yml +++ b/.github/workflows/hypersdk-ci.yml @@ -26,6 +26,19 @@ jobs: - shell: bash run: scripts/tests.clean.sh + build_image: + name: Image build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install qemu (required for cross-platform builds) + run: | + sudo apt update + sudo apt -y install qemu-system qemu-user-static + - name: Build MorpheusVM Docker Image + shell: bash + run: bash -x scripts/build_docker_image.sh + hypersdk-lint: runs-on: ubuntu-latest steps: diff --git a/scripts/build_docker_image.sh b/scripts/build_docker_image.sh index 923afbbcd2..69bad8774e 100755 --- a/scripts/build_docker_image.sh +++ b/scripts/build_docker_image.sh @@ -62,9 +62,9 @@ if [[ "${VM_ID}" != "${DEFAULT_VM_ID}" ]]; then fi # Default to the release image. Will need to be overridden when testing against unreleased versions. -AVALANCHEGO_NODE_IMAGE="${AVALANCHEGO_NODE_IMAGE:-${AVALANCHEGO_IMAGE_NAME}:${AVALANCHE_VERSION}}" +AVALANCHEGO_NODE_IMAGE="${AVALANCHEGO_NODE_IMAGE:-${AVALANCHEGO_IMAGE_NAME}:${AVALANCHE_DOCKER_VERSION}}" -echo "Building Docker Image: $DOCKERHUB_REPO:$BUILD_IMAGE_ID based off AvalancheGo@$AVALANCHE_VERSION" +echo "Building Docker Image: $DOCKERHUB_REPO:$BUILD_IMAGE_ID based off AvalancheGo@$AVALANCHE_DOCKER_VERSION" ${DOCKER_CMD} -t "$DOCKERHUB_REPO:$BUILD_IMAGE_ID" \ "$HYPERSDK_PATH" -f "$HYPERSDK_PATH/Dockerfile" \ --build-arg AVALANCHEGO_NODE_IMAGE="$AVALANCHEGO_NODE_IMAGE" \ diff --git a/scripts/constants.sh b/scripts/constants.sh index 5e4ca46600..2edca81186 100755 --- a/scripts/constants.sh +++ b/scripts/constants.sh @@ -7,6 +7,9 @@ set -euo pipefail AVALANCHE_VERSION=${AVALANCHE_VERSION:-'13c08681c17d0790a94ed8c8ef8a3c88f8bb196d'} +# Optionally specify a separate version of AvalancheGo for building docker images +# Added to support the case there's no such docker image for the specified commit of AvalancheGo +AVALANCHE_DOCKER_VERSION=${AVALANCHE_DOCKER_VERSION:-'v1.12.2'} # Set the PATHS GOPATH="$(go env GOPATH)" @@ -40,14 +43,6 @@ DOCKERHUB_TAG=${VM_COMMIT::8} echo "Using branch: ${CURRENT_BRANCH}" -# Static compilation -STATIC_LD_FLAGS='' -if [ "${STATIC_COMPILATION:-}" = 1 ]; then - export CC=musl-gcc - command -v $CC || (echo $CC must be available for static compilation && exit 1) - STATIC_LD_FLAGS=' -extldflags "-static" -linkmode external ' -fi - # Set the CGO flags to use the portable version of BLST # # We use "export" here instead of just setting a bash variable because we need From 3d857f718b819e9a71db92fd74b8275e266b5937 Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Thu, 6 Feb 2025 10:31:21 -0500 Subject: [PATCH 4/4] Clean up Dockerfile + add dockerignore --- .dockerignore | 13 +++++++++++++ Dockerfile | 14 +++----------- 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..5e5b5f07e9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +.ci +.github +.gitignore +.golangci.yml + +.idea +.vscode + +LICENSE +*.md + +# Ignore all dockerfiles not just the main one +Dockerfile* diff --git a/Dockerfile b/Dockerfile index 614a670e94..c053651956 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,24 +12,16 @@ FROM --platform=$BUILDPLATFORM golang:1.22.8-bullseye AS builder WORKDIR /build -# Copy avalanche dependencies first (intermediate docker image caching) -# Copy avalanchego directory if present (for manual CI case, which uses local dependency) -COPY go.mod go.sum avalanchego* ./ - -# Download avalanche dependencies using go mod -RUN go mod download && go mod tidy - # Copy the code into the container COPY . . - -# Ensure pre-existing builds are not available for inclusion in the final image -RUN [ -d ./build ] && rm -rf ./build/* || true - ARG VM_NAME WORKDIR /build/examples/$VM_NAME/ +# Ensure pre-existing builds are not available for inclusion in the final image +RUN [ -d ./build ] && rm -rf ./build/* || true + RUN export VM_COMMIT=$VM_COMMIT && export CURRENT_BRANCH=$CURRENT_BRANCH && ./scripts/build.sh /build/build/vm # ============= Cleanup Stage ================