Repository navigation
chore(docker): slim image and drop runtime git - #1279
Conversation
- Multi-stage Dockerfile (build -> prune -> runtime) with a BuildKit yarn cache mount, so the 2.2 GB yarn cache never lands in a layer - Add .dockerignore (keeps .git, node_modules and local configs/secrets out of the build context; configs are mounted as documented) - Pass GIT_SHA/GIT_REF as build args instead of .gitsha/.gitref files, and remove the dead placeholder files - checkForUpdates: read sha/ref from env, fetch the remote sha via the GitHub API (no git binary needed), skip non-branch refs (PR images) - Move vite + build plugins to dependencies since `yarn start` builds the client on boot; lazy-load vite-plugin-checker (dev only) - Name the Sentry release from SENTRY_RELEASE/GIT_SHA (the plugin used `git rev-parse HEAD`, which only worked because the image had .git) - Move openai/gpt-tokenizer to @rm/locales devDependencies and drop the unused `generate` re-export; keep loading .env in @rm/locales - Remove unused monaco-editor devDependency (the playground loads Monaco from jsDelivr via @monaco-editor/loader) - docker.yml: buildx, current action versions, GHA layer cache, provenance disabled to keep publishing a single manifest Image: 3 GB -> 608 MB uncompressed (~1.4 GB -> ~207 MB compressed) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 21b0149371
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| */ | ||
| async function getCurrentBranch() { | ||
| const gitRef = process.env.GIT_REF?.trim() | ||
| if (gitRef) { |
There was a problem hiding this comment.
Handle an empty Docker ref before falling back to git
When an image is built with plain docker build ., the Dockerfile always defines GIT_REF but leaves it as an empty string. This truthiness check therefore falls through to git branch, even though the new runtime contains neither git nor .git; after logging that failure, it assumes main, repeats the git failure for the SHA, and performs an awaited GitHub fetch that can add the full 10-second timeout before the server starts. Treat the presence of the Docker metadata environment variable, even when empty, as a Docker build and return an empty branch so the intended no-argument update check is actually skipped.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 6db8242. GIT_REF being defined at all (the Dockerfile always sets it, empty without --build-arg) now marks a Docker build, and Docker never falls back to git. An empty ref or sha skips the check. The remote lookup is also skipped whenever the local sha is unknown. In a plain docker build . image the check now exits in ~2 ms with no git call and no fetch.
The Dockerfile always defines GIT_REF/GIT_SHA (empty without --build-arg), so treat their presence as Docker and never fall back to git, which the image doesn't ship. Also skip the remote lookup whenever the local sha is unknown instead of awaiting a fetch whose result can't be compared. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- checkout v7, setup-buildx v4, login v4, metadata v6, build-push v7 (none of their breaking changes affect this workflow) - BUILDX_METADATA_PROVENANCE=disabled drops the ~600 line provenance trace from the printed build metadata - DOCKER_BUILD_RECORD_UPLOAD=false stops uploading a .dockerbuild artifact on every run; the job summary is kept Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Slims the Docker image from 3 GB → 608 MB uncompressed (~1.4 GB → ~207 MB compressed) and removes the runtime dependency on
git/.git. Behavior stays the same for Docker, localdocker buildand bare-metal installs; see the comparison below.:maintoday.git/gitbinaryWhere the size went
yarn installleft the yarn download cache (/usr/local/share/.cache, 2.2 GB) in the layer..dockerignore.Changes
build→prune→runtime.gitis only installed in the build stage, for the git-URL dependencieschalkercliandpassport-discord.node:22.23.4-alpinewith productionnode_modules. Paths stay under/home/node, so existing compose mounts keep working.NPM_CONFIG_PREFIX/PATHare unchanged, and the default isCMD ["yarn", "start"]..dockerignore: new. Keeps.git,node_modules,distand local configs/secrets (config/local.json,config/areas.json,server/src/configs/**,.env) out of the build context. CI images never contained those, and configs are mounted as documented.GIT_SHA/GIT_REFbuild args become env vars. The workflow's.gitsha/.gitrefsteps and the tracked empty placeholder files are removed.checkForUpdates.js:git branch/git rev-parse.application/vnd.github.sha) instead ofgit ls-remote.refs/pull/123/mergeas branch"123".yarn startrebuilds the client on every boot, baking in the user's title, theme, start location, GA, Sentry and favicon. So the build toolchain is a real runtime dependency:vite,@vitejs/plugin-react-swc,rollup-plugin-delete,@sentry/vite-pluginand@rm/vite-pluginsmove todependencies.vite-plugin-checkeris lazy-loaded (dev only) and stays a devDependency.openaiandgpt-tokenizer(only used by the CIlocales:generatejob) move to@rm/localesdevDependencies. The unusedgeneratere-export is dropped, so the server no longer loads them at boot.@rm/localesstill callsdotenv.config()on import, whichvite.config.jsrelies on forNODE_CONFIG_ENV→dist-*.monaco-editordevDependency is removed. The playground keeps working:@monaco-editor/loaderloads Monaco fromcdn.jsdelivr.net/npm/monaco-editor@0.55.1, and the npm copy (^0.41) was never bundled.SENTRY_RELEASE→GIT_SHA. It used to fall back togit rev-parse HEAD, which only worked because the old image shippedgit+.git.docker.yml:setup-buildx-actionand bumps to login v3, metadata v5, build-push v6.type=gha,mode=max).provenance: false, so a single image manifest is still published (no attestation index).permissions(contents: read,packages: write).Intentional behavior changes
/are no longer truncated, PR images skip the check, and there's no false "new version" notice when the remote sha can't be fetched. The remote lookup is skipped entirely when the local sha is unknown. The remote lookup has a 10s timeout;git ls-remotehad none, and startup awaits it.api.github.com(unauthenticated limit: 60 requests/hour per IP, and the check runs once at startup). On bare-metal, a branch that doesn't exist upstream now logsUnable to get remote SHAinstead of a false "new version available".docker buildwithout build args: the update check is skipped with a single info line, with no git calls and no network request. Old local builds ran git, failed withdubious ownership in repository at '/home/node', calledgit ls-remotewithout a timeout and printed a false "new version available". Pass--build-arg GIT_SHA=$(git rev-parse HEAD) --build-arg GIT_REF=$(git symbolic-ref HEAD)to enable it.yarn dev,yarn lint,yarn locales:generate,yarn testetc. don't work inside the container.yarn start,yarn server,yarn build,yarn masterfileandmigrate:*do.yarn installwarning: it now prints an unmet-peer warning formonaco-editor.Old vs new comparison
The same mounted
local.json(customheaderTitle, MariaDB) was used in every setup. Probes:/,/playground,/index.html,/favicon.ico,/locales/{en,de}/translation.json, a 404,/api/v1/config,/auth/discord,POST /graphql, the config baked into the bundle, and sha256 of everydistfile.yarn start)maindistfiles identicaldocker build(no args, config mounted)distidentical, startup build bakes the config in bothyarn start)ghcr.io/watwowmap/reactmap:mainindex.html/ bundle; CI-built and local new images identicalTesting
yarn install --frozen-lockfile,yarn lint,yarn prettier,yarn config:check,yarn masterfile,yarn testandyarn buildall pass. These cover the steps inlint.yml,config.ymlandrelease.yml.gitand no.git*files in the image, and Node isv22.23.4(includes the CVE-2026-111497 fix).lint✓,dockerbuild + push ✓). Note that the docker job is skipped for PRs from forks, so it first runs here after merge.🤖 Generated with Claude Code