From 176d385753fb09c0cf4437cfb487e934fafc6f39 Mon Sep 17 00:00:00 2001 From: Stanislav Matveyev Date: Tue, 21 Oct 2025 20:30:05 +0300 Subject: [PATCH 1/6] CC-36444: composer vendor folder usage --- images/baked/application/Dockerfile | 19 ++++++++++++------- images/baked/cli/Dockerfile | 11 ++++++----- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/images/baked/application/Dockerfile b/images/baked/application/Dockerfile index fa0e20bcd..fa5be2895 100644 --- a/images/baked/application/Dockerfile +++ b/images/baked/application/Dockerfile @@ -5,14 +5,19 @@ FROM ${SPRYKER_PARENT_IMAGE} AS application-production-dependencies USER spryker -# Install composer modules for Spryker COPY --chown=spryker:spryker composer.json composer.lock ${srcRoot}/ -ARG SPRYKER_COMPOSER_MODE -ARG SPRYKER_COMPOSER_VERBOSE -RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ - --mount=type=ssh,uid=1000 --mount=type=secret,id=secrets-env,uid=1000 \ - set -o allexport && . /run/secrets/secrets-env && set +o allexport \ - && composer install --no-scripts --no-interaction ${SPRYKER_COMPOSER_MODE} ${SPRYKER_COMPOSER_VERBOSE} +COPY --chown=spryker:spryker vendor ${srcRoot}/vendor + +# Install composer modules for Spryker only if vendor is missing +#ARG SPRYKER_COMPOSER_MODE +#ARG SPRYKER_COMPOSER_VERBOSE +#RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ +# --mount=type=ssh,uid=1000 \ +# --mount=type=secret,id=secrets-env,uid=1000 \ +# bash -c 'if [ ! -d "${srcRoot}/vendor" ] || [ -z "$(ls -A ${srcRoot}/vendor)" ]; then \ +# set -o allexport && . /run/secrets/secrets-env && set +o allexport \ +# && composer install --no-scripts --no-interaction ${SPRYKER_COMPOSER_MODE} ${SPRYKER_COMPOSER_VERBOSE}; \ +# fi' FROM application-production-dependencies AS application-production-codebase diff --git a/images/baked/cli/Dockerfile b/images/baked/cli/Dockerfile index a019d0e4b..5e43e167a 100644 --- a/images/baked/cli/Dockerfile +++ b/images/baked/cli/Dockerfile @@ -7,11 +7,12 @@ USER spryker # Install composer modules for Spryker COPY --chown=spryker:spryker composer.json composer.lock ${srcRoot}/ -ARG SPRYKER_COMPOSER_MODE -RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ - --mount=type=ssh,uid=1000 --mount=type=secret,id=secrets-env,uid=1000 \ - set -o allexport && . /run/secrets/secrets-env && set +o allexport \ - && composer install --no-interaction ${SPRYKER_COMPOSER_MODE} + +#ARG SPRYKER_COMPOSER_MODE +#RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ +# --mount=type=ssh,uid=1000 --mount=type=secret,id=secrets-env,uid=1000 \ +# set -o allexport && . /run/secrets/secrets-env && set +o allexport \ +# && composer install --no-interaction ${SPRYKER_COMPOSER_MODE} ARG SPRYKER_COMPOSER_AUTOLOAD RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ From bbc84a484711f83e3e31fd4af83a373c6aea0a35 Mon Sep 17 00:00:00 2001 From: Stanislav Matveyev Date: Wed, 22 Oct 2025 01:12:53 +0300 Subject: [PATCH 2/6] CC-36444: added docker cache for composer from host machine --- bin/sdk/images/common.sh | 4 ++ bin/sdk/images/prepopulate-composer-cache.sh | 42 ++++++++++++++++++++ images/baked/application/Dockerfile | 19 ++++----- images/baked/cli/Dockerfile | 12 +++--- 4 files changed, 60 insertions(+), 17 deletions(-) create mode 100755 bin/sdk/images/prepopulate-composer-cache.sh diff --git a/bin/sdk/images/common.sh b/bin/sdk/images/common.sh index e46fa197b..ee4d7b346 100644 --- a/bin/sdk/images/common.sh +++ b/bin/sdk/images/common.sh @@ -45,6 +45,10 @@ function Images::_buildApp() { sshArgument=('--ssh' 'default') fi + # Pre-populate Docker BuildKit composer cache from host + Console::verbose "${INFO}Pre-populating composer cache...${NC}" + bash "${BASH_SOURCE%/*}/prepopulate-composer-cache.sh" || Console::verbose "${WARN}Cache pre-population skipped${NC}" + Images::_prepareSecrets Registry::Trap::addExitHook 'removeBuildSecrets' "rm -f ${SECRETS_FILE_PATH}" diff --git a/bin/sdk/images/prepopulate-composer-cache.sh b/bin/sdk/images/prepopulate-composer-cache.sh new file mode 100755 index 000000000..dd8d74efe --- /dev/null +++ b/bin/sdk/images/prepopulate-composer-cache.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +# Pre-populate Docker BuildKit composer cache from host composer cache +# This speeds up Docker builds by copying existing composer packages into Docker's cache mount + +set -e + +COMPOSER_CACHE_DIR=$(composer config cache-dir) + +echo "Pre-populating Docker BuildKit cache from ${COMPOSER_CACHE_DIR}" + +if [ ! -d "${COMPOSER_CACHE_DIR}" ]; then + echo "Warning: Composer cache directory ${COMPOSER_CACHE_DIR} does not exist. Skipping pre-population." + exit 0 +fi + +# Create a temporary Dockerfile to copy cache into Docker's cache mount +cat > /tmp/prepopulate-cache.Dockerfile <<'EOF' +FROM alpine:latest +ARG COMPOSER_CACHE_DIR +RUN --mount=type=cache,id=composer,sharing=locked,target=/cache \ + if [ -n "$(ls -A /source 2>/dev/null)" ]; then \ + echo "Copying composer cache to Docker cache mount..."; \ + cp -a /source/. /cache/ || true; \ + echo "Cache pre-population complete. Files in cache:"; \ + ls -lah /cache | head -20; \ + else \ + echo "No files to copy from source cache"; \ + fi +EOF + +# Build the temporary image to populate the cache +DOCKER_BUILDKIT=1 docker build \ + --build-arg COMPOSER_CACHE_DIR="${COMPOSER_CACHE_DIR}" \ + --mount type=bind,source="${COMPOSER_CACHE_DIR}",target=/source \ + -f /tmp/prepopulate-cache.Dockerfile \ + /tmp + +rm -f /tmp/prepopulate-cache.Dockerfile + +echo "Docker BuildKit composer cache pre-populated successfully!" + diff --git a/images/baked/application/Dockerfile b/images/baked/application/Dockerfile index fa5be2895..a4e9e11bb 100644 --- a/images/baked/application/Dockerfile +++ b/images/baked/application/Dockerfile @@ -5,19 +5,16 @@ FROM ${SPRYKER_PARENT_IMAGE} AS application-production-dependencies USER spryker +# Install composer modules for Spryker COPY --chown=spryker:spryker composer.json composer.lock ${srcRoot}/ -COPY --chown=spryker:spryker vendor ${srcRoot}/vendor -# Install composer modules for Spryker only if vendor is missing -#ARG SPRYKER_COMPOSER_MODE -#ARG SPRYKER_COMPOSER_VERBOSE -#RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ -# --mount=type=ssh,uid=1000 \ -# --mount=type=secret,id=secrets-env,uid=1000 \ -# bash -c 'if [ ! -d "${srcRoot}/vendor" ] || [ -z "$(ls -A ${srcRoot}/vendor)" ]; then \ -# set -o allexport && . /run/secrets/secrets-env && set +o allexport \ -# && composer install --no-scripts --no-interaction ${SPRYKER_COMPOSER_MODE} ${SPRYKER_COMPOSER_VERBOSE}; \ -# fi' +ARG SPRYKER_COMPOSER_MODE +ARG SPRYKER_COMPOSER_VERBOSE +RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ + --mount=type=ssh,uid=1000 \ + --mount=type=secret,id=secrets-env,uid=1000 \ + set -o allexport && . /run/secrets/secrets-env && set +o allexport \ + && composer install --no-scripts --no-interaction ${SPRYKER_COMPOSER_MODE} ${SPRYKER_COMPOSER_VERBOSE} FROM application-production-dependencies AS application-production-codebase diff --git a/images/baked/cli/Dockerfile b/images/baked/cli/Dockerfile index 5e43e167a..10dd70c49 100644 --- a/images/baked/cli/Dockerfile +++ b/images/baked/cli/Dockerfile @@ -7,12 +7,12 @@ USER spryker # Install composer modules for Spryker COPY --chown=spryker:spryker composer.json composer.lock ${srcRoot}/ - -#ARG SPRYKER_COMPOSER_MODE -#RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ -# --mount=type=ssh,uid=1000 --mount=type=secret,id=secrets-env,uid=1000 \ -# set -o allexport && . /run/secrets/secrets-env && set +o allexport \ -# && composer install --no-interaction ${SPRYKER_COMPOSER_MODE} +ARG SPRYKER_COMPOSER_MODE +RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ + --mount=type=ssh,uid=1000 \ + --mount=type=secret,id=secrets-env,uid=1000 \ + set -o allexport && . /run/secrets/secrets-env && set +o allexport \ + && composer install --no-interaction ${SPRYKER_COMPOSER_MODE} ARG SPRYKER_COMPOSER_AUTOLOAD RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ From bdfe36037434b696f5b777a3ee5eb010eb9f4f9c Mon Sep 17 00:00:00 2001 From: Stanislav Matveyev Date: Wed, 22 Oct 2025 11:08:59 +0300 Subject: [PATCH 3/6] CC-36444: fixed the cache population step --- bin/sdk/images/common.sh | 2 +- bin/sdk/images/prepopulate-composer-cache.sh | 36 +++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/bin/sdk/images/common.sh b/bin/sdk/images/common.sh index ee4d7b346..7429c2159 100644 --- a/bin/sdk/images/common.sh +++ b/bin/sdk/images/common.sh @@ -47,7 +47,7 @@ function Images::_buildApp() { # Pre-populate Docker BuildKit composer cache from host Console::verbose "${INFO}Pre-populating composer cache...${NC}" - bash "${BASH_SOURCE%/*}/prepopulate-composer-cache.sh" || Console::verbose "${WARN}Cache pre-population skipped${NC}" + bash "${BASH_SOURCE%/*}/prepopulate-composer-cache.sh" Images::_prepareSecrets Registry::Trap::addExitHook 'removeBuildSecrets' "rm -f ${SECRETS_FILE_PATH}" diff --git a/bin/sdk/images/prepopulate-composer-cache.sh b/bin/sdk/images/prepopulate-composer-cache.sh index dd8d74efe..5d5de91df 100755 --- a/bin/sdk/images/prepopulate-composer-cache.sh +++ b/bin/sdk/images/prepopulate-composer-cache.sh @@ -5,6 +5,12 @@ set -e +# Check if composer is installed +if ! command -v composer &> /dev/null; then + echo "Warning: composer command not found. Skipping cache pre-population." + exit 0 +fi + COMPOSER_CACHE_DIR=$(composer config cache-dir) echo "Pre-populating Docker BuildKit cache from ${COMPOSER_CACHE_DIR}" @@ -14,16 +20,25 @@ if [ ! -d "${COMPOSER_CACHE_DIR}" ]; then exit 0 fi +# Create a temporary directory for the build context +TEMP_CONTEXT=$(mktemp -d) +trap "rm -rf ${TEMP_CONTEXT}" EXIT + +# Copy composer cache to temporary context +echo "Copying cache to temporary context..." +mkdir -p "${TEMP_CONTEXT}/cache" +cp -a "${COMPOSER_CACHE_DIR}/." "${TEMP_CONTEXT}/cache/" 2>/dev/null || true + # Create a temporary Dockerfile to copy cache into Docker's cache mount -cat > /tmp/prepopulate-cache.Dockerfile <<'EOF' +cat > "${TEMP_CONTEXT}/Dockerfile" <<'EOF' FROM alpine:latest -ARG COMPOSER_CACHE_DIR +COPY cache /cache-source RUN --mount=type=cache,id=composer,sharing=locked,target=/cache \ - if [ -n "$(ls -A /source 2>/dev/null)" ]; then \ + if [ -n "$(ls -A /cache-source 2>/dev/null)" ]; then \ echo "Copying composer cache to Docker cache mount..."; \ - cp -a /source/. /cache/ || true; \ - echo "Cache pre-population complete. Files in cache:"; \ - ls -lah /cache | head -20; \ + cp -a /cache-source/. /cache/ 2>/dev/null || true; \ + echo "Cache pre-population complete. Cache directory size:"; \ + du -sh /cache 2>/dev/null || echo "Cache populated"; \ else \ echo "No files to copy from source cache"; \ fi @@ -31,12 +46,7 @@ EOF # Build the temporary image to populate the cache DOCKER_BUILDKIT=1 docker build \ - --build-arg COMPOSER_CACHE_DIR="${COMPOSER_CACHE_DIR}" \ - --mount type=bind,source="${COMPOSER_CACHE_DIR}",target=/source \ - -f /tmp/prepopulate-cache.Dockerfile \ - /tmp - -rm -f /tmp/prepopulate-cache.Dockerfile + -f "${TEMP_CONTEXT}/Dockerfile" \ + "${TEMP_CONTEXT}" echo "Docker BuildKit composer cache pre-populated successfully!" - From 7efaef7bd6c7dc970cdcb9956abae995f0a058e4 Mon Sep 17 00:00:00 2001 From: Stanislav Matveyev Date: Wed, 22 Oct 2025 11:22:07 +0300 Subject: [PATCH 4/6] CC-36444: fixed the cache population step 2 --- bin/sdk/images/prepopulate-composer-cache.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bin/sdk/images/prepopulate-composer-cache.sh b/bin/sdk/images/prepopulate-composer-cache.sh index 5d5de91df..4bb938ae1 100755 --- a/bin/sdk/images/prepopulate-composer-cache.sh +++ b/bin/sdk/images/prepopulate-composer-cache.sh @@ -30,15 +30,18 @@ mkdir -p "${TEMP_CONTEXT}/cache" cp -a "${COMPOSER_CACHE_DIR}/." "${TEMP_CONTEXT}/cache/" 2>/dev/null || true # Create a temporary Dockerfile to copy cache into Docker's cache mount +# Using the same cache id and target path as the main Dockerfile cat > "${TEMP_CONTEXT}/Dockerfile" <<'EOF' FROM alpine:latest -COPY cache /cache-source -RUN --mount=type=cache,id=composer,sharing=locked,target=/cache \ +RUN adduser -u 1000 -D spryker +USER spryker +COPY --chown=spryker:spryker cache /cache-source +RUN --mount=type=cache,id=composer,sharing=locked,target=/home/spryker/.composer/cache,uid=1000 \ if [ -n "$(ls -A /cache-source 2>/dev/null)" ]; then \ echo "Copying composer cache to Docker cache mount..."; \ - cp -a /cache-source/. /cache/ 2>/dev/null || true; \ + cp -a /cache-source/. /home/spryker/.composer/cache/ 2>/dev/null || true; \ echo "Cache pre-population complete. Cache directory size:"; \ - du -sh /cache 2>/dev/null || echo "Cache populated"; \ + du -sh /home/spryker/.composer/cache 2>/dev/null || echo "Cache populated"; \ else \ echo "No files to copy from source cache"; \ fi From 1aeacb07c446f94c016749b97bef3c0aa6fd0bbf Mon Sep 17 00:00:00 2001 From: Stanislav Matveyev Date: Wed, 22 Oct 2025 14:48:04 +0300 Subject: [PATCH 5/6] CC-36444: fixed the cache population step 3 --- bin/sdk/images/common.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/sdk/images/common.sh b/bin/sdk/images/common.sh index 7429c2159..75daec851 100644 --- a/bin/sdk/images/common.sh +++ b/bin/sdk/images/common.sh @@ -46,8 +46,10 @@ function Images::_buildApp() { fi # Pre-populate Docker BuildKit composer cache from host - Console::verbose "${INFO}Pre-populating composer cache...${NC}" - bash "${BASH_SOURCE%/*}/prepopulate-composer-cache.sh" + if [ "${folder}" == "baked" ]; then + Console::verbose "${INFO}Pre-populating composer cache...${NC}" + bash "${BASH_SOURCE%/*}/prepopulate-composer-cache.sh" + fi Images::_prepareSecrets Registry::Trap::addExitHook 'removeBuildSecrets' "rm -f ${SECRETS_FILE_PATH}" From 31c69c740e9e0dc5a82a361a7f6d011d2e2deb25 Mon Sep 17 00:00:00 2001 From: Stanislav Matveyev Date: Thu, 23 Oct 2025 11:32:41 +0300 Subject: [PATCH 6/6] CC-36444: added early return when cache folder is empty --- bin/sdk/images/prepopulate-composer-cache.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/sdk/images/prepopulate-composer-cache.sh b/bin/sdk/images/prepopulate-composer-cache.sh index 4bb938ae1..9d5e58270 100755 --- a/bin/sdk/images/prepopulate-composer-cache.sh +++ b/bin/sdk/images/prepopulate-composer-cache.sh @@ -13,13 +13,13 @@ fi COMPOSER_CACHE_DIR=$(composer config cache-dir) -echo "Pre-populating Docker BuildKit cache from ${COMPOSER_CACHE_DIR}" - -if [ ! -d "${COMPOSER_CACHE_DIR}" ]; then - echo "Warning: Composer cache directory ${COMPOSER_CACHE_DIR} does not exist. Skipping pre-population." +if [ -z "$(ls -A "${COMPOSER_CACHE_DIR}" 2>/dev/null | grep -v '^\.htaccess$')" ]; then + echo "Warning: Composer cache directory ${COMPOSER_CACHE_DIR} is empty (excluding .htaccess). Skipping pre-population." exit 0 fi +echo "Pre-populating Docker BuildKit cache from ${COMPOSER_CACHE_DIR}" + # Create a temporary directory for the build context TEMP_CONTEXT=$(mktemp -d) trap "rm -rf ${TEMP_CONTEXT}" EXIT