在Docker里应用监听不到Signal怎么办?

# 问题描述

最近程序在docker里运行时,signal.Notify(sigChannel, syscall.SIGINT, syscall.SIGTERM)收不到信号了,导致发版时程序不能优雅关闭。

调查发现最忌的改动是把Dockerfile里的CMD由原先的bin文件改为了shell脚本。如下图: image

# 问题原因

经过搜索了解到,Docker stop的signal只会发给1号进程,CMD启动的就是1号进程。在本次案例中,本来CMD直接启动Bin文件,所以是可以直接收到Signal的。而改为Shell脚本后,Shell脚本是1号进程,由Shell脚本启动的Bin变成了x号进程。所以我们需要让Shell脚本收到的Signal转发给x号进程。

# 解决方案

#!/bin/bash

prep_term()
{
    unset term_child_pid
    unset term_kill_needed
    trap 'handle_term' TERM INT
}

handle_term()
{
    if [ "${term_child_pid}" ]; then
        kill -TERM "${term_child_pid}" 2>/dev/null
    else
        term_kill_needed="yes"
    fi
}

wait_term()
{
    term_child_pid=$!
    if [ "${term_kill_needed}" ]; then
        kill -TERM "${term_child_pid}" 2>/dev/null
    fi
    wait ${term_child_pid}
    trap - TERM INT
    wait ${term_child_pid}
}

run() {
  ./bin/server -mode cluster &
}

run_with_ddns() {
  ./launcher -name zt-ddgw-internal -port 8088 ./bin/server -mode cluster &
}

prep_term
if [ $RUN_WITH_DDNS ]; then
  run_with_ddns
else
  run
fi
wait_term

# 参考内容

  • https://www.cnblogs.com/sparkdev/p/7598590.html
  • https://unix.stackexchange.com/questions/146756/forward-sigterm-to-child-in-bash