在docker入口点脚本中使用exec的目的是什么?

m0m*_*eni 31 bash docker

例如在redis官方图片中:

https://github.com/docker-library/redis/blob/master/2.8/docker-entrypoint.sh

#!/bin/bash
set -e

if [ "$1" = 'redis-server' ]; then
    chown -R redis .
    exec gosu redis "$@"
fi

exec "$@"
Run Code Online (Sandbox Code Playgroud)

为什么不像往常一样运行命令而不在它们之前的exec?

Adr*_*uat 47

正如@Peter Lyons所说,使用exec将替换父进程,而不是运行两个进程.

这在Docker中非常重要,可以正确代理信号.例如,如果Redis是在没有exec的情况下启动的,它将不会接收到SIGTERM,docker stop并且不会有机会干净地关闭.在某些情况下,这可能会导致数据丢失或僵尸进程.

如果确实启动了子进程(即不使用exec),则父进程负责处理和转发信号.这是在容器中运行多个进程时最好使用supervisord或类似的原因之一,因为它会适当地转发信号.

  • 这非常重要. (3认同)

Pet*_*ons 17

如果没有exec,父shell进程将继续存在并等待子进程退出.使用exec,子进程完全替换父进程,所以当父进程分配后父进程没有任何内容时,我会考虑exec更精确/正确/有效.在宏观方案中,我认为将其归类为次要优化可能是安全的.

没有执行官

  • 父shell启动
  • 父壳叉子
    • 孩子跑
    • 孩子退出
  • 父shell退出

与执行官

  • 父shell启动
  • 父壳子叉子,用孩子代替
  • 子程序运行接管shell的过程
  • 孩子退出

  • 我认为它比"次要优化"更重要,因为父进程负责处理信号.我在答案中写了一点. (3认同)
  • 不,只有 1 个 shell,但不是分叉子进程,等待子进程退出,然后“哦,看我已经到了脚本文件的末尾,没有什么可做了”,然后退出, `exec` 版本基本上“预先退出”父 shell,因此当子 shell 接管时它已经消失了。然而,关于这种舞蹈的精确机制,我将不得不听从更深入的 Unix 开发人员的意见。 (2认同)