在Docker中,使用’CMD cmd1 && cmd2’和’CMD cmd1 && exec cmd2’有什么优缺点?

87次阅读
没有评论

问题描述

在Docker中使用shell形式的多个启动命令(CMD)时,想知道使用shell的exec特性将其替换为链中的最后一个命令,与仅将其作为启动shell的子进程运行相比,是否有任何优势?
以下是一个示例:

CMD npm install && npm start

与:

CMD npm install && exec npm start

我认为在后一个示例中,npm start命令将替换shell作为PID 1进程。但我不完全理解这样做会有哪些优势或劣势。

解决方案

请注意以下操作注意版本差异及修改前做好备份。

方案1

当你使用exec语法将PID 1替换为新的可执行文件时,而不是将其作为子PID进行分叉,你会减少一些开销(稍微)。更重要的是,你可以直接将信号发送到你的应用程序,而不是将它们传递给作为PID 1运行的shell。默认情况下,作为PID 1运行的shell将忽略docker发送的SIGTERM信号,以优雅地停止你的应用程序。在10秒内没有响应后,docker将发送SIGKILL信号,立即终止shell和子进程,而不给它们机会来处理网络连接或完成对任何文件的写入。这可能导致数据库损坏,这取决于容器中的应用程序是什么。
即使对于你的应用程序不适用这一点(如果没有状态),通过切换到exec语法,每次停止容器时都可以节省多达10秒的时间(假设你的应用程序在接收到SIGTERM时退出)。因此,我更喜欢使用exec语法,既可以保证数据安全性,又可以提高速度。

方案2

请注意以下操作注意版本差异及修改前做好备份。
另一种方法是使用exec命令来替换shell作为PID 1进程。这样做的好处是可以直接将信号发送到应用程序,而不是传递给shell。这样可以避免一些潜在的问题,比如shell忽略SIGTERM信号,导致应用程序无法优雅地停止。此外,使用exec命令还可以减少一些开销,因为不需要创建新的进程。
以下是使用exec命令的示例:

CMD npm install && exec npm start

在上面的示例中,我们使用exec命令将npm start替换为PID 1进程。这样,当Docker发送SIGTERM信号时,它将直接发送给npm start,而不是传递给shell。这样可以确保应用程序能够优雅地停止,并避免潜在的问题。
请注意,使用exec命令可能会导致一些副作用,具体取决于你的应用程序和容器环境。因此,在使用exec命令之前,请确保你了解其可能的影响,并进行适当的测试。
以上是使用exec命令替换shell作为PID 1进程的两种方案。根据你的具体需求和应用程序的特点,选择适合你的方案。

正文完