mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-02 20:30:10 +00:00
Merge branch 'main' into ebook-piecewise
This commit is contained in:
@@ -1,12 +1,33 @@
|
||||
#!/bin/bash
|
||||
# App startup wrapper for unified container
|
||||
# Starts Next.js server and initializes services
|
||||
# Uses gosu to ensure correct PUID:PGID for file operations
|
||||
|
||||
set -e
|
||||
|
||||
# Load environment from /etc/environment (set by entrypoint)
|
||||
if [ -f /etc/environment ]; then
|
||||
set -a
|
||||
source /etc/environment
|
||||
set +a
|
||||
fi
|
||||
|
||||
# Get PUID/PGID (default to node user's current IDs if not set)
|
||||
PUID=${PUID:-$(id -u node)}
|
||||
PGID=${PGID:-$(id -g node)}
|
||||
|
||||
echo "[App] Starting Next.js server..."
|
||||
echo "[App] Process will run as UID:GID = $PUID:$PGID"
|
||||
|
||||
cd /app
|
||||
|
||||
# Start server in background
|
||||
node server.js &
|
||||
# Use gosu to switch to correct UID:GID and start server
|
||||
# This bypasses username resolution issues when PUID collides with existing users
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
# Running as root - use gosu to switch to PUID:PGID
|
||||
echo "[App] Switching to UID:GID $PUID:$PGID via gosu..."
|
||||
|
||||
# Start server in background with gosu
|
||||
gosu "$PUID:$PGID" node server.js &
|
||||
SERVER_PID=$!
|
||||
|
||||
echo "[App] Waiting for server to be ready..."
|
||||
@@ -14,9 +35,25 @@ sleep 5
|
||||
|
||||
# Initialize application services (creates default scheduled jobs)
|
||||
echo "[App] Initializing application services..."
|
||||
curl -f http://localhost:3030/api/init || echo "[App] ⚠️ Warning: Failed to initialize services"
|
||||
curl -sf http://localhost:3030/api/init || echo "[App] Warning: Failed to initialize services (may already be initialized)"
|
||||
|
||||
echo "[App] Server ready with PID $SERVER_PID"
|
||||
echo "[App] Server ready with PID $SERVER_PID (running as $PUID:$PGID)"
|
||||
|
||||
# Verify the process is running with correct UID:GID
|
||||
if [ -f "/proc/$SERVER_PID/status" ]; then
|
||||
ACTUAL_UID=$(grep '^Uid:' /proc/$SERVER_PID/status | awk '{print $2}')
|
||||
ACTUAL_GID=$(grep '^Gid:' /proc/$SERVER_PID/status | awk '{print $2}')
|
||||
echo "[App] Verified process credentials: UID=$ACTUAL_UID GID=$ACTUAL_GID"
|
||||
|
||||
if [ "$ACTUAL_UID" != "$PUID" ] || [ "$ACTUAL_GID" != "$PGID" ]; then
|
||||
echo "[App] WARNING: Process UID:GID ($ACTUAL_UID:$ACTUAL_GID) does not match expected ($PUID:$PGID)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Wait for server process
|
||||
wait $SERVER_PID
|
||||
else
|
||||
# Not running as root - just run directly (fallback)
|
||||
echo "[App] Warning: Not running as root, cannot use gosu. Running as current user."
|
||||
exec node server.js
|
||||
fi
|
||||
|
||||
@@ -4,12 +4,16 @@ set -e
|
||||
echo "🚀 ReadMeABook Unified Container Starting..."
|
||||
|
||||
# ============================================================================
|
||||
# PUID/PGID USER REMAPPING (Hybrid approach)
|
||||
# PUID/PGID USER REMAPPING (Hybrid approach with gosu)
|
||||
# ============================================================================
|
||||
# Hybrid approach to support user file ownership while maintaining PostgreSQL compatibility:
|
||||
# - postgres user: Keep UID 103 (required by PostgreSQL), remap GID → PGID
|
||||
# - redis user: Remap UID → PUID, GID → PGID
|
||||
# - node user: Remap UID → PUID, GID → PGID
|
||||
# - redis user: Remap UID → PUID, GID → PGID (also uses gosu at runtime)
|
||||
# - node user: Remap UID → PUID, GID → PGID (also uses gosu at runtime)
|
||||
#
|
||||
# NOTE: We use gosu in app-start.sh and redis-start.sh to ensure the process
|
||||
# actually runs with the correct UID:GID. This fixes issues where PUID collides
|
||||
# with existing system users (e.g., PUID=65534 collides with 'nobody').
|
||||
#
|
||||
# Result:
|
||||
# - PostgreSQL data (103:PGID) - postgres user with shared group
|
||||
@@ -309,7 +313,8 @@ export NODE_ENV="production"
|
||||
export PORT="3030"
|
||||
export HOSTNAME="0.0.0.0"
|
||||
|
||||
# Persist environment variables for supervisord
|
||||
# Persist environment variables for supervisord and child processes
|
||||
# PUID/PGID are critical for gosu-based user switching in app-start.sh and redis-start.sh
|
||||
cat > /etc/environment <<EOF
|
||||
DATABASE_URL=$DATABASE_URL
|
||||
REDIS_URL=$REDIS_URL
|
||||
@@ -322,6 +327,8 @@ LOG_LEVEL=$LOG_LEVEL
|
||||
NODE_ENV=$NODE_ENV
|
||||
PORT=$PORT
|
||||
HOSTNAME=$HOSTNAME
|
||||
PUID=${PUID:-}
|
||||
PGID=${PGID:-}
|
||||
EOF
|
||||
|
||||
echo "✅ Environment configured"
|
||||
@@ -353,9 +360,14 @@ if [ "$POSTGRES_PASSWORD" = "$(generate_secret)" ]; then
|
||||
fi
|
||||
echo ""
|
||||
echo "📊 Services starting:"
|
||||
echo " - PostgreSQL (internal)"
|
||||
echo " - Redis (internal)"
|
||||
echo " - Next.js App (port 3030)"
|
||||
echo " - PostgreSQL (internal, user=postgres)"
|
||||
echo " - Redis (internal, UID:GID=${PUID:-102}:${PGID:-102})"
|
||||
echo " - Next.js App (port 3030, UID:GID=${PUID:-1000}:${PGID:-1000})"
|
||||
if [ -n "$PUID" ] && [ -n "$PGID" ]; then
|
||||
echo ""
|
||||
echo "🔐 Using gosu for reliable UID:GID switching"
|
||||
echo " App and Redis will run as $PUID:$PGID"
|
||||
fi
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
# Redis startup wrapper for unified container
|
||||
# Uses gosu to ensure correct PUID:PGID for file operations
|
||||
|
||||
set -e
|
||||
|
||||
# Load environment from /etc/environment (set by entrypoint)
|
||||
if [ -f /etc/environment ]; then
|
||||
set -a
|
||||
source /etc/environment
|
||||
set +a
|
||||
fi
|
||||
|
||||
# Get PUID/PGID (default to redis user's current IDs if not set)
|
||||
PUID=${PUID:-$(id -u redis)}
|
||||
PGID=${PGID:-$(id -g redis)}
|
||||
|
||||
echo "[Redis] Starting Redis server..."
|
||||
echo "[Redis] Process will run as UID:GID = $PUID:$PGID"
|
||||
|
||||
# Use gosu to switch to correct UID:GID and start redis
|
||||
# This bypasses username resolution issues when PUID collides with existing users
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
# Running as root - use gosu to switch to PUID:PGID
|
||||
echo "[Redis] Switching to UID:GID $PUID:$PGID via gosu..."
|
||||
exec gosu "$PUID:$PGID" /usr/bin/redis-server --appendonly yes --dir /var/lib/redis --bind 127.0.0.1 --port 6379
|
||||
else
|
||||
# Not running as root - just run directly (fallback)
|
||||
echo "[Redis] Warning: Not running as root, cannot use gosu. Running as current user."
|
||||
exec /usr/bin/redis-server --appendonly yes --dir /var/lib/redis --bind 127.0.0.1 --port 6379
|
||||
fi
|
||||
@@ -20,8 +20,8 @@ stdout_events_enabled=true
|
||||
stderr_events_enabled=true
|
||||
|
||||
[program:redis]
|
||||
command=/usr/bin/redis-server --appendonly yes --dir /var/lib/redis --bind 127.0.0.1 --port 6379
|
||||
user=redis
|
||||
command=/app/redis-start.sh
|
||||
user=root
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=20
|
||||
@@ -35,7 +35,7 @@ stderr_events_enabled=true
|
||||
[program:app]
|
||||
command=/app/app-start.sh
|
||||
directory=/app
|
||||
user=node
|
||||
user=root
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=30
|
||||
|
||||
+7
-1
@@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y curl gnupg && \
|
||||
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /etc/apt/keyrings/postgresql.gpg && \
|
||||
echo "deb [signed-by=/etc/apt/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/postgresql.list
|
||||
|
||||
# Install PostgreSQL, Redis, and supervisord
|
||||
# Install PostgreSQL, Redis, supervisord, and gosu (for reliable user switching)
|
||||
RUN apt-get update && apt-get install -y \
|
||||
postgresql-16 \
|
||||
postgresql-client-16 \
|
||||
@@ -25,6 +25,7 @@ RUN apt-get update && apt-get install -y \
|
||||
openssl \
|
||||
ffmpeg \
|
||||
locales \
|
||||
gosu \
|
||||
&& sed -i 's/^# \(en_US.UTF-8 UTF-8\)/\1/' /etc/locale.gen \
|
||||
&& locale-gen en_US.UTF-8 \
|
||||
&& update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 \
|
||||
@@ -106,6 +107,11 @@ COPY --chown=root:root docker/unified/app-start.sh /app/app-start.sh
|
||||
# Convert line endings and make executable
|
||||
RUN sed -i 's/\r$//' /app/app-start.sh && chmod +x /app/app-start.sh
|
||||
|
||||
# Copy redis startup wrapper
|
||||
COPY --chown=root:root docker/unified/redis-start.sh /app/redis-start.sh
|
||||
# Convert line endings and make executable
|
||||
RUN sed -i 's/\r$//' /app/redis-start.sh && chmod +x /app/redis-start.sh
|
||||
|
||||
# Expose app port
|
||||
EXPOSE 3030
|
||||
|
||||
|
||||
@@ -691,6 +691,20 @@ docker volume rm readmeabook-pgdata readmeabook-redis readmeabook-cache
|
||||
- Let Docker create directories on first run (they'll have correct ownership)
|
||||
- Note: Works fine on WSL2 when using Docker volumes or letting container create directories
|
||||
|
||||
**19. PUID collision causes wrong GID (EACCES: permission denied, mkdir)**
|
||||
- Issue: File organization fails with `EACCES: permission denied, mkdir '/media/...'` even though PUID/PGID are set correctly
|
||||
- Symptoms: `docker exec -u $PUID:$PGID container mkdir /media/test` works, but the app fails
|
||||
- Root cause: When PUID collides with an existing system user (e.g., PUID=65534 collides with `nobody`), the `usermod` command creates two users with the same UID. When supervisord resolves `user=node` from /etc/passwd, it may resolve to the wrong user's GID
|
||||
- Example: User sets PUID=65534 (nobody), PGID=321601206 (AD group). App runs with UID=65534 but GID=65534 (nogroup) instead of GID=321601206
|
||||
- Diagnosis: Run `docker exec container ps ax -o user,pid,group,gid,comm` - if GID column shows wrong value, this is the issue
|
||||
- Fix: Use `gosu` for reliable UID:GID switching that bypasses username resolution
|
||||
- Added `gosu` package to Dockerfile
|
||||
- Created `app-start.sh` and `redis-start.sh` wrapper scripts that use `gosu $PUID:$PGID` to switch users
|
||||
- Supervisord now starts these wrappers as root, and gosu switches to the exact UID:GID
|
||||
- PUID/PGID are passed via /etc/environment to the wrapper scripts
|
||||
- Verification: After fix, `ps ax -o user,pid,group,gid,comm` will show correct GID for app and redis processes
|
||||
- Note: This primarily affects users with complex setups (NFS mounts, AD/SSSD groups, PUID=65534)
|
||||
|
||||
## Related
|
||||
|
||||
- [Multi-container deployment](docker.md)
|
||||
|
||||
Reference in New Issue
Block a user