Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] 新增一个deploy重试机制,在cron中重试deploy #4845

Open
PMExtra opened this issue Oct 30, 2023 · 5 comments
Open

[Feature] 新增一个deploy重试机制,在cron中重试deploy #4845

PMExtra opened this issue Oct 30, 2023 · 5 comments

Comments

@PMExtra
Copy link
Contributor

PMExtra commented Oct 30, 2023

需求背景

目前 acme.sh 有很多的 deploy-hook 。这些 hook 大多依赖一个外部服务。

acme.sh --cron 更新证书时,如果外部服务临时发生异常,无法与 acme.sh 正确通信,则这个 deploy-hook 会失败,证书未能正确部署。而在这之后,即使外部服务恢复正常,也会因为错过这次证书从而更新导致证书过期。

当前行为

因为 acme.sh 下一次 cron 发现本地证书已经是最新的,在设定的有效期内,不需要更新,自然也就不触发 deploy 。所以即使外部服务恢复正常,也会发生证书过期。

举例(如果已经理解了以上内容就不用看了):
  • 第1天,acme.sh 申请了一个证书,有效期是90天,当有效期不足30天的时候自动更新证书。同时通过 docker deploy-hook 将证书部署到了指定容器。
  • 在第61天的时候,acme.sh 发现证书需要更新,向 CA 申请了新的证书。但是此时,Docker 或者指定容器因为各种原因没能正常工作,导致 deploy 失败。
  • 在第62天,容器恢复了正常工作,但是此时容器内的证书仍然是旧证书。
  • 在第62~90天里,acme.sh 每天检查证书状态,发现这个证书不需要刷新。而容器里一直还在用着旧证书。
  • 在第91天,容器里的证书过期了,服务发生异常。

此示例仅为了方便理解,使用最常见的 docker 举例。实际上 deploy-hook 还有许多类型,例如 Vault 这样需要远程通信的场景,实际发生失败的可能性并不低。

功能预期

在 deploy 的时候,记录每个 hook 的执行结果(return code),在下一次执行 --cron 的时候,检查每个 hook 上一次执行的结果,如果结果非0,则重新尝试 deploy 。

最后

麻烦 @Neilpang 大大评估一下这个功能设计能否被接受,如果可以接受,我可以之后抽空实现并提交 PR 。(当然如果大大或者其他好心人愿意帮忙实现那更是感激不尽)

@github-actions
Copy link

Please upgrade to the latest code and try again first. Maybe it's already fixed. acme.sh --upgrade If it's still not working, please provide the log with --debug 2, otherwise, nobody can help you.

@shaojs321
Copy link

运行acme.sh --cron时,我看命令行中最后有部署环节,可以设置cron通知,如果发现失败可以查看原因,解决问题后重新来一次acme.sh --cron --force
acme

@PMExtra
Copy link
Contributor Author

PMExtra commented Nov 26, 2023

@shaojs321 问题在于日常的cron是无人值守的,显然我每天--force一次是不太合理的。
而我的重点是说,一些情况下发生偶然的失败是无需人工干预,稍后重试就能自愈的,而目前cron模式是不会进行这种重试。

@Neilpang
Copy link
Member

可以, 这看起来的确是一个问题.

@PMExtra
Copy link
Contributor Author

PMExtra commented Sep 23, 2024

@Neilpang 我对这个问题进一步分析了一下,我目前有以下想法:

1. 记录安装部署的结果

_installcert() 函数中记录执行结果,在 _deploy() 函数中也记录每个 hook 的执行结果,都用 _savedomainconf 分别保存起来。

Q1. 这里记返回值(错误码)还是记时间戳?

  • 如果记返回值,当记录的返回值为大于0,视作上次部署失败,需要重试;每次执行后无论成败记录最后一次返回值。
  • 如果记时间戳,可以用 部署时间戳 和 证书签发时间戳 做比较,如果 部署时间戳 小于 证书签发时间戳,就说明最新的证书没有被成功部署,需要重试。只在安装部署执行成功的时候,才更新这个时间戳。

2. 添加 _ensure_install_ensure_deploy 函数

acme.sh/acme.sh

Lines 5465 to 5474 in e036eea

if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
_info "Skipping. Next renewal time is: $(__green "$Le_NextRenewTimeStr")"
_info "Add '$(__red '--force')' to force renewal."
if [ -z "$_ACME_IN_RENEWALL" ]; then
if [ $_set_level -ge $NOTIFY_LEVEL_SKIP ]; then
_send_notify "Renew $Le_Domain skipped" "Good, the cert is skipped." "$NOTIFY_HOOK" "$RENEW_SKIP"
fi
fi
return "$RENEW_SKIP"
fi

新增 _ensure_install_ensure_deploy 函数,在 renew 函数的 5473 行之前调用。

即刷新操作因为时间没到而被跳过的时候,检查证书的安装部署。

具体检查方式如上述第 1 点所述,如果需要重试,就调用对应的 installcert <domain>_deploy <domain> <hook>

Q2. 是否只在 cron 环境下做部署重试?

感觉对所有的 renew 操作都做这个检查重试,好像也没什么问题。但如果不希望给 renew 命令带来副作用,那就加上判断。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants