【问题标题】:Signal handlers of C++ application within a docker container are not workingdocker 容器中 C++ 应用程序的信号处理程序不工作
【发布时间】:2021-12-29 03:48:36
【问题描述】:

我有以下 C++ 代码:

#include <signal>
#include <iostream>

void sig_handler(int signo, siginfo_t *info, void *_ctx) {
      
    cout << "HANDLE AND RESET!!" << endl;

    // try to forward the signal.
    raise(info->si_signo);

    // terminate the process immediately.
    puts("watf? exit");
    _exit(EXIT_FAILURE);
}


void registerSignalHandlers() {
    vector<int> signals = {
      // Signals for which the default action is "Core".
      SIGABRT, // Abort signal from abort(3)
      SIGBUS,  // Bus error (bad memory access)
      SIGFPE,  // Floating point exception
      SIGILL,  // Illegal Instruction
      SIGIOT,  // IOT trap. A synonym for SIGABRT
      SIGQUIT, // Quit from keyboard
      SIGSEGV, // Invalid memory reference
      SIGSYS,  // Bad argument to routine (SVr4)
      SIGTRAP, // Trace/breakpoint trap
      SIGXCPU, // CPU time limit exceeded (4.2BSD)
      SIGXFSZ, // File size limit exceeded (4.2BSD)
      SIGTERM
    };
    
    
    for (size_t i = 0; i < signals.size(); ++i) {
      struct sigaction action;
      memset(&action, 0, sizeof action);
      action.sa_flags = static_cast<int>(SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND);
      sigfillset(&action.sa_mask);
      sigdelset(&action.sa_mask, signals[i]);
      action.sa_sigaction = &sig_handler;

      int r = sigaction(signals[i], &action, nullptr);
    }

}



int main(int argc, char *argv[]) {
    
    registerSignalHandlers();

    //rest of the code goes here

    return 0;
}

我在带有debian:stretch 图像的docker 容器中运行我的应用程序,tini 作为 PID 1(直接使用它而不是通过bash)。当我在我的设备(MacBook Pro)上运行容器时,一切正常,没有任何问题。我试图在我的代码中导致分段错误SIGSEGV 异常来测试处理程序触发器,在我的设备上,它工作正常,但是一旦我在服务器(CentOS 7)上运行相同的容器,处理程序就根本不工作。

我所说的根本不工作的意思是我的应用程序永远不会收到信号。我尝试从容器kill -15 PID_OF_APPLICATION 内部手动发送信号,并且处理程序工作得很好,但如果发送kill -11 PID_OF_APPLICATION 处理程序不起作用并且不知道为什么!

我尝试使用strace 检查我的代码是否引发了信号,我能够看到SIGSEGV 引发了。

另外,我尝试运行一个脚本来运行我的应用程序和trap 它接收到的信号。在脚本中接收到信号,但处理程序也没有被触发

我不确定我是否遗漏了与 docker 容器配置相关的内容(我正在使用 docker-compose),但我认为我做的一切都是正确的,因为我的设备上有同一个 docker-compose 文件正在启动容器,它可以正常工作。

容器内的应用程序发出的信号是否也通过 PID 1 处理? tini 就我而言。

非常感谢任何帮助

更新

如果我将入口点设置为 sleep infinity 并使用 docker exec -it container_id bash 进入 docker 容器,然后手动启动我的应用程序作为前台进程,处理程序可以正常工作

【问题讨论】:

  • Docker 捕捉到一些信号。根据个人经验,我知道它对键盘中断 (Ctrl-c) 起作用,但我不知道其他信号。我的猜测是必须有一些 Docker 配置来进行信号处理?
  • 我浏览的所有资源都在谈论从主机向容器发送信号,但我没有发现任何对从容器内部发出的信号有用的东西。我试图覆盖默认停止信号,但也没有任何效果@HumphreyWinnebago

标签: c++ linux docker signals


【解决方案1】:

我以前去过那里。这是一场真正的斗争,尤其是当事情在您的设备上运行但在其他设备上却无法运行时。

我会写下我为自己的问题所做的步骤,也许它可以为您提供一些解决方案。

在 macOS 上一切正常,我不得不比较我的设备和 CentOS7 服务器之间的 docker 引擎版本,但没有区别!

然后我尝试在 Ubuntu 而不是 CentOS7 上使用 docker-compose 运行相同的 docker 映像,这让我感到惊讶!它也可以工作,所以我的问题只在 CentOS7 上。我建议您也这样做,尝试在另一个操作系统(如 Ubuntu)上运行您的 docker 映像,以确保您的问题与您的实际应用程序无关。

尝试使用 cronjob 运行您的应用

是的,尝试将其作为 cronjob 运行。我不确定问题的根本原因,但这对我有用。我认为这与运行容器 Here 时 docker 代理如何发出信号有关,您会在 README 文件的末尾找到关于信号的有用结论,具体取决于您运行容器的方式。

另外,另一个可能的原因是当应用程序在后台运行时,信号不会以某种方式代理给它,因此将其作为 cronjob 运行与常规后台进程不同。

您可以将此方法作为一个完整的解决方案来管理,维护 docker 容器对您的应用程序的响应(包括崩溃),如下所示:

  1. 使用tini 作为容器的入口点。
  2. 使tiniCMD 运行您的脚本
  3. 您的脚本将使用您的 cronjob 更新 crontab 文件(由您决定运行频率)
  4. 添加的 cron 将运行您的实际运行脚本。
  5. 您的运行脚本应该有一个trap 函数。为什么?一旦您的应用程序崩溃,您可以向您的入口点脚本(点#2)发送一个 KILL 信号,这将杀死 docker 容器。通过这种方式,您可以保持将应用作为入口点运行的行为。

希望这对您的情况有所帮助。

【讨论】:

  • 我尝试在 Ubuntu 上运行我的应用程序,它确实有效。我简直不敢相信我在这件事上花了多少时间!!
猜你喜欢
  • 2014-10-07
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
  • 1970-01-01
  • 2022-11-16
  • 1970-01-01
  • 2019-05-18
  • 2017-05-06
相关资源
最近更新 更多