Cloud Native 19 min read

How to Gracefully Stop Docker Containers: Signals, Exit Codes, and Go Example

This guide explains how Docker containers can be gracefully stopped by handling Linux signals such as SIGTERM, details common exit codes, demonstrates a Go program that captures these signals, and provides best‑practice Dockerfile configurations to ensure proper shutdown behavior.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
How to Gracefully Stop Docker Containers: Signals, Exit Codes, and Go Example

1. Overview

Any application wants to receive a stop notification before termination so it can release resources, close connections, and finish pending work. For example, a web service should finish all in‑flight HTTP requests, and a file‑writing process should flush data to disk before the container stops.

2. Common Linux Signals

Signals are a form of inter‑process communication. A signal is a message from the kernel indicating an event. Processes register handlers for signals they care about.

Programs typically handle SIGTERM to exit gracefully; SIGKILL terminates a process abruptly.

Daemons often use SIGHUP for hot‑reloading configuration files.

The kill -l command lists supported signals. Signals 1‑31 are traditional (non‑real‑time); 32‑63 are reliable (real‑time) signals.

SIGHUP (1)

Sent when a terminal disconnects; also used for hot‑reloading configs. Services like wget, Docker, Nginx, and LVS register SIGHUP to reload configuration without stopping.

SIGINT (2)

Interrupt signal generated by Ctrl+C, notifying the foreground process group to terminate.

SIGQUIT (3)

Similar to SIGINT but triggered by Ctrl+\. Nginx uses it for graceful shutdown.

SIGKILL (9)

Immediately terminates a program. This signal cannot be blocked, handled, or ignored.

SIGTERM (15)

Terminate signal (request to exit). Unlike SIGKILL, it can be caught and handled, allowing graceful shutdown. The kill command sends SIGTERM by default.

SIGCHLD (17)

Sent to a parent when a child process exits. Nginx uses it for master‑worker communication.

3. Common Docker Container Exit Codes

Exit Code 1

Program error or missing file referenced in Dockerfile (e.g., wrong entrypoint).

Examples: division by zero, null reference, or crash.

Exit Code 137

Indicates the container received SIGKILL (kill -9).

Triggered by docker kill or OOMKilled when memory limits are too low.

Exit Code 139

Indicates the container received SIGSEGV (invalid memory access, kill -11).

Usually caused by buggy code or a faulty base image.

Exit Code 143

Indicates the container received SIGTERM (kill -15), typically from docker stop.

Sometimes docker stop falls back to SIGKILL, resulting in 137 if the program cannot handle SIGTERM within the timeout.

Other Exit Codes

126 – Permission problem or non‑executable command.

127 – Command not found (often a typo in a shell script).

1 or 255 – Custom exit codes from programs (e.g., exit(1) or exit(-1) which maps to 255).

For processes terminated by a signal, the OS adds 128 to the signal number to form the exit status (e.g., SIGKILL 9 → 137, SIGTERM 15 → 143). This convention helps distinguish normal exits (0‑127) from signal‑induced exits (128‑255) in container environments.

4. Docker Container Signal Support

Docker provides extensive support for Linux signals.

4.1 docker stop Signal Support

When docker stop is executed, Docker sends SIGTERM to the container’s PID 1 and waits (default 10 seconds) before sending SIGKILL. The timeout can be changed with --time (or -t).

docker stop --help
Usage:  docker stop [OPTIONS] CONTAINER [CONTAINER...]
Options:
  -t, --time int   Seconds to wait for stop before killing it (default 10)

4.2 docker kill Signal Support

docker kill

sends SIGKILL by default, but you can specify any signal with --signal (or -s).

docker kill --signal=SIGINT container_name

4.3 docker rm Signal Support

docker rm -f

forces removal of a running container by first sending SIGKILL, then deleting the container.

4.4 Docker Daemon Signal Support

The Docker daemon (dockerd) reloads its configuration when it receives SIGHUP. You can trigger this with:

kill -SIGHUP $(pidof dockerd)
# or
systemctl reload docker

After reloading, the daemon logs “Got signal to reload configuration”.

Note: systemctl reload docker reloads the daemon without restarting containers; systemctl restart docker stops and restarts the daemon, causing all containers to restart.

5. Graceful Shutdown Example for a Service

Below is a simple Go program that registers handlers for SIGTERM and SIGINT, prints a message when a signal is received, and exits.

// 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!")
        // Do something…
    case s == syscall.SIGTERM:
        fmt.Println("SIGTERM received!")
        // Do something…
    }
    fmt.Println("Exiting…")
}

Build the binary for Linux:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o graceful

Run the binary in a container:

FROM alpine:latest
ADD graceful /graceful
CMD ["/graceful"]

Test the program:

# Foreground, then Ctrl+C
./graceful
Program started…
^CSIGINT received!
Exiting…

# Background, then kill
./graceful &
kill <pid>
Program started…
SIGTERM received!
Exiting…

Build the Docker image:

docker build -t graceful-golang-case:1.0.0 .

Run the container:

docker run -d --name graceful graceful-golang-case:1.0.0

Check logs to confirm the program started:

docker logs graceful
Program started…

Stop the container with a custom timeout to give the program time to clean up:

docker stop --time=120 graceful

Logs show the program handled SIGTERM and exited cleanly.

6. Summary

To achieve graceful shutdown of Docker containers, ensure your application registers and handles the SIGTERM signal. Use docker stop (not docker kill or docker rm -f) so the container receives SIGTERM and has a chance to finish work. In Dockerfiles, prefer the exec form of CMD or ENTRYPOINT to guarantee that signals are delivered directly to your application process.

Q&A

Q1: How can I verify that my program’s SIGTERM handler executed?

A: Check the container’s logs for the expected output.

References:

Gracefully Stopping Docker Containers

Best Practices for Pod Pre‑Stop

Diagram
Diagram
Illustration
Illustration
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DockerGocontainerGraceful ShutdownLinux signalsExit Codes
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

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.