kube/certs: use Let's Encrypt's recommended retry schedule (#20292)
Replace the doubling backoff (1m, 2m, 4m, ...) with LE's recommended 1m, 10m, 100m, daily. The old schedule burned retry attempts inside the rate-limit window without speeding recovery. Updates #20288 Updates #19895 Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
This commit is contained in:
+15
-14
@@ -94,6 +94,16 @@ func (cm *CertManager) EnsureCertLoops(ctx context.Context, sc *ipn.ServeConfig)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// retrySchedule is the wait between successive failed issuance attempts,
|
||||||
|
// following LE's recommended schedule.
|
||||||
|
// https://letsencrypt.org/docs/integration-guide/#retrying-failures
|
||||||
|
var retrySchedule = []time.Duration{
|
||||||
|
1 * time.Minute,
|
||||||
|
10 * time.Minute,
|
||||||
|
100 * time.Minute,
|
||||||
|
24 * time.Hour,
|
||||||
|
}
|
||||||
|
|
||||||
// runCertLoop:
|
// runCertLoop:
|
||||||
// - calls localAPI certificate endpoint to ensure that certs are issued for the
|
// - calls localAPI certificate endpoint to ensure that certs are issued for the
|
||||||
// given domain name
|
// given domain name
|
||||||
@@ -103,13 +113,8 @@ func (cm *CertManager) EnsureCertLoops(ctx context.Context, sc *ipn.ServeConfig)
|
|||||||
// Note that renewal check also happens when the node receives an HTTPS request and it is possible that certs get
|
// Note that renewal check also happens when the node receives an HTTPS request and it is possible that certs get
|
||||||
// renewed at that point. Renewal here is needed to prevent the shared certs from expiry in edge cases where the 'write'
|
// renewed at that point. Renewal here is needed to prevent the shared certs from expiry in edge cases where the 'write'
|
||||||
// replica does not get any HTTPS requests.
|
// replica does not get any HTTPS requests.
|
||||||
// https://letsencrypt.org/docs/integration-guide/#retrying-failures
|
|
||||||
func (cm *CertManager) runCertLoop(ctx context.Context, domain string) {
|
func (cm *CertManager) runCertLoop(ctx context.Context, domain string) {
|
||||||
const (
|
const normalInterval = 24 * time.Hour // regular renewal check
|
||||||
normalInterval = 24 * time.Hour // regular renewal check
|
|
||||||
initialRetry = 1 * time.Minute // initial backoff after a failure
|
|
||||||
maxRetryInterval = 24 * time.Hour // max backoff period
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := cm.waitForCertDomain(ctx, domain); err != nil {
|
if err := cm.waitForCertDomain(ctx, domain); err != nil {
|
||||||
// Best-effort, log and continue with the issuing loop.
|
// Best-effort, log and continue with the issuing loop.
|
||||||
@@ -153,15 +158,11 @@ func (cm *CertManager) runCertLoop(ctx context.Context, domain string) {
|
|||||||
nextInterval = normalInterval
|
nextInterval = normalInterval
|
||||||
} else {
|
} else {
|
||||||
retryCount++
|
retryCount++
|
||||||
// Calculate backoff: initialRetry * 2^(retryCount-1)
|
idx := retryCount - 1
|
||||||
// For retryCount=1: 1min * 2^0 = 1min
|
if idx >= len(retrySchedule) {
|
||||||
// For retryCount=2: 1min * 2^1 = 2min
|
idx = len(retrySchedule) - 1
|
||||||
// For retryCount=3: 1min * 2^2 = 4min
|
|
||||||
backoff := initialRetry * time.Duration(1<<(retryCount-1))
|
|
||||||
if backoff > maxRetryInterval {
|
|
||||||
backoff = maxRetryInterval
|
|
||||||
}
|
}
|
||||||
nextInterval = backoff
|
nextInterval = retrySchedule[idx]
|
||||||
cm.logf("Error refreshing certificate for %s (retry %d): %v. Will retry in %v\n",
|
cm.logf("Error refreshing certificate for %s (retry %d): %v. Will retry in %v\n",
|
||||||
domain, retryCount, err, nextInterval)
|
domain, retryCount, err, nextInterval)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user