Skip to content

Shrink prod Docker image via multi-stage build#13

Open
Bensonheimer992 wants to merge 3 commits into
kasteckis:masterfrom
Bensonheimer992:master
Open

Shrink prod Docker image via multi-stage build#13
Bensonheimer992 wants to merge 3 commits into
kasteckis:masterfrom
Bensonheimer992:master

Conversation

@Bensonheimer992

Copy link
Copy Markdown

Restructures the Dockerfile to drop Node.js, git, and Composer from the
production runtime image. Frontend assets and PHP dependencies are now
built once in dedicated builder stages and copied into a slim final image.

Copilot AI review requested due to automatic review settings May 1, 2026 12:36
@Bensonheimer992

Copy link
Copy Markdown
Author

Also the first startup is faster now

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restructures the container build to produce a slimmer production image by moving Composer dependency installation and webpack asset compilation into dedicated builder stages, then copying the built artifacts into a minimal runtime stage.

Changes:

  • Add php_builder and node_builder stages to build prod PHP deps and frontend assets once during docker build.
  • Split frankenphp_base into frankenphp_dev (with composer/node/git/xdebug) and frankenphp_prod (minimal runtime).
  • Update the entrypoint to avoid requiring Composer/npm in the prod runtime image.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
Dockerfile Introduces multi-stage builders and a minimal prod stage; reworks dev stage tooling installation.
frankenphp/docker-entrypoint.sh Makes Composer/npm steps conditional and replaces Composer auto-scripts with direct Symfony console commands.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Dockerfile
COMPOSER_CACHE_DIR=/tmp/composer-cache \
composer install --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress

COPY --link --exclude=frankenphp/ . ./

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COPY --exclude=frankenphp/ requires a Dockerfile frontend that supports the --exclude flag; with #syntax=docker/dockerfile:1 this may fail on builders that don't have the newer BuildKit frontend enabled. Consider either bumping the syntax directive to a frontend version that guarantees COPY --exclude support, or avoid --exclude by using .dockerignore/more targeted COPY steps.

Copilot uses AI. Check for mistakes.
Comment thread Dockerfile

# Base FrankenPHP image
# ---------------------------------------------------------------
# Builder: install prod vendor, dump autoload, warm Symfony cache

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says this stage "warm[s] Symfony cache", but the stage only runs composer dump-autoload/dump-env and never executes bin/console cache:clear/cache:warmup. Either update the comment to match what’s actually happening, or add an explicit cache warmup step (ideally in the builder so runtime startup doesn’t have to rebuild it).

Suggested change
# Builder: install prod vendor, dump autoload, warm Symfony cache
# Builder: install prod vendor, dump autoload, dump env

Copilot uses AI. Check for mistakes.
Comment on lines +43 to 45
php bin/console cache:clear --no-debug
php bin/console assets:install public --no-debug

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cache:clear and assets:install are always executed with --no-debug. In the dev image APP_ENV=dev and APP_DEBUG is typically on; forcing --no-debug here can generate a cache that doesn’t match the runtime debug setting and can make debugging behavior inconsistent. Consider making --no-debug conditional on APP_ENV=prod (or using the current APP_DEBUG value) instead of hard-coding it.

Suggested change
php bin/console cache:clear --no-debug
php bin/console assets:install public --no-debug
NO_DEBUG_FLAG=''
if [ "${APP_ENV:-}" = 'prod' ] || [ "${APP_DEBUG:-}" = '0' ] || [ "${APP_DEBUG:-}" = 'false' ]; then
NO_DEBUG_FLAG='--no-debug'
fi
php bin/console cache:clear ${NO_DEBUG_FLAG}
php bin/console assets:install public ${NO_DEBUG_FLAG}

Copilot uses AI. Check for mistakes.
Comment on lines +43 to 45
php bin/console cache:clear --no-debug
php bin/console assets:install public --no-debug

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entrypoint clears the Symfony cache and installs bundle assets on every container start. With the new multi-stage build (pre-built vendor/assets), doing this work at runtime increases startup time and reduces the benefit of building/warming once during the image build. Consider moving these steps into the php_builder stage for frankenphp_prod, or guarding them (e.g., only when the cache/assets directories are missing or behind an env flag).

Suggested change
php bin/console cache:clear --no-debug
php bin/console assets:install public --no-debug
RUN_SYMFONY_RUNTIME_SETUP="${RUN_SYMFONY_RUNTIME_SETUP:-0}"
if [ "$RUN_SYMFONY_RUNTIME_SETUP" = "1" ] || [ -z "$(ls -A 'var/cache/' 2>/dev/null)" ]; then
php bin/console cache:clear --no-debug
fi
if [ "$RUN_SYMFONY_RUNTIME_SETUP" = "1" ] || [ -z "$(ls -A 'public/bundles/' 2>/dev/null)" ]; then
php bin/console assets:install public --no-debug
fi

Copilot uses AI. Check for mistakes.
Comment thread Dockerfile
Comment on lines +127 to +129
&& apt-get install -y --no-install-recommends git \
&& curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dev image installs Node.js by piping a remote script into bash (curl ... | bash). This pattern makes builds harder to audit/reproduce and is a supply-chain risk. Prefer installing Node via a pinned, verified package source (or using a dedicated node base image / official Debian packages) to avoid executing unpinned remote code during builds.

Suggested change
&& apt-get install -y --no-install-recommends git \
&& curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& apt-get install -y --no-install-recommends \
git \
nodejs \
npm \

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants