Details on docker container graceful exit

  • 2020-06-23 02:28:15
  • OfStack

preface

Recently, for work reasons, I talked about how to exit the running docker container properly, which is a topic worth discussing. This article will give a detailed introduction, let's start with 1.

Use of container signals

A program running in a container usually wants to do some cleaning before the container exits. A more common approach is to listen for a signal and delay closing the container.

docker offers the following features:


 � ─ ➤ docker stop --help

Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]

Stop one or more running containers

Options:
 --help Print usage
 -t, --time int Seconds to wait for stop before killing it (default 10)

docker 1.13 and above specify the STOP_TIMEOUT and STOP_SIGNAL parameters directly when creating the container:


$ docker run --help
...
--stop-signal string   Signal to stop a container, SIGTERM by default (default "SIGTERM")
--stop-timeout int   Timeout (in seconds) to stop a container
...

But...

We tested 1:


package main

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

func main() {
 fmt.Println("signal test")
 go func() {
 for {
  c := make(chan os.Signal, 1)
  signal.Notify(c, syscall.SIGTERM)
  s := <-c
  fmt.Println("Got signal:", s)
 }
 }()
 time.Sleep(time.Second * 100)
}

Dockerfile:


FROM golang:1.8.0
COPY main.go .
RUN go build -o signal && cp signal $GOPATH/bin
CMD signal 

Construction:


docker build -t signal:latest .

Run:


docker run --name signal signal:latest

Open 1 terminal again and run:


docker stop -t 10 signal

Got signal:... Failed to listen for signal.

The problem is: we docker inspect signal See one

You can see


Path:/bin/sh
Args:[
 -c,
 signal
]

or docker exec signal ps If you look at 1 you can see that the process of pid 1 is not signal but shell.

So the reason is because docker engine Only the pid 1 process is signaled, sh receives the signal and the signal process we want is not signaled

Solutions:


FROM golang:1.8.0
COPY main.go .
RUN go build -o signal && cp signal $GOPATH/bin
CMD ["signal"] #  Can not write  CMD signal,  This will directly exec , or it will take shell Is the way to derive a child process. 

conclusion


Related articles: