Skip to content

Support a single docker image for deployments - #14362

Merged
nothingrandom merged 4 commits into
masterfrom
single-docker-image
Aug 3, 2026
Merged

Support a single docker image for deployments#14362
nothingrandom merged 4 commits into
masterfrom
single-docker-image

Conversation

@nothingrandom

@nothingrandom nothingrandom commented Jul 30, 2026

Copy link
Copy Markdown
Member

Fixes mozilla/addons#2184

Summary

Moves the webpack production build out of container startup and into image build time. Today every app instance (and the static-upload job) starts with npm run build && … npm start, and that webpack build takes 2 to 5 minutes per instance, which delays every pod start and every rollout.

Env-specific values (apiHost, baseURL, fxaConfig, extensionWorkshopUrl, langs, and so on) are baked into the client bundle via webpack's DefinePlugin (CLIENT_CONFIG), so a single generic bundle can't serve every environment. The browser bundle is frozen at build time and can't be overridden by a runtime env var. So we build one bundle per env at image build time and select the right one at container start. This matches OPs' preference for a single generic image switched by one env var.

Why

Runtime env-var overrides only rebind server config. The browser bundle (src/amo/api/index.js calls config.get('apiHost'), which resolves from the frozen CLIENT_CONFIG on the client) is fixed at build time. I verified locally that the per-env bundles differ: the stage bundle bakes in addons.allizom.org, the prod bundle only addons.mozilla.org. So per-env builds are required, not optional.

Notes

  • Release CI does three webpack builds instead of one. That cost is paid once per release rather than once per instance. The image is also larger, since it carries three copies of static/. PR builds stay single-env, so PR turnaround is unaffected.
  • The startup speedup needs the companion webservices-infra PR (https://github.com/mozilla/webservices-infra/pull/11975), which drops npm run build from the deployment command and the static-upload job. This image change is backward compatible on its own: the old sh -c "npm run build && npm start" override still works against this image.

Local validation / testing

Everything below was run locally against the npm layer. The Docker layer wraps these same commands.

1. Build two envs and confirm the bundles genuinely differ per env:

PREBUILD_ENVS=stage,prod npm run build:prebuilt

# main entry bundle differs byte-for-byte between envs, and bakes the right host
for e in stage prod; do
  main=$(ls dist-prebuilt/$e/static/ | grep -E '^amo-[0-9a-f]+\.js$')
  echo "$e -> $main"
  grep -aoE "https://(internal-api\.)?addons[a-z0-9.-]*\.(mozilla\.org|allizom\.org)" \
    "dist-prebuilt/$e/static/$main" | sort -u
done

Expected:

  • stage amo-4f3f13b1... (contains addons.allizom.org)
  • prod amo-0ad27136... (contains addons.mozilla.org)

2. Boot with prebuilt STAGE assets, no build at start:

NODE_ENV=production NODE_CONFIG_ENV=stage SERVER_HOST=0.0.0.0 SERVER_PORT=4000 \
  API_HOST=https://internal-api.addons.allizom.org \
  npm run start:prebuilt

curl -sf http://localhost:4000/__frontend_lbheartbeat__          # HTTP 200
curl -s  http://localhost:4000/en-US/firefox/ | grep -oE 'amo-[0-9a-f]+\.js' | sort -u

Expected:

  • the server log shows apiHost:https://internal-api.addons.allizom.org
  • the served HTML references the stage bundle amo-4f3f13b1...

3. Switch to PROD against the same artifacts, still no build:

NODE_ENV=production NODE_CONFIG_ENV=prod SERVER_HOST=0.0.0.0 SERVER_PORT=4000 \
  API_HOST=https://internal-api.addons.mozilla.org \
  npm run start:prebuilt

curl -sf http://localhost:4000/__frontend_lbheartbeat__          # HTTP 200
curl -s  http://localhost:4000/en-US/firefox/ | grep -oE 'amo-[0-9a-f]+\.js' | sort -u

Expected:

  • the server log shows apiHost:https://internal-api.addons.mozilla.org
  • the served page uses the prod bundle amo-0ad27136...
  • heartbeat 200
  • no build ran

4. (Optional) Docker end-to-end:

# version.json is normally written by the build-docker action into the context
printf '{"commit":"local","version":"ci","source":"local","build":"local"}\n' > version.json
docker build --build-arg PREBUILD_ENVS=prod -t amo-frontend:prebuilt-test .
docker run --rm -p 4000:4000 -e NODE_ENV=production -e NODE_CONFIG_ENV=prod amo-frontend:prebuilt-test
curl -sf http://localhost:4000/__frontend_lbheartbeat__          # expect HTTP 200
git checkout -- version.json   # discard the stub

@nothingrandom
nothingrandom requested review from a team and eviljeff and removed request for a team July 30, 2026 15:39
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.13%. Comparing base (7777973) to head (e4c16e9).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #14362   +/-   ##
=======================================
  Coverage   98.13%   98.13%           
=======================================
  Files         269      269           
  Lines       10750    10750           
  Branches     3314     3314           
=======================================
  Hits        10550    10550           
  Misses        187      187           
  Partials       13       13           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread Dockerfile
Comment thread package.json
Comment thread bin/select-prebuilt-assets.js
@nothingrandom
nothingrandom merged commit 5b17771 into master Aug 3, 2026
15 checks passed
@nothingrandom
nothingrandom deleted the single-docker-image branch August 3, 2026 13:52
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.

Generate assets at the image build time

2 participants