Implementation:Vespa engine Vespa Build Container Sh
Overview
This page documents the implementation of the Vespa container image building script: .buildkite/build-container.sh. This script builds two Docker images -- a Vespa preview image and a system-test image -- for the target architecture and OS combination.
Type: External Tool Doc
Code Reference
#!/usr/bin/env bash
# .buildkite/build-container.sh (L1-91)
set -o errexit
set -o nounset
set -o pipefail
if [[ -n "${DEBUG:-}" ]]; then
set -o xtrace
fi
if ! docker ps &> /dev/null; then
echo "No working docker command found."
exit 1
fi
case "${VESPA_BUILDOS_LABEL}" in
alma8)
VESPA_BASE_IMAGE="el8"
SYSTEM_TEST_BASE_IMAGE="almalinux:8"
;;
alma9)
VESPA_BASE_IMAGE="el9"
SYSTEM_TEST_BASE_IMAGE="almalinux:9"
;;
*)
echo "Unknown build os: ${VESPA_BUILDOS_LABEL}" 1>&2
exit 1
;;
esac
# --- Clone docker-image repository ---
if [[ ! -d "${WORKDIR}/docker-image" ]]; then
git clone --quiet --depth 1 https://github.com/vespa-engine/docker-image "$WORKDIR/docker-image"
fi
# --- Prepare RPMs for container build ---
rm -rf "${WORKDIR}/docker-image/rpms"
cp -a "${WORKDIR}/artifacts/$ARCH/rpms" "${WORKDIR}/docker-image/"
cd "${WORKDIR}/docker-image"
SOURCE_GITREF=$(git rev-parse HEAD)
# --- Build Vespa preview container ---
GHCR_PREVIEW_TAG=ghcr.io/vespa-engine/vespa-preview-${ARCH}:${VESPA_VERSION}${VESPA_CONTAINER_IMAGE_VERSION_TAG_SUFFIX}
docker build --progress plain \
--build-arg SOURCE_GITREF="$SOURCE_GITREF" \
--build-arg VESPA_VERSION="$VESPA_VERSION" \
--build-arg VESPA_BASE_IMAGE="$VESPA_BASE_IMAGE" \
--tag vespaengine/vespa \
--tag "${GHCR_PREVIEW_TAG}" \
--file Dockerfile .
# --- Clone system-test repository ---
declare -r GITREF="${GITREF_SYSTEM_TEST:-HEAD}"
cd "$WORKDIR"
if [[ ! -d $WORKDIR/system-test ]]; then
git clone --quiet --filter="blob:none" https://github.com/vespa-engine/system-test
fi
cd system-test
git checkout "$GITREF"
mkdir -p docker/vespa-systemtests
git archive HEAD --format tar | tar x -C docker/vespa-systemtests
cd docker
rm -rf maven-repo
cp -a "$HOME/.m2/repository" maven-repo
rm -rf rpms
mv "$WORKDIR/docker-image/rpms" rpms
# --- Build system-test container ---
DOCKER_SYSTEMTEST_TAG=docker.io/vespaengine/vespa-systemtest-preview-${ARCH}:${VESPA_VERSION}${VESPA_CONTAINER_IMAGE_VERSION_TAG_SUFFIX}
docker build --progress=plain \
--build-arg BASE_IMAGE="$SYSTEM_TEST_BASE_IMAGE" \
--build-arg VESPA_BASE_IMAGE="${GHCR_PREVIEW_TAG}" \
--target systemtest \
--tag "$DOCKER_SYSTEMTEST_TAG" \
--file Dockerfile .
I/O Contract
Inputs (Environment Variables)
| Variable | Required | Description | Example |
|---|---|---|---|
VESPA_BUILDOS_LABEL |
Yes | Build OS identifier determining base images | alma8 or alma9
|
VESPA_VERSION |
Yes | Version string for image tags | 8.432.17
|
ARCH |
Yes | CPU architecture identifier | x86_64 or aarch64
|
WORKDIR |
Yes | Working directory containing build artifacts | /tmp/vespa-build
|
VESPA_CONTAINER_IMAGE_VERSION_TAG_SUFFIX |
Yes | Optional suffix appended to image version tags | (empty string or custom) |
GITREF_SYSTEM_TEST |
No | Git ref for system-test checkout (defaults to HEAD) | abc123 or HEAD
|
DEBUG |
No | If set to a non-empty value, enables bash xtrace | 1
|
Inputs (Prerequisite Files)
| File/Directory | Produced By | Description |
|---|---|---|
$WORKDIR/artifacts/$ARCH/rpms/ |
build-rpms.sh | YUM repository with Vespa RPM packages |
$HOME/.m2/repository/ |
java.sh | Maven local repository with compiled JARs |
Inputs (External Repositories)
| Repository | URL | Purpose |
|---|---|---|
| docker-image | https://github.com/vespa-engine/docker-image |
Contains Dockerfile for the Vespa production image |
| system-test | https://github.com/vespa-engine/system-test |
Contains test framework and system-test Dockerfile |
Outputs (Docker Images)
| Image | Tag | Description |
|---|---|---|
| Vespa Preview | ghcr.io/vespa-engine/vespa-preview-${ARCH}:${VESPA_VERSION}${SUFFIX} |
Production Vespa image |
| Vespa Preview (local) | vespaengine/vespa |
Local tag for the production image |
| System Test Preview | docker.io/vespaengine/vespa-systemtest-preview-${ARCH}:${VESPA_VERSION}${SUFFIX} |
System test image with test frameworks |
Key Implementation Details
Docker Availability Check
if ! docker ps &> /dev/null; then
echo "No working docker command found."
exit 1
fi
The script immediately verifies that the Docker daemon is accessible by running docker ps and redirecting all output to /dev/null. This provides an early, clear failure message if Docker is not available, rather than a confusing error later during the build.
Base Image Selection
case "${VESPA_BUILDOS_LABEL}" in
alma8)
VESPA_BASE_IMAGE="el8"
SYSTEM_TEST_BASE_IMAGE="almalinux:8"
;;
alma9)
VESPA_BASE_IMAGE="el9"
SYSTEM_TEST_BASE_IMAGE="almalinux:9"
;;
*)
echo "Unknown build os: ${VESPA_BUILDOS_LABEL}" 1>&2
exit 1
;;
esac
The case statement maps the build OS label to two different base image references:
VESPA_BASE_IMAGEuses a short label (el8/el9) that is resolved inside the Dockerfile to the appropriate internal base image.SYSTEM_TEST_BASE_IMAGEuses a full Docker Hub reference (almalinux:8/almalinux:9) for the system test base.
Docker-Image Repository Cloning
if [[ ! -d "${WORKDIR}/docker-image" ]]; then
git clone --quiet --depth 1 https://github.com/vespa-engine/docker-image "$WORKDIR/docker-image"
fi
rm -rf "${WORKDIR}/docker-image/rpms"
cp -a "${WORKDIR}/artifacts/$ARCH/rpms" "${WORKDIR}/docker-image/"
The docker-image repository is cloned with --depth 1 (shallow clone) for minimal download. The built RPMs are then copied into the clone to serve as the Docker build context. The cp -a flag preserves file attributes and timestamps.
Vespa Preview Image Build
The Docker build uses three build arguments:
SOURCE_GITREF: The git commit hash of the docker-image repo, used for image metadata.VESPA_VERSION: Baked into the image for runtime version reporting.VESPA_BASE_IMAGE: Selects the OS variant within the Dockerfile.
Two tags are applied: a local tag (vespaengine/vespa) used as the base for the system-test image, and a GHCR preview tag for registry storage.
System-Test Image Build
The system-test build is more involved:
- The system-test repository is cloned with
--filter="blob:none"(blobless clone) for efficiency. - A specific git ref is checked out (defaulting to HEAD).
git archive HEAD | tar xexports the test framework without.gitmetadata.- The Maven repository and RPMs are copied into the Docker build context.
- The image is built with
--target systemtest, using a multi-stage Dockerfile.
The --target systemtest flag selects the systemtest stage in the multi-stage Dockerfile, which extends the base Vespa image with test dependencies.
RPM Movement Between Images
After the Vespa preview image is built, the RPMs are moved (not copied) from the docker-image context into the system-test context:
rm -rf rpms
mv "$WORKDIR/docker-image/rpms" rpms
Using mv instead of cp avoids doubling the disk usage for the RPM repository.
Execution Context
Buildkite Pipeline
--> .buildkite/build-rpms.sh (produces RPMs)
--> .buildkite/build-container.sh
--> Verify Docker availability
--> Map VESPA_BUILDOS_LABEL to base images
--> Clone vespa-engine/docker-image (shallow)
--> Copy RPMs into docker-image context
--> docker build (Vespa preview image)
--> Clone vespa-engine/system-test (blobless)
--> Prepare test context (git archive, copy Maven repo)
--> docker build --target systemtest (system-test image)
Source File Locations
.buildkite/build-container.sh(Lines 1-91)
See Also
- Container Image Building Principle -- The design rationale for Vespa container images.
- RPM Build Implementation -- The preceding stage that produces the RPMs installed in the image.
- Artifact Publishing Implementation -- The stage that signs and uploads build artifacts.