Principle:Vespa engine Vespa Container Image Building
Overview
Container image building packages software into OCI-compliant images for reproducible deployment. The Vespa build supports multiple base images (AlmaLinux 8 and AlmaLinux 9) and produces both a production Vespa image and a system-test image. These images are tagged with the Vespa version and architecture, enabling multi-architecture deployments.
Motivation
Container images provide a standardized packaging format that bundles the application with all its dependencies and runtime environment. For Vespa, containerization serves several purposes:
- Reproducible deployment: A container image captures the exact combination of OS packages, Java runtime, native libraries, and Vespa binaries. The same image runs identically across development, staging, and production environments.
- Multi-OS support: By building on different base images (AlmaLinux 8 with glibc 2.28 and AlmaLinux 9 with glibc 2.34), Vespa supports deployment targets with different OS requirements.
- Multi-architecture support: Separate images are built for x86_64 and aarch64 architectures, and can later be combined into multi-architecture manifest lists.
- System testing: A dedicated system-test image includes test frameworks and the Maven repository, enabling automated integration testing in containerized environments.
How It Works
The container build process produces two images per architecture per OS:
Image 1: Vespa Preview Image
The production Vespa image is built from the vespa-engine/docker-image repository:
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 .
Build arguments control the image content:
| Build Argument | Description | Example Value |
|---|---|---|
SOURCE_GITREF |
Git commit hash for traceability | a1b2c3d4...
|
VESPA_VERSION |
Version string baked into the image | 8.432.17
|
VESPA_BASE_IMAGE |
Base image variant | el8 or el9
|
The image is tagged with both a local name (vespaengine/vespa) and a GitHub Container Registry preview tag.
Image 2: System Test Image
The system test image extends the Vespa preview image with test infrastructure:
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 .
This image includes:
- The full Maven local repository (
~/.m2/repository) - The system-test framework from vespa-engine/system-test
- RPM packages for local installation within the test environment
Base Image Mapping
The script maps the VESPA_BUILDOS_LABEL to the appropriate base images:
| Build OS Label | Vespa Base Image | System Test Base Image |
|---|---|---|
alma8 |
el8 |
almalinux:8
|
alma9 |
el9 |
almalinux:9
|
Output Image Tags
| Image | Tag Pattern | Example |
|---|---|---|
| Vespa Preview | ghcr.io/vespa-engine/vespa-preview-${ARCH}:${VESPA_VERSION} |
ghcr.io/vespa-engine/vespa-preview-x86_64:8.432.17
|
| System Test Preview | docker.io/vespaengine/vespa-systemtest-preview-${ARCH}:${VESPA_VERSION} |
docker.io/vespaengine/vespa-systemtest-preview-x86_64:8.432.17
|
Environment Variables
| Variable | Description | Example Value |
|---|---|---|
VESPA_VERSION |
Version string for image tags | 8.432.17
|
VESPA_BUILDOS_LABEL |
Build OS identifier | alma8 or alma9
|
ARCH |
CPU architecture for image tagging | x86_64 or aarch64
|
WORKDIR |
Working directory containing RPMs and Maven repo | /tmp/vespa-build
|
VESPA_CONTAINER_IMAGE_VERSION_TAG_SUFFIX |
Optional suffix for image version tags | (empty or custom suffix) |
GITREF_SYSTEM_TEST |
Optional git ref for system-test checkout | HEAD
|
Design Considerations
Shallow clones: The docker-image repository is cloned with --depth 1 to minimize download time. Only the latest commit is needed since the Dockerfile is the only file of interest.
Blobless clone for system-test: The system-test repository is cloned with --filter="blob:none", which downloads the commit and tree objects but defers blob downloads until they are accessed. This reduces initial clone time for the large test repository.
Git archive for test content: Instead of copying the system-test working tree directly, the script uses git archive HEAD | tar x to create a clean export without .git metadata. This produces a smaller build context for the Docker build.
Docker availability check: The script begins with docker ps to verify that the Docker daemon is accessible. This provides a clear error message rather than an obscure failure during the build.
Reuse of existing clones: The script checks for existing repository clones before cloning, allowing reruns of the build to skip the clone step.
Relationship to Other Build Stages
Container image building depends on RPM package creation and the Java Maven build:
RPM Package Creation -+
+--> Container Image Building --> (push to registry)
Java Maven Build -----+
|
+--> Artifact Signing and Publishing
See Also
- Container Build Implementation -- The implementation details of the build-container.sh script.
- RPM Package Creation -- The preceding stage that produces RPMs.
- Artifact Signing and Publishing -- The stage that signs and publishes the final artifacts.
- Source: build-container.sh