diff --git a/bin/sdk/images/common.sh b/bin/sdk/images/common.sh index e46fa197b..75daec851 100644 --- a/bin/sdk/images/common.sh +++ b/bin/sdk/images/common.sh @@ -45,6 +45,12 @@ function Images::_buildApp() { sshArgument=('--ssh' 'default') fi + # Pre-populate Docker BuildKit composer cache from host + 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}" diff --git a/bin/sdk/images/prepopulate-composer-cache.sh b/bin/sdk/images/prepopulate-composer-cache.sh new file mode 100755 index 000000000..9d5e58270 --- /dev/null +++ b/bin/sdk/images/prepopulate-composer-cache.sh @@ -0,0 +1,55 @@ +#!/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 + +# 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) + +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 + +# 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 +# Using the same cache id and target path as the main Dockerfile +cat > "${TEMP_CONTEXT}/Dockerfile" <<'EOF' +FROM alpine:latest +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/. /home/spryker/.composer/cache/ 2>/dev/null || true; \ + echo "Cache pre-population complete. Cache directory size:"; \ + du -sh /home/spryker/.composer/cache 2>/dev/null || echo "Cache populated"; \ + else \ + echo "No files to copy from source cache"; \ + fi +EOF + +# Build the temporary image to populate the cache +DOCKER_BUILDKIT=1 docker build \ + -f "${TEMP_CONTEXT}/Dockerfile" \ + "${TEMP_CONTEXT}" + +echo "Docker BuildKit composer cache pre-populated successfully!" diff --git a/images/baked/application/Dockerfile b/images/baked/application/Dockerfile index fa0e20bcd..a4e9e11bb 100644 --- a/images/baked/application/Dockerfile +++ b/images/baked/application/Dockerfile @@ -7,12 +7,14 @@ 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} + --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 a019d0e4b..10dd70c49 100644 --- a/images/baked/cli/Dockerfile +++ b/images/baked/cli/Dockerfile @@ -9,9 +9,10 @@ USER 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} + --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 \