如何在Docker中正确捕获SIGTERM信号?
Why This Happens
When you run docker stop, Docker sends a SIGTERM signal to the PID 1 process inside the container. Your run_api.sh script is running as PID 1 here, but by default, Bash doesn't automatically forward signals to child processes (like your gunicorn server). That's why manually sending SIGTERM to gunicorn works, but docker stop doesn't—your shell is swallowing the signal instead of passing it along to the process that needs it.
Solutions
Option 1: Make Gunicorn PID 1 with exec
The simplest fix is to use exec when starting gunicorn. This replaces the shell process with gunicorn entirely, making gunicorn the new PID 1. Now, the SIGTERM from Docker goes directly to gunicorn, and your signal handling logic will trigger as expected.
Update your run_api.sh like this:
#!/bin/bash cd /repo PROCESSES=${1:-9} LOCAL_DOCKER_PORT=${2:-7001} # Use exec to replace the shell with gunicorn, making it PID 1 exec /opt/conda/envs/environment/bin/gunicorn --bind 0.0.0.0:$LOCAL_DOCKER_PORT --workers=$PROCESSES restful_api:app
Option 2: Add Signal Forwarding Logic to the Shell Script
If you need to keep the shell script as PID 1 (for example, to run pre-start setup tasks), you can add a trap to catch SIGTERM and explicitly forward it to the gunicorn process.
Here's the modified script:
#!/bin/bash cd /repo PROCESSES=${1:-9} LOCAL_DOCKER_PORT=${2:-7001} # Start gunicorn in the background and save its process ID /opt/conda/envs/environment/bin/gunicorn --bind 0.0.0.0:$LOCAL_DOCKER_PORT --workers=$PROCESSES restful_api:app & GUNICORN_PID=$! # Define a handler to forward SIGTERM to gunicorn handle_sigterm() { echo "Received SIGTERM, forwarding to gunicorn (PID: $GUNICORN_PID)" kill -TERM "$GUNICORN_PID" # Wait for gunicorn to exit cleanly before stopping the script wait "$GUNICORN_PID" } # Trap SIGTERM signals and run our handler trap handle_sigterm SIGTERM # Keep the shell running until gunicorn exits wait "$GUNICORN_PID"
Extra Tips
- Ensure
run_api.shhas executable permissions: You can addRUN chmod +x /repo/run_api.shto your Dockerfile, or set the permission locally before copying the script into the container. - If you're using Docker Compose, you can specify a custom stop signal with
stop_signal: SIGTERM, but the above fixes should handle the core issue regardless of your orchestration tool.
内容的提问来源于stack exchange,提问作者Zorgoth

