如何让指定脚本在Packer构建成功或失败时均执行?
要实现不管前面的脚本(scriptA.sh、scriptB.sh)是否执行失败,scriptC.sh都能运行,你有几个可靠的方法,下面按推荐程度排序:
方法1:使用Packer的cleanup_provisioners(最推荐)
Packer原生支持清理阶段的provisioner,这些provisioner会在构建结束时自动执行——不管主provisioner是成功还是失败(刚好匹配你当前使用的packer build -on-error=cleanup参数)。
在你的template.json里,单独配置cleanup_provisioners字段,把scriptC.sh放在这里:
{ "builders": [ // 你的builder配置 ], "provisioners": [ { "type": "shell", "script": "scriptA.sh" }, { "type": "shell", "script": "scriptB.sh" } ], "cleanup_provisioners": [ { "type": "shell", "script": "scriptC.sh" } ] }
这个方法完全符合Packer的设计规范,逻辑清晰,不需要修改脚本内容,也不会掩盖前面脚本的错误状态,是最优解。
方法2:用Shell的trap捕获退出信号
如果不想拆分provisioner,可以把所有逻辑放到一个inline shell provisioner里,用trap命令注册EXIT信号的处理函数,确保scriptC.sh在shell会话结束时(不管正常退出还是异常退出)都会执行:
{ "provisioners": [ { "type": "shell", "inline": [ // 注册退出时执行scriptC.sh "trap './scriptC.sh' EXIT", // 执行你的主脚本 "./scriptA.sh", "./scriptB.sh" ] } ] }
注意替换脚本路径为实际相对/绝对路径即可,这个方法适合脚本之间有依赖、需要放在同一个会话中的场景。
方法3:强制执行脚本(简单但不推荐)
如果你只是想让scriptC.sh无条件执行,可以直接用Shell的分号分隔命令,忽略前面命令的错误状态:
{ "provisioners": [ { "type": "shell", "inline": [ "./scriptA.sh; ./scriptB.sh; ./scriptC.sh" ] } ] }
⚠️ 注意:这个方法的问题是,Packer会把整个inline命令的退出码设为最后一个命令(scriptC.sh)的退出码,这会掩盖scriptA.sh或scriptB.sh的错误——即使它们执行失败,Packer也会认为provisioner成功。所以除非你不在意前面脚本的错误状态,否则不建议用这个方法。
内容的提问来源于stack exchange,提问作者bigbaeng

