Files
TREK/server/scripts/entrypoint.sh
T
Maurice 7faf771f9c fix(docker): look at the volume roots only, and say when chown is refused
The ownership check still read every inode of the volumes on each start.
It now looks at the dirs and what sits directly in them, hands a volume
over once when it is not node's, and logs a warning instead of walking a
volume that refuses chown (NFS with root_squash).
2026-11-01 11:41:56 +01:00

57 lines
2.9 KiB
Bash

#!/bin/sh
# Container start-up: check the image layout, correct ownership of the mounted
# data dirs while still root, then drop to the node user.
#
# This has to stay a file rather than an inline `sh -c` string in CMD. Container
# management UIs render Config.Cmd back into a text field and re-split it with a
# quote-aware tokenizer when you edit a container in place; a command carrying
# embedded quotes comes back mangled and the container dies with a shell syntax
# error before Node starts. A CMD of one bare token survives that round-trip.
set -e
# If the app code is missing, a volume was almost certainly mounted over /app
# (it hides the image's node_modules + dist). Fail with actionable guidance
# instead of a cryptic "Cannot find module 'tsconfig-paths/register'".
if [ ! -f /app/server/dist/index.js ] || [ ! -d /app/node_modules/tsconfig-paths ]; then
echo 'FATAL: TREK application files are missing from the image.'
echo 'A volume is likely mounted over /app, which hides the app code.'
echo 'Mount ONLY your data and uploads dirs: -v ./data:/app/data -v ./uploads:/app/uploads'
echo 'Do NOT mount a volume at /app. See https://github.com/liketrek/TREK/wiki/Troubleshooting'
exit 1
fi
# cd into server/ so tsconfig-paths/register finds tsconfig.json and
# ../node_modules resolves correctly.
cd /app/server
# Already started as a non-root user (Kubernetes runAsUser, docker --user): there
# is nothing to chown and no privilege to drop, and gosu would only fail to switch
# users. Run Node as whoever we are; the volumes are that user's to provide.
if [ "$(id -u)" != "0" ]; then
exec node --require tsconfig-paths/register dist/index.js
fi
# Hand the mounted data dirs to node. A blanket `chown -R` on every start
# rewrote, and even a search for strays still read, every inode of the volume,
# which on a large or network-backed one (NFS, CephFS, Longhorn) kept the
# container busy for minutes before Node printed its first line (#2918). So only
# the dir and what sits directly in it are looked at: a volume that is not
# node's yet (a fresh one, or one copied in as root) shows there, and is handed
# over once. A volume that refuses chown altogether (NFS with root_squash) is
# said once per start instead of being walked file by file; such a pod belongs
# under runAsUser 1000, see the Helm page of the wiki. Best effort either way: a
# read-only host filesystem or a locked-down bind mount must keep booting.
for dir in /app/data /app/uploads; do
[ -d "$dir" ] || continue
if [ -n "$(find "$dir" -maxdepth 1 \( ! -user node -o ! -group node \) -print -quit 2>/dev/null)" ]; then
if chown node:node "$dir" 2>/dev/null; then
echo "Correcting ownership of $dir for the node user..."
chown -R -h node:node "$dir" 2>/dev/null || true
else
echo "WARNING: $dir cannot be handed to the node user (chown refused); run the container as uid 1000 instead."
fi
fi
done
exec gosu node node --require tsconfig-paths/register dist/index.js