diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 25cd201e87692b1a640bd784dee750bf5e168f07..a770b7f2a208f3f8bdab6f0937ee070f7dee4f97 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -270,6 +270,9 @@ base: needs: - version script: + - source spack.sh ; + source key4hep-spack.sh ; + source eic-spack.sh ; - attempts=0 - nocache="" - while ! @@ -284,6 +287,16 @@ base: --platform ${PLATFORM} --build-arg BASE_IMAGE=${BASE_IMAGE} --build-arg BUILD_IMAGE=${BUILD_IMAGE} + --build-arg SPACK_ORGREPO=${SPACK_ORGREPO} + --build-arg SPACK_VERSION=${SPACK_VERSION} + --build-arg SPACK_CHERRYPICKS="${SPACK_CHERRYPICKS}" + --build-arg SPACK_CHERRYPICKS_FILES="${SPACK_CHERRYPICKS_FILES}" + --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 S3_ACCESS_KEY=${S3_ACCESS_KEY} + --build-arg S3_SECRET_KEY=${S3_SECRET_KEY} --provenance false containers/debian 2>&1 | tee build.log @@ -419,16 +432,6 @@ eic: --build-arg BUILDER_IMAGE=${BUILDER_IMAGE} --build-arg RUNTIME_IMAGE=${RUNTIME_IMAGE} --build-arg INTERNAL_TAG=${INTERNAL_TAG} - --build-arg SPACK_ORGREPO=${SPACK_ORGREPO} - --build-arg SPACK_VERSION=${SPACK_VERSION} - --build-arg SPACK_CHERRYPICKS="${SPACK_CHERRYPICKS}" - --build-arg SPACK_CHERRYPICKS_FILES="${SPACK_CHERRYPICKS_FILES}" - --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 S3_ACCESS_KEY=${S3_ACCESS_KEY} - --build-arg S3_SECRET_KEY=${S3_SECRET_KEY} --build-arg JUG_VERSION=${EXPORT_TAG}-${BUILD_TYPE}-$(git rev-parse HEAD) ${IF_BUILD_DEFAULT+ ${EDM4EIC_VERSION:+--build-arg EDM4EIC_VERSION=${EDM4EIC_VERSION}} diff --git a/containers/debian/base.Dockerfile b/containers/debian/base.Dockerfile index 72daa2408daa00fd166e483cffe620c099b93f0f..9aa43551c2ff0ced30671e909fcee1a16a8cf91c 100644 --- a/containers/debian/base.Dockerfile +++ b/containers/debian/base.Dockerfile @@ -5,6 +5,8 @@ ARG BUILD_IMAGE="debian_stable_base" # Minimal container based on Debian base systems for up-to-date packages. FROM ${BASE_IMAGE} +ARG TARGETPLATFORM + LABEL maintainer="Sylvester Joosten <sjoosten@anl.gov>" \ name="${BUILD_IMAGE}" \ march="amd64" @@ -125,3 +127,116 @@ update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 100 gcc --version clang --version EOF + +## Install some extra spack dependencies +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=${TARGETPLATFORM} \ + --mount=type=cache,target=/var/lib/apt/lists,sharing=locked,id=${TARGETPLATFORM} <<EOF +rm -f /etc/apt/apt.conf.d/docker-clean +apt-get -yqq update +apt-get -yqq install --no-install-recommends \ + jq \ + python3 \ + python3-dev \ + python3-distutils \ + python3-boto3 \ + python-is-python3 +EOF + +## Setup spack +ENV SPACK_ROOT=/opt/spack +ARG SPACK_ORGREPO="spack/spack" +ARG SPACK_VERSION="releases/v0.20" +ENV SPACK_PYTHON=/usr/bin/python3 +ARG SPACK_CHERRYPICKS="" +ARG SPACK_CHERRYPICKS_FILES="" +ADD https://api.github.com/repos/${SPACK_ORGREPO}/commits/${SPACK_VERSION} /tmp/spack.json +RUN <<EOF +git config --global user.email "gitlab@eicweb.phy.anl.gov" +git config --global user.name "EIC Container Build Service" +git config --global advice.detachedHead false +git clone --filter=tree:0 https://github.com/${SPACK_ORGREPO}.git ${SPACK_ROOT} +git -C ${SPACK_ROOT} checkout ${SPACK_VERSION} +if [ -n "${SPACK_CHERRYPICKS}" ] ; then + SPACK_CHERRYPICKS=$(git -C ${SPACK_ROOT} rev-list --topo-order ${SPACK_CHERRYPICKS} | grep -m $(echo ${SPACK_CHERRYPICKS} | wc -w) "${SPACK_CHERRYPICKS}" | tac) + eval "declare -A SPACK_CHERRYPICKS_FILES_ARRAY=(${SPACK_CHERRYPICKS_FILES})" + for hash in ${SPACK_CHERRYPICKS} ; do + if [ -n "${SPACK_CHERRYPICKS_FILES_ARRAY[${hash}]+found}" ] ; then + git -C ${SPACK_ROOT} show ${hash} -- ${SPACK_CHERRYPICKS_FILES_ARRAY[${hash}]//,/ } | patch -p1 -d ${SPACK_ROOT} + git -C ${SPACK_ROOT} commit --all --message "$(git -C ${SPACK_ROOT} show --no-patch --pretty=format:%s ${hash})" + else + git -C ${SPACK_ROOT} cherry-pick ${hash} + fi + done +fi +git -C $SPACK_ROOT gc --prune=all --aggressive +sed -i 's/timeout=60/timeout=None/' $SPACK_ROOT/lib/spack/spack/stage.py +ln -s $SPACK_ROOT/share/spack/docker/entrypoint.bash /usr/bin/docker-shell +ln -s $SPACK_ROOT/share/spack/docker/entrypoint.bash /usr/bin/interactive-shell +ln -s $SPACK_ROOT/share/spack/docker/entrypoint.bash /usr/bin/spack-env +EOF + +## Use spack entrypoint. NOTE: Requires `set -ex` in all multi-line scripts! +SHELL ["docker-shell"] + +## Setup build configuration +ARG jobs=1 +RUN <<EOF +set -e +declare -A target=(["linux/amd64"]="x86_64_v2" ["linux/arm64"]="aarch64") +target=${target[${TARGETPLATFORM}]} +spack config --scope site add "packages:all:require:[target=${target}]" +spack config --scope site add "packages:all:target:[${target}]" +spack config blame packages +spack config --scope user add "config:suppress_gpg_warnings:true" +spack config --scope user add "config:build_jobs:${jobs}" +spack config --scope user add "config:db_lock_timeout:${jobs}00" +spack config --scope user add "config:source_cache:/var/cache/spack" +spack config --scope user add "config:install_tree:root:/opt/software" +spack config --scope user add "config:ccache:true" +spack config blame config +spack compiler find --scope site +spack config blame compilers +EOF + +## Setup buildcache mirrors +## - this always adds the read-only mirror to the container +## - the write-enabled mirror is provided later as a secret mount +ARG S3_ACCESS_KEY="" +ARG S3_SECRET_KEY="" +RUN --mount=type=cache,target=/var/cache/spack <<EOF +set -e +if [ -n "${S3_ACCESS_KEY}" ] ; then + spack mirror add --scope site --unsigned \ + --s3-endpoint-url https://eics3.sdcc.bnl.gov:9000 \ + --s3-access-key-id "${S3_ACCESS_KEY}" \ + --s3-access-key-secret "${S3_SECRET_KEY}" \ + eics3 s3://eictest/EPIC/spack/${SPACK_VERSION} +fi +spack mirror add --scope site --signed spack-${SPACK_VERSION} https://binaries.spack.io/${SPACK_VERSION} +spack mirror add --scope site --unsigned ghcr-${SPACK_VERSION} oci://ghcr.io/eic/spack-${SPACK_VERSION} +spack mirror list +EOF + +## Setup eic-spack +ENV EICSPACK_ROOT=${SPACK_ROOT}/var/spack/repos/eic-spack +ARG EICSPACK_ORGREPO="eic/eic-spack" +ARG EICSPACK_VERSION="$SPACK_VERSION" +ADD https://api.github.com/repos/${EICSPACK_ORGREPO}/commits/${EICSPACK_VERSION} /tmp/eic-spack.json +RUN <<EOF +set -e +git clone --filter=tree:0 https://github.com/${EICSPACK_ORGREPO}.git ${EICSPACK_ROOT} +git -C ${EICSPACK_ROOT} checkout ${EICSPACK_VERSION} +spack repo add --scope site "${EICSPACK_ROOT}" +EOF + +## Setup key4hep-spack +ENV KEY4HEPSPACK_ROOT=${SPACK_ROOT}/var/spack/repos/key4hep-spack +ARG KEY4HEPSPACK_ORGREPO="key4hep/key4hep-spack" +ARG KEY4HEPSPACK_VERSION="main" +ADD https://api.github.com/repos/${KEY4HEPSPACK_ORGREPO}/commits/${KEY4HEPSPACK_VERSION} /tmp/key4hep-spack.json +RUN <<EOF +set -e +git clone --filter=tree:0 https://github.com/${KEY4HEPSPACK_ORGREPO}.git ${KEY4HEPSPACK_ROOT} +git -C ${KEY4HEPSPACK_ROOT} checkout ${KEY4HEPSPACK_VERSION} +spack repo add --scope site "${KEY4HEPSPACK_ROOT}" +EOF diff --git a/containers/jug/dev.Dockerfile b/containers/jug/dev.Dockerfile index 807d5377ce9d394fa75de61df2114d71c14e6536..02f2c7ffe6787d6c40d446f537774544fc013c25 100644 --- a/containers/jug/dev.Dockerfile +++ b/containers/jug/dev.Dockerfile @@ -5,155 +5,69 @@ ARG BUILDER_IMAGE="debian_stable_base" ARG RUNTIME_IMAGE="debian_stable_base" ARG INTERNAL_TAG="testing" +## +## This docker build follows two tracks, in order to ensure that we build all packages +## in a builder image, but install them in a runtime image, while at the same time +## avoiding a expensive filesystem copy operation at the end that breaks layering. +## +## The build is split in an infrequently-changing default environment, upon which +## an environment with custom versions (e.g. individual commits) is layered. The +## custom environment will change frequently but layers will be smaller, allowing +## for easier deployment with smaller delta layers. +## +## The separation in a builder and runtime image is particularly relevant to end up with +## lightweight images for expensive build dependencies, such as for example CUDA. +## +## builder track runtime track +## ---------------------------------------------------------------------- +## builder_image runtime_image +## builder_concretization_default +## builder_installation_default -> runtime_concretization_default (copy spack.lock) +## \-> runtime_installation_default (from buildcache) +## builder_concretization_custom +## builder_installation_custom -> runtime_concretization_custom (copy spack.lock) +## \-> runtime_installation_custom (from buildcache) +## + + ## ======================================================================================== -## STAGE 0: spack image -## EIC spack image with spack and eic-spack repositories +## builder_concretization_default +## - builder base with concretization of default versions ## ======================================================================================== -FROM ${DOCKER_REGISTRY}${BUILDER_IMAGE}:${INTERNAL_TAG} as spack +FROM ${DOCKER_REGISTRY}${BUILDER_IMAGE}:${INTERNAL_TAG} as builder_concretization_default ARG TARGETPLATFORM -## With heredocs for multi-line scripts, we want to fail on error and the print failing line. -## Ref: https://docs.docker.com/engine/reference/builder/#example-running-a-multi-line-script -SHELL ["bash", "-ex", "-c"] - -## install some extra spack dependencies -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=${TARGETPLATFORM} \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked,id=${TARGETPLATFORM} <<EOF -rm -f /etc/apt/apt.conf.d/docker-clean -apt-get -yqq update -apt-get -yqq install --no-install-recommends \ - jq \ - python3 \ - python3-dev \ - python3-distutils \ - python3-boto3 \ - python-is-python3 -EOF - -## Setup spack -ENV SPACK_ROOT=/opt/spack -ARG SPACK_ORGREPO="spack/spack" -ARG SPACK_VERSION="releases/v0.20" -ENV SPACK_PYTHON=/usr/bin/python3 -ARG SPACK_CHERRYPICKS="" -ARG SPACK_CHERRYPICKS_FILES="" -ADD https://api.github.com/repos/${SPACK_ORGREPO}/commits/${SPACK_VERSION} /tmp/spack.json -RUN <<EOF -git config --global user.email "gitlab@eicweb.phy.anl.gov" -git config --global user.name "EIC Container Build Service" -git config --global advice.detachedHead false -git clone --filter=tree:0 https://github.com/${SPACK_ORGREPO}.git ${SPACK_ROOT} -git -C ${SPACK_ROOT} checkout ${SPACK_VERSION} -if [ -n "${SPACK_CHERRYPICKS}" ] ; then - SPACK_CHERRYPICKS=$(git -C ${SPACK_ROOT} rev-list --topo-order ${SPACK_CHERRYPICKS} | grep -m $(echo ${SPACK_CHERRYPICKS} | wc -w) "${SPACK_CHERRYPICKS}" | tac) - eval "declare -A SPACK_CHERRYPICKS_FILES_ARRAY=(${SPACK_CHERRYPICKS_FILES})" - for hash in ${SPACK_CHERRYPICKS} ; do - if [ -n "${SPACK_CHERRYPICKS_FILES_ARRAY[${hash}]+found}" ] ; then - git -C ${SPACK_ROOT} show ${hash} -- ${SPACK_CHERRYPICKS_FILES_ARRAY[${hash}]//,/ } | patch -p1 -d ${SPACK_ROOT} - git -C ${SPACK_ROOT} commit --all --message "$(git -C ${SPACK_ROOT} show --no-patch --pretty=format:%s ${hash})" - else - git -C ${SPACK_ROOT} cherry-pick ${hash} - fi - done -fi -git -C $SPACK_ROOT gc --prune=all --aggressive -sed -i 's/timeout=60/timeout=None/' $SPACK_ROOT/lib/spack/spack/stage.py -ln -s $SPACK_ROOT/share/spack/docker/entrypoint.bash /usr/bin/docker-shell -ln -s $SPACK_ROOT/share/spack/docker/entrypoint.bash /usr/bin/interactive-shell -ln -s $SPACK_ROOT/share/spack/docker/entrypoint.bash /usr/bin/spack-env -EOF - -## Use spack entrypoint. NOTE: Requires `set -ex` in all multi-line scripts! -SHELL ["docker-shell"] - -## Setup build configuration -ARG jobs=1 -RUN <<EOF -set -e -declare -A target=(["linux/amd64"]="x86_64_v2" ["linux/arm64"]="aarch64") -target=${target[${TARGETPLATFORM}]} -spack config --scope site add "packages:all:require:[target=${target}]" -spack config --scope site add "packages:all:target:[${target}]" -spack external find --not-buildable --scope site --path /usr/local/cuda/bin cuda -spack external find --not-buildable --scope site llvm -spack config blame packages -spack config --scope user add "config:suppress_gpg_warnings:true" -spack config --scope user add "config:build_jobs:${jobs}" -spack config --scope user add "config:db_lock_timeout:${jobs}00" -spack config --scope user add "config:source_cache:/var/cache/spack" -spack config --scope user add "config:install_tree:root:/opt/software" -spack config --scope user add "config:ccache:true" -spack config blame config -spack compiler find --scope site -spack config blame compilers -EOF - -## Setup buildcache mirrors -## - this always adds the read-only mirror to the container -## - the write-enabled mirror is provided later as a secret mount -ARG S3_ACCESS_KEY="" -ARG S3_SECRET_KEY="" -RUN --mount=type=cache,target=/var/cache/spack <<EOF -set -e -if [ -n "${S3_ACCESS_KEY}" ] ; then - spack mirror add --scope site --unsigned \ - --s3-endpoint-url https://eics3.sdcc.bnl.gov:9000 \ - --s3-access-key-id "${S3_ACCESS_KEY}" \ - --s3-access-key-secret "${S3_SECRET_KEY}" \ - eics3 s3://eictest/EPIC/spack/${SPACK_VERSION} -fi -spack mirror add --scope site --signed spack-${SPACK_VERSION} https://binaries.spack.io/${SPACK_VERSION} -spack mirror add --scope site --unsigned ghcr-${SPACK_VERSION} oci://ghcr.io/eic/spack-${SPACK_VERSION} -spack mirror list -EOF - -## Setup eic-spack -ENV EICSPACK_ROOT=${SPACK_ROOT}/var/spack/repos/eic-spack -ARG EICSPACK_ORGREPO="eic/eic-spack" -ARG EICSPACK_VERSION="$SPACK_VERSION" -ADD https://api.github.com/repos/${EICSPACK_ORGREPO}/commits/${EICSPACK_VERSION} /tmp/eic-spack.json -RUN <<EOF -set -e -git clone --filter=tree:0 https://github.com/${EICSPACK_ORGREPO}.git ${EICSPACK_ROOT} -git -C ${EICSPACK_ROOT} checkout ${EICSPACK_VERSION} -spack repo add --scope site "${EICSPACK_ROOT}" -EOF +## Copy our default environment +COPY --from=spack-environment . /opt/spack-environment/ +ARG ENV=dev +ENV SPACK_ENV=/opt/spack-environment/${ENV} -## Setup key4hep-spack -ENV KEY4HEPSPACK_ROOT=${SPACK_ROOT}/var/spack/repos/key4hep-spack -ARG KEY4HEPSPACK_ORGREPO="key4hep/key4hep-spack" -ARG KEY4HEPSPACK_VERSION="main" -ADD https://api.github.com/repos/${KEY4HEPSPACK_ORGREPO}/commits/${KEY4HEPSPACK_VERSION} /tmp/key4hep-spack.json +# Concretization (default environment) RUN <<EOF -set -e -git clone --filter=tree:0 https://github.com/${KEY4HEPSPACK_ORGREPO}.git ${KEY4HEPSPACK_ROOT} -git -C ${KEY4HEPSPACK_ROOT} checkout ${KEY4HEPSPACK_VERSION} -spack repo add --scope site "${KEY4HEPSPACK_ROOT}" +echo -e "\n view: false" >> ${SPACK_ENV}/spack.yaml +spack env activate --dir ${SPACK_ENV} +spack external find --not-buildable --scope env:${SPACK_ENV} --path /usr/local/cuda/bin cuda +spack external find --not-buildable --scope env:${SPACK_ENV} llvm +spack concretize --fresh --force EOF ## ======================================================================================== -## STAGE 1: builder -## EIC builder image with spack environment +## builder_installation_default +## - builder base with installation of default versions ## ======================================================================================== -FROM spack as builder +FROM builder_concretization_default as builder_installation_default +ARG TARGETPLATFORM -## 1. Setup our default environment (secret mount for write-enabled mirror) -COPY --from=spack-environment . /opt/spack-environment/ -ARG ENV=dev -ENV SPACK_ENV=/opt/spack-environment/${ENV} +# Installation (default environment) RUN --mount=type=cache,target=/ccache,id=${TARGETPLATFORM} \ --mount=type=cache,target=/var/cache/spack \ --mount=type=secret,id=mirrors,target=/opt/spack/etc/spack/mirrors.yaml \ <<EOF set -e export CCACHE_DIR=/ccache -source ${SPACK_ROOT}/share/spack/setup-env.sh mkdir -p /var/cache/spack/blobs/sha256/ find /var/cache/spack/blobs/sha256/ -ignore_readdir_race -atime +7 -delete -echo -e "\n view: false" >> ${SPACK_ENV}/spack.yaml -spack env activate --dir ${SPACK_ENV} -spack concretize --fresh --force make --jobs ${jobs} --keep-going --directory /opt/spack-environment \ SPACK_ENV=${SPACK_ENV} \ BUILDCACHE_OCI_PROMPT="eicweb" \ @@ -163,11 +77,72 @@ spack find --long --no-groups \ | sed -e '1,/Installed packages/d;s/\([^@]*\).*/\1/g' \ | uniq -D -f1 | grep -v -w -e "\(epic\|py-pip\|py-cython\)" \ | tee /tmp/duplicates.txt -test -s /tmp/duplicates.txt && ( cat /tmp/duplicates.txt | while read hash spec ; do spack spec --long /${hash} ; done ) && exit 1 +if [ -s /tmp/duplicates.txt ] ; then + echo "Duplicate packages found" + cat /tmp/duplicates.txt | while read hash spec ; do spack spec --long /${hash} ; done + exit 1 +fi ccache --show-stats ccache --zero-stats EOF + +## ======================================================================================== +## runtime_concretization_default +## - runtime base with concretization of default versions (taken from equivalent builder) +## ======================================================================================== +FROM ${DOCKER_REGISTRY}${RUNTIME_IMAGE}:${INTERNAL_TAG} as runtime_concretization_default +ARG TARGETPLATFORM + +## Copy our default environment +COPY --from=spack-environment . /opt/spack-environment/ +ARG ENV=dev +ENV SPACK_ENV=/opt/spack-environment/${ENV} + +RUN echo -e "\n view: false" >> ${SPACK_ENV}/spack.yaml + +COPY --from=builder_installation_default \ + /opt/spack-environment/${ENV}/spack.* \ + /opt/spack-environment/${ENV}/ + + +## ======================================================================================== +## runtime_installation_default +## - runtime base with installation of default versions (buildcache populated by builder) +## ======================================================================================== +FROM runtime_concretization_default as runtime_installation_default +ARG TARGETPLATFORM + +# 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 \ + <<EOF +make --jobs ${jobs} --keep-going --directory /opt/spack-environment \ + SPACK_ENV=${SPACK_ENV} SPACK_INSTALL_FLAGS="--use-buildcache only" +spack gc --yes-to-all +EOF + +## Add minio client into /opt/mc/bin/mc +ADD --chmod=0755 https://dl.min.io/client/mc/release/linux-amd64/mc /opt/mc/bin/mc-amd64 +ADD --chmod=0755 https://dl.min.io/client/mc/release/linux-arm64/mc /opt/mc/bin/mc-arm64 +RUN <<EOF +set -e +declare -A target=(["linux/amd64"]="amd64" ["linux/arm64"]="arm64") +mv /opt/mc/bin/mc-${target[${TARGETPLATFORM}]} /opt/mc/bin/mc +unset target[${TARGETPLATFORM}] +for t in ${target[*]} ; do + rm /opt/mc/bin/mc-${t} +done +EOF + + +## ======================================================================================== +## builder_concretization_custom +## - builder base with concretization of custom versions +## ======================================================================================== +FROM builder_installation_default as builder_concretization_custom +ARG TARGETPLATFORM + ## 2. Setup our environment with custom versions (on top of cached layer) ## Note: these default versions are just the very first commit. ARG EDM4EIC_VERSION="8aeb507f93a93257c99985efbce0ec1371e0b331" @@ -178,12 +153,9 @@ ADD https://api.github.com/repos/eic/edm4eic/commits/${EDM4EIC_VERSION} /tmp/edm ADD https://api.github.com/repos/eic/eicrecon/commits/${EICRECON_VERSION} /tmp/eicrecon.json ADD https://api.github.com/repos/eic/epic/commits/${EPIC_VERSION} /tmp/epic.json ADD https://api.github.com/repos/eic/juggler/commits/${JUGGLER_VERSION} /tmp/juggler.json -RUN --mount=type=cache,target=/ccache,id=${TARGETPLATFORM} \ - --mount=type=cache,target=/var/cache/spack \ - --mount=type=secret,id=mirrors,target=/opt/spack/etc/spack/mirrors.yaml \ - <<EOF -set -e -export CCACHE_DIR=/ccache + +# Concretization (custom environment) +RUN <<EOF spack env activate --dir ${SPACK_ENV} if [ "${EDM4EIC_VERSION}" != "8aeb507f93a93257c99985efbce0ec1371e0b331" ] ; then export EDM4EIC_VERSION=$(jq -r .sha /tmp/edm4eic.json) @@ -207,19 +179,88 @@ if [ "${JUGGLER_VERSION}" != "df87bf1f8643afa8e80bece9d36d6dc26dfe8132" ] ; then spack deconcretize -y --all juggler fi spack concretize --fresh --force +EOF + + +## ======================================================================================== +## builder_installation_custom +## - builder base with installation of custom versions +## ======================================================================================== +FROM builder_concretization_custom as builder_installation_custom +ARG TARGETPLATFORM + +# Installation (custom environment) +RUN --mount=type=cache,target=/ccache,id=${TARGETPLATFORM} \ + --mount=type=cache,target=/var/cache/spack \ + --mount=type=secret,id=mirrors,target=/opt/spack/etc/spack/mirrors.yaml \ + <<EOF +set -e +export CCACHE_DIR=/ccache make --jobs ${jobs} --keep-going --directory /opt/spack-environment \ SPACK_ENV=${SPACK_ENV} \ - BUILDCACHE_OCI_FINAL="eicweb" + BUILDCACHE_OCI_PROMPT="eicweb" \ + BUILDCACHE_OCI_FINAL="ghcr" spack gc --yes-to-all spack find --long --no-groups \ | sed -e '1,/Installed packages/d;s/\([^@]*\).*/\1/g' \ | uniq -D -f1 | grep -v -w -e "\(epic\|py-pip\|py-cython\)" \ | tee /tmp/duplicates.txt -test -s /tmp/duplicates.txt && ( cat /tmp/duplicates.txt | while read hash spec ; do spack spec --long /${hash} ; done ) && exit 1 +if [ -s /tmp/duplicates.txt ] ; then + echo "Duplicate packages found" + cat /tmp/duplicates.txt | while read hash spec ; do spack spec --long /${hash} ; done + exit 1 +fi ccache --show-stats ccache --zero-stats EOF + +## ======================================================================================== +## runtime_concretization_custom +## - runtime base with concretization of custom versions (taken from equivalent builder) +## ======================================================================================== +FROM runtime_installation_default as runtime_concretization_custom +COPY --from=builder_installation_custom \ + /opt/spack-environment/${ENV}/spack.* \ + /opt/spack-environment/${ENV}/ +COPY --from=builder_installation_custom \ + /opt/spack-environment/packages.yaml \ + /opt/spack-environment/ + + +## ======================================================================================== +## runtime_installation_custom +## - runtime base with installation of custom versions (buildcache populated by builder) +## ======================================================================================== +FROM runtime_concretization_custom as runtime_installation_custom +ARG TARGETPLATFORM + +# 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 \ + <<EOF +set -e +make --jobs ${jobs} --keep-going --directory /opt/spack-environment \ + SPACK_ENV=${SPACK_ENV} SPACK_INSTALL_FLAGS="--use-buildcache only" +spack gc --yes-to-all +spack find --long --no-groups \ +| sed -e '1,/Installed packages/d;s/\([^@]*\).*/\1/g' \ +| uniq -D -f1 | grep -v -w -e "\(epic\|py-pip\|py-cython\)" \ +| tee /tmp/duplicates.txt +if [ -s /tmp/duplicates.txt ] ; then + echo "Duplicate packages found" + cat /tmp/duplicates.txt | while read hash spec ; do spack spec --long /${hash} ; done + exit 1 +fi +EOF + + +## ======================================================================================== +## final image, based on runtime_installation_custom +## ======================================================================================== +FROM runtime_installation_custom +ARG TARGETPLATFORM + ## Create views at /opt/local and /opt/detector RUN <<EOF set -e @@ -228,10 +269,24 @@ sed -i -e '/view: false/d' ${SPACK_ENV}/spack.yaml cat /opt/spack-environment/view.yaml >> ${SPACK_ENV}/spack.yaml spack -e ${SPACK_ENV} env view regenerate /opt/local spack -e ${SPACK_ENV} env view regenerate /opt/detector +# ensure /opt/local is the view, not a symlink +rm -rf /opt/local /opt/detector +LOCAL_PREFIX_PATH=$(realpath $(ls /opt/._local/ | tail -n1)) +mv /opt/._local/${LOCAL_PREFIX_PATH} /opt/local +ln -s /opt/local /opt/._local/${LOCAL_PREFIX_PATH} +DETECTOR_PREFIX_PATH=$(realpath $(ls /opt/._detector/ | tail -n1)) +mv /opt/._detector/${DETECTOR_PREFIX_PATH} /opt/detector +ln -s /opt/detector /opt/._detector/${DETECTOR_PREFIX_PATH} +EOF + +## Link minio client into /opt/local/bin/mc +RUN <<EOF +ln -sf /opt/mc/bin/mc /opt/local/bin/mc EOF ## Place cvmfs catalogs RUN <<EOF +set -e touch ${SPACK_ROOT}/.cvmfscatalog touch /opt/software/.cvmfscatalog find /opt/software -mindepth 2 -maxdepth 3 -type d -exec touch {}/.cvmfscatalog \; @@ -246,6 +301,7 @@ EOF ## Fixup /opt/detector/epic-git.fcf90937193c983c0af2acf1251e01f2e2c3a259_main RUN <<EOF +set -e shopt -s nullglob cd /opt/detector for detector in epic-git.*_* ; do @@ -255,7 +311,7 @@ EOF ## Fill jug_info RUN <<EOF -set -ex +set -e spack debug report | sed "s/^/ - /" | sed "s/\* \*\*//" | sed "s/\*\*//" >> /etc/jug_info spack find --no-groups --long --variants | sed "s/^/ - /" >> /etc/jug_info spack graph --dot > /opt/spack-environment/env.dot @@ -270,65 +326,6 @@ COPY profile.d/a00_cleanup.sh /etc/profile.d COPY profile.d/z11_jug_env.sh /etc/profile.d COPY singularity.d /.singularity.d -## Add minio client into /opt/local/bin -ADD --chmod=0755 https://dl.min.io/client/mc/release/linux-amd64/mc /opt/local/bin/mc-amd64 -ADD --chmod=0755 https://dl.min.io/client/mc/release/linux-arm64/mc /opt/local/bin/mc-arm64 -RUN <<EOF -set -ex -declare -A target=(["linux/amd64"]="amd64" ["linux/arm64"]="arm64") -mv /opt/local/bin/mc-${target[${TARGETPLATFORM}]} /opt/local/bin/mc -unset target[${TARGETPLATFORM}] -for t in ${target[*]} ; do - rm /opt/local/bin/mc-${t} -done -EOF - -## make sure we have the entrypoints setup correctly -ENTRYPOINT [] -CMD ["bash", "--rcfile", "/etc/profile", "-l"] -USER 0 -WORKDIR / - - -## ======================================================================================== -## STAGE 2 -## Lean target image -## ======================================================================================== -FROM ${DOCKER_REGISTRY}${RUNTIME_IMAGE}:${INTERNAL_TAG} as runtime -ARG TARGETPLATFORM - -LABEL maintainer="Sylvester Joosten <sjoosten@anl.gov>" \ - name="jug_xl" \ - march="$TARGETPLATFORM" - -## copy over everything we need from builder -COPY --from=builder /opt/spack /opt/spack -COPY --from=builder /opt/spack-environment /opt/spack-environment -COPY --from=builder /opt/software /opt/software -COPY --from=builder /opt/._local /opt/._local -COPY --from=builder /opt/._detector /opt/._detector -COPY --from=builder /etc/profile.d /etc/profile.d -COPY --from=builder /etc/jug_info /etc/jug_info -COPY --from=builder /etc/eic-env.sh /etc/eic-env.sh -COPY --from=builder /.singularity.d /.singularity.d -COPY --from=builder /usr/bin/docker-shell /usr/bin/docker-shell - -## Use spack entrypoint. NOTE: Requires `set -ex` in all multi-line scripts! -ENV SPACK_ROOT=/opt/spack -SHELL ["docker-shell"] - -## ensure /opt/local is the view, not a symlink -RUN <<EOF -set -ex -rm -rf /opt/local /opt/detector -LOCAL_PREFIX_PATH=$(realpath $(ls /opt/._local/ | tail -n1)) -mv /opt/._local/${LOCAL_PREFIX_PATH} /opt/local -ln -s /opt/local /opt/._local/${LOCAL_PREFIX_PATH} -DETECTOR_PREFIX_PATH=$(realpath $(ls /opt/._detector/ | tail -n1)) -mv /opt/._detector/${DETECTOR_PREFIX_PATH} /opt/detector -ln -s /opt/detector /opt/._detector/${DETECTOR_PREFIX_PATH} -EOF - ## set ROOT TFile forward compatibility RUN sed --in-place --follow-symlinks 's/# \(TFile.v630forwardCompatibility:\) no/\1 yes/' /opt/local/etc/root/system.rootrc @@ -342,7 +339,7 @@ RUN ldconfig ## set the local spack configuration ENV SPACK_DISABLE_LOCAL_CONFIG="true" RUN <<EOF -set -ex +set -e spack config --scope site add "config:install_tree:root:~/spack" spack config --scope site add "config:source_cache:~/.spack/cache" spack config --scope site add "config:binary_index_root:~/.spack" @@ -371,7 +368,7 @@ ADD ${EICWEB}/399/repository/commits/${BENCHMARK_DET_VERSION} /tmp/399.json ADD ${EICWEB}/408/repository/commits/${BENCHMARK_REC_VERSION} /tmp/408.json ADD ${EICWEB}/400/repository/commits/${BENCHMARK_PHY_VERSION} /tmp/400.json RUN <<EOF -set -ex +set -e mkdir -p /opt/benchmarks cd /opt/benchmarks git clone --filter=tree:0 -b ${BENCHMARK_COM_VERSION} --depth 1 https://eicweb.phy.anl.gov/EIC/benchmarks/common_bench.git @@ -394,7 +391,7 @@ ADD https://api.github.com/repos/eic/simulation_campaign_hepmc3/commits/${CAMPAI ADD https://api.github.com/repos/eic/job_submission_condor/commits/${CAMPAIGNS_CONDOR_VERSION} /tmp/job_submission_condor.json ADD https://api.github.com/repos/eic/job_submission_slurm/commits/${CAMPAIGNS_SLURM_VERSION} /tmp/job_submission_slurm.json RUN <<EOF -set -ex +set -e mkdir -p /opt/campaigns cd /opt/campaigns git clone --filter=tree:0 -b ${CAMPAIGNS_SINGLE_VERSION} --depth 1 https://github.com/eic/simulation_campaign_single.git single