Skip to content

Conversation

@luojiyin1987
Copy link

@luojiyin1987 luojiyin1987 commented Dec 13, 2025

What is this PR about?

Summary

  • Fix CMD format in Dockerfile.server and Dockerfile.schedule - environment variables via CMD VAR=x && cmd don't work as expected
  • Use ENV for HOSTNAME and exec form CMD ["pnpm", "start"] for proper signal handling
  • Merge RUN commands to reduce image layers

Changes

  • Dockerfile.server: Fix HOSTNAME env and CMD format
  • Dockerfile.schedule: Fix HOSTNAME env and CMD format
  • Dockerfile: Minor cleanup (merge RUN, add PORT env)

Checklist

Before submitting this PR, please make sure that:

Screenshots (if applicable)

@Siumauricio
Copy link
Contributor

Can you say what's the purpose of this changes? I don't see much benefit here, if you can add images or something that is not working

@luojiyin1987
Copy link
Author

Updated explanation with PID comparison

The original CMD HOSTNAME=0.0.0.0 && pnpm start uses shell form, causing two issues:

  1. App runs as PID 8 (not PID 1)
  2. App cannot receive SIGTERM for graceful shutdown

Test Script

#!/bin/bash
# Shell form vs Exec form comparison

echo "=== PID comparison ==="
echo "1) Original: CMD HOSTNAME=0.0.0.0 && node ..."
docker run --rm node:20-slim sh -c 'HOSTNAME=0.0.0.0 && node -e "console.log(\"   PID:\", process.pid)"'
echo "2) Fixed: ENV HOSTNAME=0.0.0.0 + CMD [\"node\", ...]"
docker run --rm -e HOSTNAME=0.0.0.0 node:20-slim node -e "console.log('   PID:', process.pid)"

echo ""
echo "=== SIGTERM test ==="
echo "1) Original - app ignores SIGTERM:"
docker run -d --name t1 node:20-slim sh -c 'HOSTNAME=0.0.0.0 && node -e "
process.on(\"SIGTERM\", () => console.log(\"GOT SIGTERM\"));
setInterval(() => {}, 1000);
"' >/dev/null
sleep 1 && docker stop -t 2 t1 >/dev/null 2>&1
echo "   Logs:" $(docker logs t1 2>&1 | grep SIGTERM || echo "(empty)")
docker rm t1 >/dev/null

echo ""
echo "2) Fixed - app receives SIGTERM:"
docker run -d --name t2 -e HOSTNAME=0.0.0.0 node:20-slim node -e "
process.on('SIGTERM', () => { console.log('GOT SIGTERM'); process.exit(0); });
setInterval(() => {}, 1000);
" >/dev/null
sleep 1 && docker stop -t 2 t2 >/dev/null 2>&1
echo "   Logs:" $(docker logs t2 2>&1 | grep SIGTERM || echo "(empty)")
docker rm t2 >/dev/null

Results

=== PID comparison ===
1) Original: CMD HOSTNAME=0.0.0.0 && node ...
   PID: 8              ← not PID 1
2) Fixed: ENV HOSTNAME=0.0.0.0 + CMD ["node", ...]
   PID: 1              ← is PID 1 ✓

=== SIGTERM test ===
1) Original - app ignores SIGTERM:
   Logs: (empty)       ← no signal
2) Fixed - app receives SIGTERM:
   Logs: GOT SIGTERM   ← received ✓

docker stop sends SIGTERM only to PID 1. Shell form makes sh PID 1, so the app (PID 8) never receives the signal.

Reference: https://docs.docker.com/reference/dockerfile/#cmd

@luojiyin1987
Copy link
Author

Why 10 seconds delay?

docker stop workflow:

1. Send SIGTERM to PID 1
2. Wait for process to exit (default: 10s)
3. If still running → Send SIGKILL (force kill)

Shell form problem:

PID 1: sh -c "HOSTNAME=0.0.0.0 && node ..."
   └── PID 8: node (app)

1. SIGTERM → sh (PID 1)
2. sh exits, but node (PID 8) never receives signal
3. node keeps running as orphan process
4. Docker waits 10s timeout
5. SIGKILL force kills the container

Exec form solution:

PID 1: node (app)

1. SIGTERM → node (PID 1) directly
2. node receives signal, exits gracefully
3. Container stops immediately (~0.3s)

This fix allows graceful shutdown instead of force kill after 10s timeout.

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