You should have encountered that if the service still has jobs to be processed and the service is to be updated, you need to wait until all jobs are processed before you can stop the service. When the service receives a shutdown notification signal, it should stop accepting jobs first, and then wait for the worker to finish processing the jobs before stopping the service, and then go online again. How to stop the service by docker-compose is the focus of this article. In this article, we will use Go Language as an example to teach how to accept signal from Docker, what to do after accepting the signal, and how to set up the YAML file of docker-compose to make sure all jobs can be executed properly.
Currently running on Mac M1 system with the following docker version.
Next is the docker-compose version information.
By preparing the actual application example first, we can run a service that is dedicated to performing some work that takes a long time. When we need to update the service, we need to stop the service from accepting any more work and wait for the work we were running to be done before we stop the service. Here is an example in Go language.
As you can see in the above example, four workers are created to receive job execution content, and the last Goroutine is used to generate jobs. In addition, two channels are given to stop the worker and stop the job generation. When the program is in progress, pressing
ctrl + c directly will trigger
stopped, which will stop sending jobs into
finished will be closed when the four workers have finished executing the rest of the jobs. This will officially stop the four workers. Next, let’s see how to stop the service with the docker-compose command.
Using docker-compose command
To restart the service, you can first shut down the service with
docker-compose stop. If the service is not processing the Signal, the service will be stopped directly. Then the running Job will be cut off, which is obviously not what you want. So when you write the program, you must handle the Signal signal, and when you run docker-compose stop, docker will send
SIGTERM signal to the container (the root process
PID in the container is 1), and the service can do the follow-up after receiving this signal. But you will find that after
10 seconds, docker will send another signal
SIGKILL to force the service to shut down. To solve this problem, it’s easy to know how much time each job will take, and how much time it will take to run all four workers. At this point, you can add
-t to determine how many seconds to send the
docker-compose stop is set to send
SIGTERM signal first, if you want to replace it with another signal, you can add
stop_signal to docker-compose.yml directly to determine the new signal, besides this, you can also set
stop_grace_period to determine how long it takes for docker to send
SIGKILL, the default is 10 seconds, which can be adjusted in the above way.
docker signal handling
From the above, we know that every service needs to handle signals from docker, and what should we pay attention to when writing a dockerfile? Here is an example of Go language with Dockerfile:
Then compile and execute.
After the start, you will find that after the stop command, the container does not receive this signal at all, then go directly into the container to check, through the
You will find that the
SIGTERM signal is sent to PID 1, but the real process ID is 68, so the reason for not receiving the signal is here. The solution here is also very simple, that is, do not run through the
go run method to run, but first build into a runtime file before using.
Also, if you use
["program", "arg1", "arg2"] in
ENTRYPOINT, instead of
program arg1 arg2, the latter will wrap another layer of bash in front of it for docker, but bash basically doesn’t handle Signal signals, which will also cause This will also prevent the service from shutting down properly.
In addition to Docker signal processing, you also need to use
docker-compose up --scale to complete the service scaling. If the service needs to handle a lot of work and work for a long time, you need to update the service by this way, otherwise the work is suddenly interrupted, how to resume the work is another issue to be solved.