diff --git a/.github/workflows/dockerhub-on-version.yml b/.github/workflows/dockerhub-on-version.yml index 5e89d89..5092ca5 100644 --- a/.github/workflows/dockerhub-on-version.yml +++ b/.github/workflows/dockerhub-on-version.yml @@ -2,7 +2,7 @@ name: Build & Push Docker image on package version change on: push: - branches: [ main, vcf_sanity_check ] + branches: [ main, docker_fix ] paths: - .github/workflows/dockerhub-on-version.yml - Dockerfile @@ -16,7 +16,7 @@ concurrency: env: IMAGE: docker.io/breedinginsight/bigapp IMAGE_DEPS: docker.io/breedinginsight/bigapp-deps - DEPS_TAG: r4.5-bioc3.21-2025-08 + DEPS_TAG: latest jobs: check-version: @@ -71,6 +71,7 @@ jobs: file: Dockerfile platforms: linux/amd64 push: true + pull: true build-args: | BASE_IMAGE=${{ env.IMAGE_DEPS }}:${{ env.DEPS_TAG }} tags: ${{ steps.meta.outputs.tags }} @@ -106,6 +107,7 @@ jobs: file: Dockerfile platforms: linux/arm64 push: true + pull: true build-args: | BASE_IMAGE=${{ env.IMAGE_DEPS }}:${{ env.DEPS_TAG }} tags: ${{ steps.meta.outputs.tags }} diff --git a/Dockerfile b/Dockerfile index d783a35..c3c0973 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1.7 # Buildx/Actions will pass BASE_IMAGE as a manifest tag that covers both arches -ARG BASE_IMAGE=docker.io/breedinginsight/bigapp-deps:r4.5-bioc3.21-2025-08 +ARG BASE_IMAGE=docker.io/breedinginsight/bigapp-deps:latest FROM ${BASE_IMAGE} SHELL ["/bin/bash","-eo","pipefail","-c"] @@ -13,7 +13,9 @@ COPY DESCRIPTION /app/ # COPY NAMESPACE /app/ # if present, include for better cache hits COPY . /app RUN R -q -e "remotes::install_local('.', upgrade='never', dependencies=TRUE, \ - INSTALL_opts=c('--no-build-vignettes','--no-manual'))" + INSTALL_opts=c('--no-build-vignettes','--no-manual')); \ + library(BIGapp)" \ + || (echo 'ERROR: BIGapp or one of its dependencies failed to install' >&2; exit 1) # Runtime RUN useradd -m appuser diff --git a/inst/Dockerfile.deps b/inst/Dockerfile.deps index 0c48941..2736762 100644 --- a/inst/Dockerfile.deps +++ b/inst/Dockerfile.deps @@ -20,9 +20,10 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ r-cran-remotes r-cran-pak r-cran-biocmanager \ && rm -rf /var/lib/apt/lists/* -# ccache +# ccache (scoped to this R/Bioc combo so a base-image bump can't reuse stale, ABI-incompatible objects) +ARG DEPS_TAG=r4.5-bioc3.21-2025-08 ENV CCACHE_DIR=/root/.cache/ccache -RUN --mount=type=cache,target=/root/.cache/ccache ccache -M 2G && \ +RUN --mount=type=cache,target=/root/.cache/ccache,id=ccache-${DEPS_TAG} ccache -M 2G && \ { echo 'CC=ccache gcc'; echo 'CXX=ccache g++'; echo 'FC=ccache gfortran'; } >> /usr/lib/R/etc/Makevars.site # ---- CRAN via r2u binaries first (fast) ---- @@ -33,12 +34,12 @@ shinyWidgets shinyjs shinydisconnect shinyalert \ stringr updog AGHmatrix factoextra \ httr future shinycssloaders RColorBrewer \ tibble rrBLUP MASS Matrix matrixcalc BIGr" -RUN install2.r --skipinstalled --ncpus 1 $CRAN_PKGS || true +RUN install2.r --skipinstalled --ncpus 1 $CRAN_PKGS -# ---- Bioconductor from source (R 4.5 -> Bioc 3.21) ---- -RUN --mount=type=cache,target=/root/.cache/R/src Rscript - <<'RS' +# ---- Bioconductor from source (version auto-matched to whatever R the base image ships) ---- +RUN --mount=type=cache,target=/root/.cache/R/src,id=rsrc-${DEPS_TAG} Rscript - <<'RS' options(Ncpus = 2) -repos <- BiocManager::repositories(version = "3.21") +repos <- BiocManager::repositories() options(repos = repos) bioc_pkgs <- c("Rsamtools","Biostrings","pwalign","VariantAnnotation") for (p in bioc_pkgs) { @@ -47,11 +48,12 @@ for (p in bioc_pkgs) { install.packages(p, dependencies = TRUE, type = "source", INSTALL_opts = c("--no-build-vignettes","--no-manual")) } + library(p, character.only = TRUE) } RS # ---- Fallback for any missing CRAN pkgs (source, sequential) ---- -RUN --mount=type=cache,target=/root/.cache/R/src Rscript - <<'RS' +RUN --mount=type=cache,target=/root/.cache/R/src,id=rsrc-${DEPS_TAG} Rscript - <<'RS' pkgs <- strsplit(Sys.getenv("CRAN_PKGS"), " +")[[1]] miss <- setdiff(pkgs, rownames(installed.packages())) if (length(miss)) { @@ -61,11 +63,14 @@ if (length(miss)) { INSTALL_opts=c("--no-build-vignettes","--no-manual")) } } +# Hard-fail the build if any package is installed but fails to actually load (e.g. ABI mismatch) +for (p in pkgs) library(p, character.only = TRUE) RS # ---- GitHub dep (pak-free to avoid QEMU helper issues) ---- RUN R -q -e "remotes::install_github('jendelman/GWASpoly', upgrade='never', dependencies=TRUE, \ - INSTALL_opts=c('--no-build-vignettes','--no-manual'))" + INSTALL_opts=c('--no-build-vignettes','--no-manual')); \ + library(GWASpoly)" # Version snapshot (handy for audits) RUN R -q -e "pkgs <- c('adegenet','curl','DT','dplyr','vcfR','ggplot2','tidyr','shiny','config','bs4Dash', \ diff --git a/inst/update_dep_image.sh b/inst/update_dep_image.sh index 094b96c..b5e9c2c 100644 --- a/inst/update_dep_image.sh +++ b/inst/update_dep_image.sh @@ -1,3 +1,6 @@ +#!/bin/bash +set -euo pipefail + # The arm64 image is too large to load with Github actions # So we build and push locally with the following commands @@ -6,27 +9,42 @@ # Make sure to login with BI user IMAGE_DEPS=docker.io/breedinginsight/bigapp-deps -DEPS_TAG=r4.5-bioc3.21-2025-08 # Update version here +BUILD_ID=build-$(date +%s) # throwaway tag used only to inspect the freshly built image -# amd64 (load locally instead of pushing) +# amd64 (load locally so we can inspect it before deciding the real tag) docker buildx build \ -f Dockerfile.deps \ --platform linux/amd64 \ - -t $IMAGE_DEPS:$DEPS_TAG-amd64 \ + -t $IMAGE_DEPS:$BUILD_ID-amd64 \ --progress=plain \ --load \ . +# Derive DEPS_TAG from what's actually inside the image (R version, Bioc version, build date) +# instead of hardcoding it, so the tag can never drift from reality. +R_VER=$(docker run --rm $IMAGE_DEPS:$BUILD_ID-amd64 Rscript -e 'cat(R.version$major, sub("\\..*", "", R.version$minor), sep=".")') +BIOC_VER=$(docker run --rm $IMAGE_DEPS:$BUILD_ID-amd64 Rscript -e 'cat(as.character(BiocManager::version()))') +DEPS_TAG="r${R_VER}-bioc${BIOC_VER}-$(date +%Y-%m)" +echo "Resolved DEPS_TAG=$DEPS_TAG" + +docker tag $IMAGE_DEPS:$BUILD_ID-amd64 $IMAGE_DEPS:$DEPS_TAG-amd64 +docker rmi $IMAGE_DEPS:$BUILD_ID-amd64 +docker push $IMAGE_DEPS:$DEPS_TAG-amd64 + # arm64 (push or save to a tar; cannot load multi-arch to local daemon) docker buildx build \ -f Dockerfile.deps \ --platform linux/arm64 \ + --build-arg DEPS_TAG=$DEPS_TAG \ -t $IMAGE_DEPS:$DEPS_TAG-arm64 \ --progress=plain \ --push \ . - + docker buildx imagetools create \ -t $IMAGE_DEPS:$DEPS_TAG \ + -t $IMAGE_DEPS:latest \ $IMAGE_DEPS:$DEPS_TAG-amd64 \ - $IMAGE_DEPS:$DEPS_TAG-arm64 \ No newline at end of file + $IMAGE_DEPS:$DEPS_TAG-arm64 + +echo "Pushed $IMAGE_DEPS:$DEPS_TAG and $IMAGE_DEPS:latest" \ No newline at end of file