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.
Environment information
Currently running on Mac M1 system with the following docker version.
|
|
Next is the docker-compose version information.
Code examples
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 jobChan
, and 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 SIGKILL
signal.
For example:
|
|
docker-compose settings
Since 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.
For more details, please refer to stop_signal and stop_grace_period. After these two settings, you can also use docker-compose up -d
to restart the container service normally.
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 ps
command.
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 CMD
or 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.
If you want to handle signal signals from bash, you can refer to this article “Trapping signals in Docker containers”. Please see the docker-compose example on the website below.
Summary
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.