Summary
Starting with the SQL Server 2022 CU18 Ubuntu container image, the container entrypoint was changed from permissions_check.sh to launch_sqlservr.sh.
The new script starts sqlservr as a background process and waits for it, but it does not install a signal handler or forward SIGTERM to the SQL Server process.
As a result, Kubernetes and docker stop send SIGTERM to the Bash process running as PID 1, while SQL Server continues running. Kubernetes eventually reaches terminationGracePeriodSeconds and sends SIGKILL, causing an unclean database shutdown.
Affected images
Confirmed with:
mcr.microsoft.com/mssql/server:2022-CU18-ubuntu-22.04
mcr.microsoft.com/mssql/server:2022-CU26-ubuntu-22.04
CU26 still contains the same signal-handling behavior.
CU17 is not affected:
mcr.microsoft.com/mssql/server:2022-CU17-ubuntu-22.04
Regression
In CU17, the image uses:
ENTRYPOINT ["/opt/mssql/bin/permissions_check.sh"]
CMD ["/opt/mssql/bin/sqlservr"]
permissions_check.sh ends with:
This replaces the shell with sqlservr, making the SQL Server watchdog PID 1. SIGTERM is therefore delivered correctly.
Starting with CU18, the image uses:
ENTRYPOINT ["/opt/mssql/bin/launch_sqlservr.sh"]
CMD ["/opt/mssql/bin/sqlservr"]
The relevant part of launch_sqlservr.sh is:
"$@" &
pid="$!"
/opt/mssql/bin/run_custom_setup.sh
wait $pid
There is no trap and no signal forwarding to $pid.
Environment
SQL Server image: mcr.microsoft.com/mssql/server:2022-CU23-ubuntu-22.04
Image digest: sha256:0ec7739e1c5ec2f57861facbe1f2b74f1d3e147c7c97edf91eeea920c5944d9c
Platform: Kubernetes / AKS
Runtime: containerd
terminationGracePeriodSeconds: 300
Container user: mssql
The Pod does not override the image command or entrypoint.
Process tree
Inside the affected container:
PID PPID COMMAND
1 0 /bin/bash /opt/mssql/bin/launch_sqlservr.sh /opt/mssql/bin/sqlservr
31 1 /opt/mssql/bin/sqlservr
34 31 /opt/mssql/bin/sqlservr
PID 31 is the SQL Server watchdog and PID 34 is the database engine.
Steps to reproduce
- Deploy an affected image without overriding its command or entrypoint.
- Verify the processes:
kubectl exec <pod> -- ps -eo pid,ppid,stat,args
- Delete the Pod:
time kubectl delete pod <pod>
- Observe that the Pod remains in
Terminating until terminationGracePeriodSeconds expires.
Sending SIGTERM directly to the SQL Server watchdog causes an immediate graceful shutdown:
kubectl exec <pod> -- bash -c '
pid="$(ps -eo pid=,ppid=,comm= |
awk '\''$2 == 1 && $3 == "sqlservr" {print $1; exit}'\'')"
kill -TERM "$pid"
'
Expected behavior
SIGTERM sent to the container PID 1 should be forwarded to the SQL Server watchdog. SQL Server should perform a graceful shutdown and the container should exit before the grace period expires.
Actual behavior
PID 1 is Bash. It does not forward SIGTERM to the background sqlservr process. The container is eventually killed with SIGKILL, and SQL Server performs crash recovery on the next startup.
Existing Microsoft Helm chart
The Microsoft sample Helm chart overrides the image entrypoint:
https://github.com/microsoft/mssql-docker/blob/master/linux/sample-helm-chart-statefulset-deployment/templates/deployment.yaml
Therefore, deployments based on that sample may not execute launch_sqlservr.sh, which can mask this regression.
Historical context
This appears to reintroduce a previously known and fixed issue:
Suggested resolution
Please make launch_sqlservr.sh forward SIGTERM and SIGINT to the background SQL Server process and wait for it to exit.
Using an init process capable of forwarding signals to the child process group would also resolve the issue.
Current Kubernetes workarounds are either:
- overriding the image entrypoint and running
/opt/mssql/bin/sqlservr directly, or
- adding a
preStop hook that sends SIGTERM directly to the SQL Server watchdog.
Neither workaround should be necessary for the official SQL Server container image.
Summary
Starting with the SQL Server 2022 CU18 Ubuntu container image, the container entrypoint was changed from
permissions_check.shtolaunch_sqlservr.sh.The new script starts
sqlservras a background process and waits for it, but it does not install a signal handler or forwardSIGTERMto the SQL Server process.As a result, Kubernetes and
docker stopsendSIGTERMto the Bash process running as PID 1, while SQL Server continues running. Kubernetes eventually reachesterminationGracePeriodSecondsand sendsSIGKILL, causing an unclean database shutdown.Affected images
Confirmed with:
CU26 still contains the same signal-handling behavior.
CU17 is not affected:
Regression
In CU17, the image uses:
permissions_check.shends with:This replaces the shell with
sqlservr, making the SQL Server watchdog PID 1.SIGTERMis therefore delivered correctly.Starting with CU18, the image uses:
The relevant part of
launch_sqlservr.shis:There is no
trapand no signal forwarding to$pid.Environment
The Pod does not override the image command or entrypoint.
Process tree
Inside the affected container:
PID 31 is the SQL Server watchdog and PID 34 is the database engine.
Steps to reproduce
TerminatinguntilterminationGracePeriodSecondsexpires.Sending
SIGTERMdirectly to the SQL Server watchdog causes an immediate graceful shutdown:Expected behavior
SIGTERMsent to the container PID 1 should be forwarded to the SQL Server watchdog. SQL Server should perform a graceful shutdown and the container should exit before the grace period expires.Actual behavior
PID 1 is Bash. It does not forward
SIGTERMto the backgroundsqlservrprocess. The container is eventually killed withSIGKILL, and SQL Server performs crash recovery on the next startup.Existing Microsoft Helm chart
The Microsoft sample Helm chart overrides the image entrypoint:
https://github.com/microsoft/mssql-docker/blob/master/linux/sample-helm-chart-statefulset-deployment/templates/deployment.yaml
Therefore, deployments based on that sample may not execute
launch_sqlservr.sh, which can mask this regression.Historical context
This appears to reintroduce a previously known and fixed issue:
Graceful container stopping #171
exec:Enable graceful shutdown #239
https://support.microsoft.com/en-gb/topic/kb4093805-fix-can-t-stop-the-sql-server-linux-docker-container-by-using-the-docker-stop-command-73387b1a-c1b3-6f49-d4dd-d291273b8b95
Suggested resolution
Please make
launch_sqlservr.shforwardSIGTERMandSIGINTto the background SQL Server process and wait for it to exit.Using an init process capable of forwarding signals to the child process group would also resolve the issue.
Current Kubernetes workarounds are either:
/opt/mssql/bin/sqlservrdirectly, orpreStophook that sendsSIGTERMdirectly to the SQL Server watchdog.Neither workaround should be necessary for the official SQL Server container image.