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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32255814/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 13:30:23  来源:igfitidea点击:

What purpose does using exec in docker entrypoint scripts serve?

bashdocker

提问by m0meni

For example in the redis official image:

例如在redis官方图片中:

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

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

#!/bin/bash
set -e

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

exec "$@"

Why not just run the commands as usual without exec preceding them?

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

回答by Adrian Mouat

As @Peter Lyons says, using exec will replace the parent process, rather than have two processes running.

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

This is important in Docker for signals to be proxied correctly. For example, if Redis was started without exec, it will not receive a SIGTERMupon docker stopand will not get a chance to shutdown cleanly. In some cases, this can lead to data loss or zombie processes.

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

If you do start child processes (i.e. don't use exec), the parent process becomes responsible for handling and forwarding signals as appropriate. This is one of the reasons it's best to use supervisord or similar when running multiple processes in a container, as it will forward signals appropriately.

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

回答by Peter Lyons

Without exec, the parent shell process survives and waits for the child to exit. With exec, the child process replaces the parent process entirely so when there's nothing for the parent to do after forking the child, I would consider execslightly more precise/correct/efficient. In the grand scheme of things, I think it's probably safe to classify it as a minor optimization.

如果没有 exec,父 shell 进程将继续存在并等待子进程退出。使用 exec,子进程完全替换了父进程,因此当在 fork 子进程后父进程无事可做时,我会考虑exec稍微更精确/正确/高效。从大局来看,我认为将其归类为次要优化可能是安全的。

without exec

没有执行

  • parent shell starts
  • parent shell forks child
    • child runs
    • child exits
  • parent shell exits
  • 父 shell 启动
  • 父壳叉子
    • 孩子跑
    • 孩子退出
  • 父壳退出

with exec

与执行

  • parent shell starts
  • parent shell forks child, replaces itself with child
  • child program runs taking over the shell's process
  • child exits
  • 父 shell 启动
  • 父壳 fork 子,用子替换自身
  • 子程序运行接管外壳程序
  • 孩子退出

回答by Mark Plotnick

Think of it as an optimization like tail recursion.

将其视为像尾递归这样的优化。

If running another program is the final act of the shell script, there's not much of a need to have the shell run the program in a new process and wait for it. Using exec, the shell process replaces itself with the program.

如果运行另一个程序是 shell 脚本的最后一步,则没有太多需要让 shell 在新进程中运行程序并等待它。使用exec,shell 进程将自身替换为程序。

In either case, the exit value of the shell script will be identical1. Whatever program originally called the shell script will see an exit value that is equal to the exit value of the exec`ed program (or 127 if the program cannot be found).

在任何一种情况下,shell 脚本的退出值都将是相同的1。无论最初调用 shell 脚本的程序是什么,都会看到一个退出值,该值等于被执行的程序的退出值(如果找不到该程序,则为 127)。

1modulo corner cases such as a program doing something different depending on the name of its parent.

1模极端情况,例如程序根据其父项的名称执行不同的操作。