2

My custom docker-compose command won't stop gracefully. Why isn't the below working and how can I fix it properly (i.e. no SIGKILL)?

I've written these tests to demonstrate:

version: '3.3'

services:
    # My personal use case
    test1_string:
        image: python:3.9.0rc1-alpine3.12
        command: 'python -u -m smtpd -n -c DebuggingServer 0.0.0.0:1025'

    # https://docs.docker.com/compose/faq/
    # "Compose always uses the JSON form, so don’t worry if you override the command or entrypoint in your Compose file."
    test2_list:
        image: python:3.9.0rc1-alpine3.12
        command: ['python', '-u', '-m', 'smtpd', '-n', '-c', 'DebuggingServer', '0.0.0.0:1025']

    # Maybe it's an issue with networking and syscalls?
    # Using nc once for a comparison to smtpd DebuggingServer above
    test3_bash:
        image: bash:5.0.18
        command: ['bash', '-c', 'nc -k -l 4444 > filename.out']

    # Something simpler, just a sleep.
    test4_bash_sleep:
        image: bash:5.0.18
        command: ['bash', '-c', 'sleep 100']

    # Apparently bash doesn't forward signals, but exec can help (?)
    test5_bash_exec:
        image: bash:5.0.18
        command: ['bash', '-c', 'exec sleep 100']

    # Print any signals sent to the executable
    test6_bash_trap:
        image: bash:5.0.18
        command: ['bash', '-c', 'for s in HUP INT TERM KILL EXIT ; do trap "echo $$s; exit 0" $$s ; done ; sleep 100']

    # Finally, use SIGKILL instead of SIGTERM. This works, but is overkill and not at all graceful.
    test7_kill:
        image: python:3.9.0rc1-alpine3.12
        command: ['python', '-u', '-m', 'smtpd', '-n', '-c', 'DebuggingServer', '0.0.0.0:1025']
        stop_signal: SIGKILL

This is the output, hitting Ctrl-C after theyre up:

$ docker-compose --version
docker-compose version 1.25.4, build unknown
$ docker --version
Docker version 19.03.11, build 42e35e6
$ docker-compose up
Creating docker_stop_test2_list_1       ... done
Creating docker_stop_test1_string_1     ... done
Creating docker_stop_test6_bash_trap_1  ... done
Creating docker_stop_test4_bash_sleep_1 ... done
Creating docker_stop_test7_kill_1       ... done
Creating docker_stop_test5_bash_exec_1  ... done
Creating docker_stop_test3_bash_1       ... done
Attaching to docker_stop_test4_bash_sleep_1, docker_stop_test5_bash_exec_1, docker_stop_test2_list_1, docker_stop_test3_bash_1, docker_stop_test6_bash_trap_1, docker_stop_test7_kill_1, docker_stop_test1_string_1
^CGracefully stopping... (press Ctrl+C again to force)
Stopping docker_stop_test5_bash_exec_1  ... 
Stopping docker_stop_test3_bash_1       ... 
Stopping docker_stop_test6_bash_trap_1  ... 
Stopping docker_stop_test7_kill_1       ... done
Stopping docker_stop_test1_string_1     ... 
Stopping docker_stop_test2_list_1       ... 
Stopping docker_stop_test4_bash_sleep_1 ... 

test7_kill is the only one that stops but it's using SIGKILL. How can I make any of the others work?

jozxyqk
  • 16,424
  • 12
  • 91
  • 180
  • Does your application code explicitly listen for SIGTERM? Does adding [`init: true`](https://docs.docker.com/compose/compose-file/#init) help? – David Maze Sep 08 '20 at 11:46
  • Thanks for the suggestion, David! I don't have a custom application yet. My use case is python's smtpd, as above (the whole compose file is standalone). The bash test explicitly listens for SIGTERM but it isn't hit. Sadly my docker-compose (Fedora 32) doesn't support `init` so I can't test it. – jozxyqk Sep 08 '20 at 21:30
  • Try `entrypoint` instead of `command`, and use the exec form for the arguments. e.g. `entrypoint: [...]` – smac89 Jun 27 '22 at 21:18

0 Answers0