问题描述
在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进程的两种方案。根据你的具体需求和应用程序的特点,选择适合你的方案。