Operations 17 min read

Master Graceful Docker Container Shutdown: Signals, Exit Codes, and Go Example

This article explains how to achieve graceful shutdown of Docker containers by handling Linux signals, interpreting common Docker exit codes, and using a Go program that registers SIGTERM and SIGINT, while also covering docker stop, docker kill, and daemon signal handling.

Raymond Ops
Raymond Ops
Raymond Ops
Master Graceful Docker Container Shutdown: Signals, Exit Codes, and Go Example

1. Overview

Any application should receive a stop notification before termination to release resources, close connections, and finish pending requests, such as completing HTTP requests or flushing file buffers.

2. Common Linux Signals

Signals are inter‑process messages. Programs typically handle SIGTERM for graceful termination, while SIGKILL forces immediate exit. SIGHUP is used for hot‑reloading configuration, SIGINT for Ctrl‑C, SIGQUIT for graceful quit, SIGCHLD for child‑process exit, etc.

SIGHUP (1) – sent when a terminal closes; used by services like wget, Docker, Nginx for config reload.

SIGINT (2) – generated by Ctrl‑C.

SIGQUIT (3) – generated by Ctrl‑\, used by Nginx for graceful stop.

SIGKILL (9) – cannot be caught or ignored; forces immediate termination.

SIGTERM (15) – termination request that can be caught; default signal for

docker stop

.

SIGCHLD (17) – sent to a parent when a child exits; used by multi‑process services like Nginx.

3. Common Docker Exit Codes

Exit Code 1

Program error or missing file in Dockerfile.

Examples: division by zero, nil pointer, crash.

Exit Code 137

Container received SIGKILL (kill -9).

Often caused by OOMKilled when memory limits are low.

Exit Code 139

Container received SIGSEGV (invalid memory access).

Usually due to buggy code or base image issues.

Exit Code 143

Container received SIGTERM (docker stop).

docker stop may fall back to SIGKILL after timeout.

Other Exit Codes

126 – permission or non‑executable command.

127 – command not found.

1 or 255 – custom exit values.

Signals terminated processes have their signal number added to 128 to form the exit status (e.g., SIGKILL → 137, SIGTERM → 143).

4. Docker Signal Support

4.1 docker stop

docker stop

sends SIGTERM to PID 1, waits (default 10 s) and then sends SIGKILL. The timeout can be changed with

--time/-t

.

<code>→ docker stop --help
Usage:  docker stop [OPTIONS] CONTAINER [CONTAINER…]
Options:
  --help     Print usage
  -t, --time int  Seconds to wait for stop before killing it (default 10)
</code>

4.2 docker kill

docker kill

sends SIGKILL by default but can send any signal with

-s/--signal

, e.g.,

docker kill --signal=SIGINT mycontainer

.

<code>→ docker kill --help
Usage:  docker kill [OPTIONS] CONTAINER [CONTAINER…]
Options:
  --help     Print usage
  -s, --signal string  Signal to send to the container (default "KILL")
</code>

4.3 docker rm

docker rm -f

forces removal by first sending SIGKILL to the running container.

4.4 Docker daemon signals

The daemon reloads its configuration on SIGHUP. Example:

kill -SIGHUP $(pidof dockerd)

or

systemctl reload docker

.

<code>root@host# kill -SIGHUP $(pidof dockerd)
root@host# systemctl reload docker
</code>

5. Graceful Shutdown Example (Go)

The following Go program registers SIGTERM and SIGINT, prints a message when a signal is received, and exits.

<code>// main.go
package main

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)

func main() {
    fmt.Println("Program started…")
    ch := make(chan os.Signal, 1)
    signal.Notify(ch, syscall.SIGTERM)
    signal.Notify(ch, syscall.SIGINT)
    s := <-ch
    switch {
    case s == syscall.SIGINT:
        fmt.Println("SIGINT received!")
    case s == syscall.SIGTERM:
        fmt.Println("SIGTERM received!")
    }
    fmt.Println("Exiting…")
}
</code>

Build the binary for Linux:

<code>CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o graceful
</code>

Run the container:

<code>docker build -t graceful-golang-case:1.0.0 .
docker run -d --name graceful graceful-golang-case:1.0.0
docker logs graceful
docker stop --time=120 graceful
</code>

Using

docker stop

allows the program to handle SIGTERM and exit cleanly, whereas

docker kill

or

docker rm -f

would terminate it abruptly.

6. Summary

For graceful Docker container termination, ensure your application handles SIGTERM, prefer

docker stop

(which sends SIGTERM then SIGKILL after a timeout), and use the exec form of

CMD

or

ENTRYPOINT

so signals reach the intended process.

Q&A

Q1: How to verify that a registered SIGTERM handler was executed?

A: Check the container logs for the expected output.

DockeroperationsGoContainer ManagementGraceful ShutdownLinux Signals
Raymond Ops
Written by

Raymond Ops

Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.