Skip to content
Open
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
564518d
feat: extract build infrastructure into standalone scripts
wdconinc Apr 6, 2026
03beded
chore: chmod u+x build-eic.sh build-base.sh
plexoos Apr 6, 2026
0855275
Add ghcr.io/eic/buildcache as default cache-from
wdconinc Apr 6, 2026
2a44103
More pipefail
wdconinc Apr 6, 2026
6654d12
fix: apk add bash
wdconinc Apr 8, 2026
a40a59c
ci(github): rewrite build jobs to call build-base.sh and build-eic.sh
wdconinc Apr 8, 2026
289505d
refactor: unify push-by-digest output for all CI modes
wdconinc Apr 8, 2026
2e625c6
build: default JOBS to $(nproc) instead of hardcoded 4
wdconinc Apr 8, 2026
686742e
build(eic): drop unused spack version file sources
wdconinc Apr 8, 2026
9481b77
build scripts: harmonize github/gitlab by normalizing CI_REGISTRY_PREFIX
wdconinc Apr 9, 2026
bbc86a0
ci: add pre-commit shellcheck hook for root-level shell scripts
wdconinc Apr 9, 2026
38d707d
fix: docs: --jobs default to $(nproc)
wdconinc Apr 9, 2026
baa3daa
docs: --jobs default nproc
wdconinc Apr 9, 2026
604ce7b
fix: preserve arch/vN suffix
wdconinc Apr 9, 2026
0e64026
docs: default base is now debian:stable-slim
wdconinc Apr 9, 2026
074ea00
docs: clarify argument and env var mismatch allowed
wdconinc Apr 9, 2026
c859cf1
fix: strip \r from GITHUB_REF_POINT_SLUG/GITHUB_BASE_REF_SLUG
wdconinc Apr 9, 2026
4c12424
refactor: replace github-slug-action with inline slugify helper
wdconinc Apr 9, 2026
e0f2a6a
fix: strip CRLF line endings that embedded \r into ARCH variable
wdconinc Apr 10, 2026
0e2c14f
fix: remove non-existent tag extraction from image@digest files
wdconinc Apr 10, 2026
c355192
fix: fix set up QEMU job step
wdconinc Apr 10, 2026
f8b57d9
fix: use getconf _NPROCESSORS_ONLN instead of nproc
wdconinc Apr 10, 2026
c7e09ab
fix: add mirrors.yaml to .gitignore to prevent secrets upload
wdconinc Apr 11, 2026
c061a72
feat: support -h/--help
wdconinc Apr 13, 2026
91d3197
fix: update default tag handling to avoid accidental misuse
wdconinc Apr 13, 2026
fa1b268
feat: move gitlab ci pipeline to separate manifest merging job
wdconinc Apr 14, 2026
0b5eb18
docs: fix stale BASE_IMAGE default (amd64/debian:stable-slim → debian…
wdconinc Apr 14, 2026
2b58860
fix: use repo default branch for cache key fallback on push events
wdconinc Apr 14, 2026
59c3c8e
fix: escape sed replacements and use temp file for mirrors.yaml
wdconinc Apr 14, 2026
261f059
fix: mention both base images in local-fallback message
wdconinc Apr 14, 2026
d97587b
fix: mark registry credential secrets as required=false in Dockerfile
wdconinc Apr 14, 2026
f7ee567
fix: apk add coreutils
wdconinc Apr 15, 2026
58475aa
fix(docs): build-eic --jobs: default: nproc
wdconinc Apr 15, 2026
ad86804
fix: build-*.sh: cd "${SCRIPT_DIR}"
wdconinc Apr 15, 2026
1f3db00
fix(docs): consistentify
wdconinc Apr 15, 2026
8687d48
build-eic: support comma-separated --build-type (default,nightly) (#252)
wdconinc Apr 23, 2026
2c875ce
fix: mv {. => scripts}/build-{base,eic}.sh
wdconinc Jun 30, 2026
4d4b2d4
fix: address reviewer comments
wdconinc Jun 30, 2026
51f4aea
fix: restore check_image_size
wdconinc Jul 3, 2026
5f3c569
fix: docs
wdconinc Jul 3, 2026
2404641
fix: run npsim and eicrecon jobs in default container
wdconinc Jul 5, 2026
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
9 changes: 9 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Enforce LF line endings for all text files tracked in this repository.
# This prevents Windows editors from introducing CRLF endings in shell scripts,
# which causes bash to embed '\r' into variable values (e.g. ARCH=$(cmd)\r).
* text=auto eol=lf

# Explicitly mark binary files so they are never munged
*.png binary
*.jpg binary
*.ico binary
280 changes: 81 additions & 199 deletions .github/workflows/build-push.yml

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# build-*.sh products
mirrors.yaml

# install.sh products
eic-shell
local/
Expand Down
318 changes: 110 additions & 208 deletions .gitlab-ci.yml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ repos:
- id: shellcheck
types: [shell]
args: [--severity=warning, -x]
files: (^[^/]+\.sh$|^\.ci/resolve_git_ref$|^\.ci/check_image_size$)
files: (^[^/]+\.sh$|^scripts/[^/]+\.sh$|^scripts/resolve_git_ref$|^scripts/check_image_size$)
24 changes: 12 additions & 12 deletions containers/eic/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ LABEL org.opencontainers.image.title="Electron-Ion Collider build installation i
RUN --mount=type=cache,target=/ccache,id=ccache-${TARGETPLATFORM} \
--mount=type=cache,target=/var/cache/spack \
--mount=type=secret,id=mirrors,target=/opt/spack/etc/spack/mirrors.yaml \
--mount=type=secret,id=CI_REGISTRY_USER,env=CI_REGISTRY_USER \
--mount=type=secret,id=CI_REGISTRY_PASSWORD,env=CI_REGISTRY_PASSWORD \
--mount=type=secret,id=GITHUB_REGISTRY_USER,env=GITHUB_REGISTRY_USER \
--mount=type=secret,id=GITHUB_REGISTRY_TOKEN,env=GITHUB_REGISTRY_TOKEN \
--mount=type=secret,id=CI_REGISTRY_USER,env=CI_REGISTRY_USER,required=false \
--mount=type=secret,id=CI_REGISTRY_PASSWORD,env=CI_REGISTRY_PASSWORD,required=false \
--mount=type=secret,id=GITHUB_REGISTRY_USER,env=GITHUB_REGISTRY_USER,required=false \
--mount=type=secret,id=GITHUB_REGISTRY_TOKEN,env=GITHUB_REGISTRY_TOKEN,required=false \
<<EOF
set -e
export CCACHE_DIR=/ccache
Expand Down Expand Up @@ -121,10 +121,10 @@ LABEL org.opencontainers.image.title="Electron-Ion Collider runtime installation
# Installation (default environment, from buildcache)
RUN --mount=type=cache,target=/var/cache/spack \
--mount=type=secret,id=mirrors,target=/opt/spack/etc/spack/mirrors.yaml \
--mount=type=secret,id=CI_REGISTRY_USER,env=CI_REGISTRY_USER \
--mount=type=secret,id=CI_REGISTRY_PASSWORD,env=CI_REGISTRY_PASSWORD \
--mount=type=secret,id=GITHUB_REGISTRY_USER,env=GITHUB_REGISTRY_USER \
--mount=type=secret,id=GITHUB_REGISTRY_TOKEN,env=GITHUB_REGISTRY_TOKEN \
--mount=type=secret,id=CI_REGISTRY_USER,env=CI_REGISTRY_USER,required=false \
--mount=type=secret,id=CI_REGISTRY_PASSWORD,env=CI_REGISTRY_PASSWORD,required=false \
--mount=type=secret,id=GITHUB_REGISTRY_USER,env=GITHUB_REGISTRY_USER,required=false \
--mount=type=secret,id=GITHUB_REGISTRY_TOKEN,env=GITHUB_REGISTRY_TOKEN,required=false \
<<EOF
set -e
spack ${SPACK_FLAGS} install ${SPACK_INSTALL_FLAGS} --use-buildcache only
Expand Down Expand Up @@ -191,10 +191,10 @@ LABEL org.opencontainers.image.title="Electron-Ion Collider build installation i
RUN --mount=type=cache,target=/ccache,id=ccache-${TARGETPLATFORM} \
--mount=type=cache,target=/var/cache/spack \
--mount=type=secret,id=mirrors,target=/opt/spack/etc/spack/mirrors.yaml \
--mount=type=secret,id=CI_REGISTRY_USER,env=CI_REGISTRY_USER \
--mount=type=secret,id=CI_REGISTRY_PASSWORD,env=CI_REGISTRY_PASSWORD \
--mount=type=secret,id=GITHUB_REGISTRY_USER,env=GITHUB_REGISTRY_USER \
--mount=type=secret,id=GITHUB_REGISTRY_TOKEN,env=GITHUB_REGISTRY_TOKEN \
--mount=type=secret,id=CI_REGISTRY_USER,env=CI_REGISTRY_USER,required=false \
--mount=type=secret,id=CI_REGISTRY_PASSWORD,env=CI_REGISTRY_PASSWORD,required=false \
--mount=type=secret,id=GITHUB_REGISTRY_USER,env=GITHUB_REGISTRY_USER,required=false \
--mount=type=secret,id=GITHUB_REGISTRY_TOKEN,env=GITHUB_REGISTRY_TOKEN,required=false \
<<EOF
set -e
export CCACHE_DIR=/ccache
Expand Down
188 changes: 87 additions & 101 deletions docs/building-locally.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,50 @@ docker buildx version

## Quick Start

The repository provides two build scripts in `./scripts` — `build-base.sh` and `build-eic.sh` —
that encapsulate the full build logic. These are the same scripts used by the CI pipelines, so
local builds are guaranteed to be equivalent.

### Building the Base Image

```bash
cd /path/to/containers

# Build the base image
docker buildx build \
-f containers/debian/Dockerfile \
-t debian_stable_base:local \
containers/debian
# Build debian_stable_base with 8 parallel jobs
bash scripts/build-base.sh --jobs 8
```

This produces a local image tagged `debian_stable_base:local`.

### Building the EIC Image

```bash
# Build the full XL environment
docker buildx build \
-f containers/eic/Dockerfile \
--build-context spack-environment=spack-environment \
--build-arg DOCKER_REGISTRY=ghcr.io/eic/ \
--build-arg BUILDER_IMAGE=debian_stable_base \
--build-arg RUNTIME_IMAGE=debian_stable_base \
--build-arg INTERNAL_TAG=latest \
--build-arg ENV=xl \
-t eic_xl:local \
containers/eic
bash scripts/build-eic.sh --env xl --jobs 8
```

This produces a local image tagged `eic_xl:local`.
Comment thread
wdconinc marked this conversation as resolved.
Outdated

`scripts/build-eic.sh` automatically detects whether the required builder and runtime base
images (for example, `debian_stable_base:local` for both, or `cuda_devel:local` and
`cuda_runtime:local` for CUDA builds) are available in the local Docker daemon. The script
only uses local base images when both images exist locally at the requested tag; if they do,
both are used directly with no registry prefix. If either image is missing, the script falls
back to pulling both base images from `ghcr.io/eic/` with the `latest` tag.

### Other environments

```bash
# Minimal CI environment (faster to build)
bash scripts/build-eic.sh --env ci

# Debug build
bash scripts/build-eic.sh --env dbg

# CUDA environment (requires local cuda_devel and cuda_runtime base images)
bash scripts/build-base.sh --image cuda_devel
bash scripts/build-base.sh --image cuda_runtime
bash scripts/build-eic.sh --env cuda --builder-image cuda_devel --runtime-image cuda_runtime
```

## Taking Advantage of Caching
Expand Down Expand Up @@ -87,19 +105,9 @@ No additional configuration is needed - the base image is pre-configured to use

### 3. Local Build Caches

For repeated local builds, set up persistent caches:

```bash
# Create cache directories
mkdir -p ~/.cache/eic-containers/{apt,spack,ccache}

# Build with local cache mounts
docker buildx build \
-f containers/debian/Dockerfile \
--build-arg jobs=8 \
-t debian_stable_base:local \
containers/debian
```
The build scripts automatically pull Docker-layer caches from `ghcr.io/eic/buildcache`.
Spack binary caches are fetched directly by Spack during the build from `ghcr.io/eic/spack-*`
and `binaries.spack.io`. No extra configuration is needed.
Comment thread
wdconinc marked this conversation as resolved.

## Build Architecture Diagram

Expand Down Expand Up @@ -127,91 +135,74 @@ flowchart TB
LC --> L5
```

## Full Build Script
## Build Script Reference

Here's a complete script for building locally with all optimizations:
Both scripts live in `scripts/` and accept command-line flags. Many options can
also be set via environment variables, but the variable names are script-specific and do
not always exactly match the flag names (for example, `JOBS=8 bash scripts/build-base.sh`,
`LOCAL_TAG=local bash scripts/build-eic.sh`, or `LOCAL_BASE_TAG=local bash scripts/build-eic.sh`).

```bash
#!/bin/bash
set -e

REPO_DIR="$(pwd)"
REGISTRY="ghcr.io/eic"
ARCH=$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')

# Load version information
source spack.sh
source spack-packages.sh
source key4hep-spack.sh
source eic-spack.sh

# Helper to resolve git refs
resolve_ref() {
.ci/resolve_git_ref "$1" "$2"
}

# Build base image
echo "=== Building debian_stable_base ==="
docker buildx build \
-f containers/debian/Dockerfile \
--build-arg SPACK_ORGREPO=${SPACK_ORGREPO} \
--build-arg SPACK_VERSION=${SPACK_VERSION} \
--build-arg SPACKPACKAGES_ORGREPO=${SPACKPACKAGES_ORGREPO} \
--build-arg SPACKPACKAGES_VERSION=${SPACKPACKAGES_VERSION} \
--build-arg KEY4HEPSPACK_ORGREPO=${KEY4HEPSPACK_ORGREPO} \
--build-arg KEY4HEPSPACK_VERSION=${KEY4HEPSPACK_VERSION} \
--build-arg EICSPACK_ORGREPO=${EICSPACK_ORGREPO} \
--build-arg EICSPACK_VERSION=${EICSPACK_VERSION} \
--build-arg jobs=8 \
--cache-from type=registry,ref=${REGISTRY}/buildcache:debian_stable_base-master-${ARCH} \
-t debian_stable_base:local \
--load \
containers/debian
### `scripts/build-base.sh`

# Build EIC image
echo "=== Building eic_xl ==="
docker buildx build \
-f containers/eic/Dockerfile \
--build-context spack-environment=spack-environment \
--build-arg DOCKER_REGISTRY="" \
--build-arg BUILDER_IMAGE=debian_stable_base:local \
--build-arg RUNTIME_IMAGE=debian_stable_base:local \
--build-arg INTERNAL_TAG="" \
--build-arg ENV=xl \
--cache-from type=registry,ref=${REGISTRY}/buildcache:eic_xl-default-master-${ARCH} \
-t eic_xl:local \
--load \
containers/eic
Builds the base image that all EIC images depend on.

```
bash scripts/build-base.sh [options]

echo "=== Build complete ==="
echo "Run with: docker run -it eic_xl:local"
--image IMAGE Image to build: debian_stable_base (default), cuda_devel, cuda_runtime
--base-image IMAGE Upstream image (derived automatically from --image if omitted)
--platform PLATFORM linux/amd64 (default), linux/arm64
--jobs N Parallel Spack build jobs (default: nproc)
--tag TAG Output image tag (default: local)
Comment thread
wdconinc marked this conversation as resolved.
```

### `scripts/build-eic.sh`

Builds an EIC software environment image.

```
bash scripts/build-eic.sh [options]

--env ENV Environment: ci, xl (default), cuda, dbg, jl, prod, cvmfs, tf, ...
--build-type TYPE default (default) or nightly
Comment thread
wdconinc marked this conversation as resolved.
Outdated
--builder-image IMG Builder base image name (default: debian_stable_base)
--runtime-image IMG Runtime base image name (default: debian_stable_base)
--platform PLATFORM linux/amd64 (default), linux/arm64
--jobs N Parallel Spack build jobs (default: nproc)
--base-tag TAG Tag of the locally built base image to use (default: local); if not found
locally, ghcr.io/eic/:latest is used as fallback
--tag TAG Output image tag (default: local)
Comment thread
wdconinc marked this conversation as resolved.
```

## Build Arguments Reference

### Base Image (containers/debian/Dockerfile)
### Base image build arguments used by `scripts/build-base.sh` (`containers/debian/Dockerfile`)

This table documents values passed by `scripts/build-base.sh`. If you invoke `docker buildx build`
directly, Dockerfile `ARG` defaults apply instead.

| Argument | Description | Default |
|----------|-------------|---------|
| `BASE_IMAGE` | Base Debian image | `debian:stable-slim` |
| `BASE_IMAGE` | Base Debian image passed by script | `debian:trixie-slim` for `debian_stable_base` (derived from `--image`) |
| `SPACK_ORGREPO` | Spack GitHub org/repo | `spack/spack` |
Comment thread
wdconinc marked this conversation as resolved.
Outdated
Comment thread
wdconinc marked this conversation as resolved.
Outdated
| `SPACK_VERSION` | Spack version/branch | `develop` |
| `SPACK_VERSION` | Spack version/branch | (from `spack.sh`) |
| `SPACK_SHA` | Specific commit SHA | (resolved from version) |
| `SPACK_CHERRYPICKS` | Space-separated cherry-pick SHAs | |
| `SPACKPACKAGES_*` | Similar args for spack-packages | |
| `KEY4HEPSPACK_*` | Similar args for key4hep-spack | |
| `EICSPACK_*` | Similar args for eic-spack | |
| `SPACK_CHERRYPICKS` | Newline-separated cherry-pick SHAs | (from `spack.sh`) |
Comment thread
wdconinc marked this conversation as resolved.
| `SPACKPACKAGES_*` | Similar args for spack-packages | (from `spack-packages.sh`) |
| `KEY4HEPSPACK_*` | Similar args for key4hep-spack | (from `key4hep-spack.sh`) |
| `EICSPACK_*` | Similar args for eic-spack | (from `eic-spack.sh`) |
| `jobs` | Parallel build jobs | `1` |

### EIC Image (containers/eic/Dockerfile)

| Argument | Description | Default |
|----------|-------------|---------|
| `DOCKER_REGISTRY` | Registry prefix for base images | `eicweb/` |
| `DOCKER_REGISTRY` | Registry prefix for base images | empty (local) or `ghcr.io/eic/` (GHCR fallback) |
| `BUILDER_IMAGE` | Builder base image name | `debian_stable_base` |
| `RUNTIME_IMAGE` | Runtime base image name | `debian_stable_base` |
| `INTERNAL_TAG` | Tag for base images | `master` |
| `ENV` | Environment type (`ci` or `xl`) | `xl` |
| `INTERNAL_TAG` | Tag for base images | value of `--base-tag` (local) or `latest` (GHCR fallback) |
| `ENV` | Environment type | `xl` |
Comment thread
wdconinc marked this conversation as resolved.
Comment thread
wdconinc marked this conversation as resolved.
| `SPACK_DUPLICATE_ALLOWLIST` | Pipe-separated allowed duplicates | (per ENV) |
Comment thread
wdconinc marked this conversation as resolved.
Comment thread
wdconinc marked this conversation as resolved.
| `EDM4EIC_SHA` | Custom edm4eic commit | |
| `EICRECON_SHA` | Custom eicrecon commit | |
| `EPIC_SHA` | Custom epic commit | |
Expand All @@ -224,14 +215,13 @@ echo "Run with: docker run -it eic_xl:local"
Reduce the number of parallel jobs:

```bash
docker buildx build --build-arg jobs=2 ...
bash scripts/build-base.sh --jobs 2
```

### Build Takes Too Long

1. Ensure you're using registry cache (`--cache-from`)
2. Check that Spack buildcache is accessible
3. Build the CI environment first (smaller): `--build-arg ENV=ci`
1. Ensure you're on a fast network (registry cache is fetched from `ghcr.io`)
2. Build the CI environment first (smaller): `bash scripts/build-eic.sh --env ci`

### Cannot Pull from ghcr.io

Expand All @@ -258,11 +248,7 @@ Using QEMU emulation (slower but works):
docker run --privileged --rm tonistiigi/binfmt --install arm64

# Build for ARM64
docker buildx build \
--platform linux/arm64 \
-f containers/debian/Dockerfile \
-t debian_stable_base:local-arm64 \
containers/debian
bash scripts/build-base.sh --platform linux/arm64 --tag local-arm64
```

## Next Steps
Expand Down
Loading
Loading