diff --git a/dockerfiles/README.md b/dockerfiles/README.md new file mode 100644 index 00000000000..01bcddd6d8c --- /dev/null +++ b/dockerfiles/README.md @@ -0,0 +1,117 @@ +# The HELM Docker Image + +This guide outlines how to build, tag, and test the HELM Docker image. Start by +navigating to a local clone of the HELM repository, and then navigating to it: + +```bash +git clone https://github.com/stanford-crfm/helm.git ~/code/helm +cd ~/code/helm/ +``` + +### Building the Image + +To ensure reproducibility, specify the versions of HELM, `uv`, and Python via +build arguments. This guarantees that builds are consistent across machines and +environments. + +Run docker build with build args to specify exactly which variant of HELM we +are building and in which environment it will run. This ensures +reproducibility. + +```bash +# Determine version of helm, uv, and python to use +export HELM_GIT_HASH=$(git rev-parse --short=12 HEAD) +export UV_VERSION=0.8.4 +export PYTHON_VERSION=3.10 + +# Build the image with version-specific tags +DOCKER_BUILDKIT=1 docker build --progress=plain \ + -t helm:${HELM_GIT_HASH}-uv${UV_VERSION}-python${PYTHON_VERSION} \ + --build-arg PYTHON_VERSION=$PYTHON_VERSION \ + --build-arg UV_VERSION=$UV_VERSION \ + --build-arg HELM_GIT_HASH=$HELM_GIT_HASH \ + -f ./dockerfiles/helm.dockerfile . +``` + + +After building, tag the image with shorter aliases for convenience: + +```bash +# Add concise tags for easier reuse +docker tag helm:${HELM_GIT_HASH}-uv${UV_VERSION}-python${PYTHON_VERSION} helm:latest-uv${UV_VERSION}-python${PYTHON_VERSION} +docker tag helm:${HELM_GIT_HASH}-uv${UV_VERSION}-python${PYTHON_VERSION} helm:latest-python${PYTHON_VERSION} +docker tag helm:${HELM_GIT_HASH}-uv${UV_VERSION}-python${PYTHON_VERSION} helm:latest +``` + + +### Smoke Testing the Image + +Perform basic sanity checks to ensure: + +* The GPU is accessible (if available) + +```bash +docker run --gpus=all -it helm:latest nvidia-smi +``` + +* All CLI entry points are wired up correctly + +```bash +docker run --gpus=all -it helm:latest helm-run --help +docker run --gpus=all -it helm:latest helm-summarize --help +docker run --gpus=all -it helm:latest helm-server --help +``` + +### Unit Tests + +This Docker image is designed as a development container, so you can also +verify the HELM installation by running the unit tests inside the image. + + +```bash +docker run --rm --gpus=all \ + -it helm:latest \ + pytest +``` + +### End-to-End Benchmark Test + +For a more robust validation—and to demonstrate typical usage—you can run a +small benchmark and persist results using a shared host volume. + +Create a shared directory on the host for output persistence + +```bash +mkdir -p ./shared_directory +``` + +Run a benchmark: + +```bash +docker run --rm --gpus=all \ + -v $PWD/shared_directory:/mnt/shared_directory \ + --workdir /mnt/shared_directory \ + -it helm:latest \ + helm-run --run-entries mmlu:subject=philosophy,model=openai/gpt2 --suite my-suite --max-eval-instances 10 +``` + +Summarize the results: + +```bash +docker run --rm --gpus=all \ + -v $PWD/shared_directory:/mnt/shared_directory \ + --workdir /mnt/shared_directory \ + -it helm:latest \ + helm-summarize --suite my-suite +``` + +Start a web server to view the results: + +```bash +docker run --rm --gpus=all \ + -v $PWD/shared_directory:/mnt/shared_directory \ + --workdir /mnt/shared_directory \ + -p 8000:8000 \ + -it helm:latest \ + helm-server --suite my-suite +``` diff --git a/dockerfiles/helm.dockerfile b/dockerfiles/helm.dockerfile new file mode 100644 index 00000000000..c12555855a8 --- /dev/null +++ b/dockerfiles/helm.dockerfile @@ -0,0 +1,181 @@ +# syntax=docker/dockerfile:1.5 +FROM nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04 + + +# ------------------------------------ +# Step 1: Install System Prerequisites +# ------------------------------------ + +RUN --mount=type=cache,target=/var/cache/apt \ + --mount=type=cache,target=/var/lib/apt/lists < $DOWNLOAD_PATH +report_bad_checksum(){ + echo "Got unexpected checksum" + sha256sum "$DOWNLOAD_PATH" + exit 1 +} +echo "$EXPECTED_SHA256 $DOWNLOAD_PATH" | sha256sum --check || report_bad_checksum +# Run the install script +bash /bootstrap/uv-install-v${UV_VERSION}.sh +EOF + + +# ------------------------------------------ +# Step 3: Setup a Python virtual environment +# ------------------------------------------ +# This step mirrors a normal virtualenv development environment inside the +# container, which can prevent subtle issues due when running as root inside +# containers. + +# Control which python version we are using +ARG PYTHON_VERSION=3.10 + +ENV UV_COMPILE_BYTECODE=1 + +ENV PIP_ROOT_USER_ACTION=ignore + +RUN --mount=type=cache,target=/root/.cache <> $HOME/.bashrc +echo "$BASHRC_CONTENTS" >> $HOME/.profile +echo "$BASHRC_CONTENTS" >> $HOME/.bash_profile +EOF + + +# ----------------------------------- +# Step 4: Ensure venv auto-activation +# ----------------------------------- +# This step creates an entrypoint script that ensures any command passed to +# `docker run` is executed inside a login shell where the virtual environment +# is auto-activated. It handles complex cases like multi-arg commands and +# ensures quoting is preserved accurately. +RUN < /entrypoint.sh +#!/bin/bash +set -e + +# Reconstruct the full command line safely, quoting each argument +args=() +for arg in "$@"; do + args+=("$(printf "%q" "$arg")") +done + +# Join arguments into a command string that can be executed by bash -c +# This preserves exact argument semantics (including quotes, spaces, etc.) +cmd="${args[*]}" + +# Execute the reconstructed command inside a login shell +# This ensures virtualenv activation via .bash_profile +exec bash -l -c "$cmd" +__EOSCRIPT__ + +# Print the script at build time for visibility/debugging +cat /entrypoint.sh + +chmod +x /entrypoint.sh +EOF + +# Set the entrypoint to our script that activates the virtual environment first +ENTRYPOINT ["/entrypoint.sh"] + + +# --------------------------------- +# Step 5: Checkout and install REPO +# --------------------------------- +# Based on the state of the repo this copies the host .git data over and then +# checks out the exact version of HELM requested by HELM_GIT_HASH. It then +# performs a basic install of helm into the virtual environment. + +RUN mkdir -p /root/code/helm + +COPY .git /root/code/helm/.git + +# Control the version of HELM (by default uses the current branch) +ARG HELM_GIT_HASH=HEAD + +ENV UV_LINK_MODE=copy + +RUN --mount=type=cache,target=/root/.cache <