Reputation: 40834
I want to be able to shutdown a docker process gracefully. I derived the these files by following the idea in this blog post: https://husobee.github.io/golang/ecs/2016/05/19/ecs-graceful-go-shutdown.html
Here are my files
1) Dockerfile
FROM debian:jessie
ADD app /app
RUN apt-get update --fix-missing
RUN apt-get install -y golang
CMD ["go", "run", "/app/main.go"]
2) app/main.go
package main
import "os"
import "syscall"
import "fmt"
import "time"
import "os/signal"
func main() {
// create a "returnCode" channel which will be the return code of the application
var returnCode = make(chan int)
// finishUP channel signals the application to finish up
var finishUP = make(chan struct{})
// done channel signals the signal handler that the application has completed
var done = make(chan struct{})
// gracefulStop is a channel of os.Signals that we will watch for -SIGTERM
var gracefulStop = make(chan os.Signal)
// watch for SIGTERM and SIGINT from the operating system, and notify the app on
// the gracefulStop channel
signal.Notify(gracefulStop, syscall.SIGTERM)
signal.Notify(gracefulStop, syscall.SIGINT)
// launch a worker whose job it is to always watch for gracefulStop signals
go func() {
// wait for our os signal to stop the app
// on the graceful stop channel
// this goroutine will block until we get an OS signal
sig := <-gracefulStop
fmt.Printf("caught sig: %+v", sig)
// send message on "finish up" channel to tell the app to
// gracefully shutdown
finishUP<-struct{}{}
// wait for word back if we finished or not
select {
case <-time.After(30*time.Second):
// timeout after 30 seconds waiting for app to finish,
// our application should Exit(1)
returnCode<-1
case <-done:
// if we got a message on done, we finished, so end app
// our application should Exit(0)
returnCode<-0
}
}()
// ... Do business Logic in goroutines
fmt.Println("waiting for finish")
// wait for finishUP channel write to close the app down
<-finishUP
fmt.Println("stopping things, might take 2 seconds")
// ... Do business Logic for shutdown simulated by Sleep 2 seconds
time.Sleep(2*time.Second)
// write to the done channel to signal we are done.
done <-struct{}{}
os.Exit(<-returnCode)
}
I build the image by running
docker build -f Dockerfile -t docker-shutdown .
I start a container by
docker run docker-shutdown
Then I try to shut it down by
docker stop <container id>
In the console that runs 'docker run', I can see:
waiting for finish
and it just terminated with no further output.
I would expect to see at least some output like
caught sig <SIGNAL_VALUE>
So why my expected behavior did not happen? I am also new to go
so I am not sure if it may have something to do with the go
code or the CMD
definition in the Dockerfile
.
My question:
Why the go
process cannot catch the either TERM and KILL signals?
Upvotes: 4
Views: 2429
Reputation: 773
go run
is getting the signal, not the program that is being run.
Compile the program ahead of time and run the binary directly in docker, and it will work as expected.
Upvotes: 4