With apisix.deployment.mode: standalone, the Deployment template starts the container with:
command: ["sh", "-c","ln -s /apisix-config/apisix.yaml /usr/local/apisix/conf/apisix.yaml && /docker-entrypoint.sh docker-start"]
sh stays PID 1 and runs the entrypoint, and therefore openresty, as its child. A shell as PID 1 installs no SIGTERM handler and forwards nothing. When Kubernetes stops the pod, APISIX never learns it should shut down: it keeps accepting requests until the grace period ends, then it is killed. The image's own entrypoint already execs openresty so that openresty is PID 1 and handles signals; the chart's wrapper undoes that.
Reproduction (image apache/apisix:3.18.0-ubuntu, the chart's rendered config.yaml and apisix.yaml mounted as in the chart, stopped with a 30-second grace period like the kubelet default):
| Start command |
PID 1 |
Time to stop |
Exit code |
| as in the chart |
sh |
30.4 s, then SIGKILL |
137 |
with exec before /docker-entrypoint.sh |
openresty |
1.0 s |
0 |
Fix
One word in templates/deployment.yaml:
command: ["sh", "-c","ln -s /apisix-config/apisix.yaml /usr/local/apisix/conf/apisix.yaml && exec /docker-entrypoint.sh docker-start"]
The shell still creates the symlink, then replaces itself with the entrypoint, which in turn execs openresty. Traditional and decoupled modes are unaffected, since they don't use this command.
Related
#1011 (with PR #1012) covers the other half of graceful shutdown: the hardcoded preStop: sleep 30 uses up the default 30-second grace period before SIGTERM is sent. In standalone mode the two combine: the preStop hook spends the grace period, and the SIGTERM that follows goes to a shell that ignores it. Both need fixing for APISIX to drain connections on shutdown in standalone mode.
With
apisix.deployment.mode: standalone, the Deployment template starts the container with:shstays PID 1 and runs the entrypoint, and therefore openresty, as its child. A shell as PID 1 installs no SIGTERM handler and forwards nothing. When Kubernetes stops the pod, APISIX never learns it should shut down: it keeps accepting requests until the grace period ends, then it is killed. The image's own entrypoint alreadyexecs openresty so that openresty is PID 1 and handles signals; the chart's wrapper undoes that.Reproduction (image
apache/apisix:3.18.0-ubuntu, the chart's renderedconfig.yamlandapisix.yamlmounted as in the chart, stopped with a 30-second grace period like the kubelet default):shexecbefore/docker-entrypoint.shFix
One word in
templates/deployment.yaml:The shell still creates the symlink, then replaces itself with the entrypoint, which in turn
execs openresty. Traditional and decoupled modes are unaffected, since they don't use this command.Related
#1011 (with PR #1012) covers the other half of graceful shutdown: the hardcoded
preStop: sleep 30uses up the default 30-second grace period before SIGTERM is sent. In standalone mode the two combine: the preStop hook spends the grace period, and the SIGTERM that follows goes to a shell that ignores it. Both need fixing for APISIX to drain connections on shutdown in standalone mode.