Skip to content

Commit 7c8af49

Browse files
authored
Controller: Make Leader Election TTL configurable. (#11142)
* feature(leader_ttl): feature to customize ttl to leader be re-elected * fix(review): docs
1 parent aedb13c commit 7c8af49

File tree

9 files changed

+93
-8
lines changed

9 files changed

+93
-8
lines changed

charts/ingress-nginx/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
297297
| controller.dnsConfig | object | `{}` | Optionally customize the pod dnsConfig. |
298298
| controller.dnsPolicy | string | `"ClusterFirst"` | Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. |
299299
| controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' |
300+
| controller.electionTTL | string | `""` | Duration a leader election is valid before it's getting re-elected, e.g. `15s`, `10m` or `1h`. (Default: 30s) |
300301
| controller.enableAnnotationValidations | bool | `false` | |
301302
| controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # |
302303
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto" Defaults to false |

charts/ingress-nginx/templates/_params.tpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@
6363
{{- if .Values.controller.disableLeaderElection }}
6464
- --disable-leader-election=true
6565
{{- end }}
66+
{{- if .Values.controller.electionTTL }}
67+
- --election-ttl={{ .Values.controller.electionTTL }}
68+
{{- end }}
6669
{{- range $key, $value := .Values.controller.extraArgs }}
6770
{{- /* Accept keys without values or with false as value */}}
6871
{{- if eq ($value | quote | len) 2 }}

charts/ingress-nginx/values.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ controller:
8585
enableTopologyAwareRouting: false
8686
# -- This configuration disable Nginx Controller Leader Election
8787
disableLeaderElection: false
88+
# -- Duration a leader election is valid before it's getting re-elected, e.g. `15s`, `10m` or `1h`. (Default: 30s)
89+
electionTTL: ""
8890
# -- This configuration defines if Ingress Controller should allow users to set
8991
# their own *-snippet annotations, otherwise this is forbidden / dropped
9092
# when users add those annotations.

docs/user-guide/cli-arguments.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment
2222
| `--disable-sync-events` | Disables the creation of 'Sync' Event resources, but still logs them |
2323
| `--dynamic-configuration-retries` | Number of times to retry failed dynamic configuration before failing to sync an ingress. (default 15) |
2424
| `--election-id` | Election id to use for Ingress status updates. (default "ingress-controller-leader") |
25+
| `--election-ttl` | Duration a leader election is valid before it's getting re-elected, e.g. `15s`, `10m` or `1h`. (Default: 30s) |
2526
| `--enable-metrics` | Enables the collection of NGINX metrics. (default true) |
2627
| `--enable-ssl-chain-completion` | Autocomplete SSL certificate chains with missing intermediate CA certificates. Certificates uploaded to Kubernetes must have the "Authority Information Access" X.509 v3 extension for this to succeed. (default false)|
2728
| `--enable-ssl-passthrough` | Enable SSL Passthrough. (default false) |

internal/ingress/controller/controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ type Configuration struct {
9191
UpdateStatus bool
9292
UseNodeInternalIP bool
9393
ElectionID string
94+
ElectionTTL time.Duration
9495
UpdateStatusOnShutdown bool
9596

9697
HealthCheckHost string

internal/ingress/controller/nginx.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,9 @@ func (n *NGINXController) Start() {
274274
if !n.cfg.DisableLeaderElection {
275275
electionID := n.cfg.ElectionID
276276
setupLeaderElection(&leaderElectionConfig{
277-
Client: n.cfg.Client,
278-
ElectionID: electionID,
277+
Client: n.cfg.Client,
278+
ElectionID: electionID,
279+
ElectionTTL: n.cfg.ElectionTTL,
279280
OnStartedLeading: func(stopCh chan struct{}) {
280281
if n.syncStatus != nil {
281282
go n.syncStatus.Run(stopCh)

internal/ingress/controller/status.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import (
3636
type leaderElectionConfig struct {
3737
Client clientset.Interface
3838

39-
ElectionID string
39+
ElectionID string
40+
ElectionTTL time.Duration
4041

4142
OnStartedLeading func(chan struct{})
4243
OnStoppedLeading func()
@@ -107,13 +108,11 @@ func setupLeaderElection(config *leaderElectionConfig) {
107108
LockConfig: resourceLockConfig,
108109
}
109110

110-
ttl := 30 * time.Second
111-
112111
elector, err = leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
113112
Lock: lock,
114-
LeaseDuration: ttl,
115-
RenewDeadline: ttl / 2,
116-
RetryPeriod: ttl / 4,
113+
LeaseDuration: config.ElectionTTL,
114+
RenewDeadline: config.ElectionTTL / 2,
115+
RetryPeriod: config.ElectionTTL / 4,
117116

118117
Callbacks: callbacks,
119118
})

pkg/flags/flags.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ Requires setting the publish-service parameter to a valid Service reference.`)
132132
electionID = flags.String("election-id", "ingress-controller-leader",
133133
`Election id to use for Ingress status updates.`)
134134

135+
electionTTL = flags.Duration("election-ttl", 30*time.Second,
136+
`Duration a leader election is valid before it's getting re-elected`)
137+
135138
updateStatusOnShutdown = flags.Bool("update-status-on-shutdown", true,
136139
`Update the load-balancer status of Ingress objects when the controller shuts down.
137140
Requires the update-status parameter.`)
@@ -314,6 +317,10 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
314317
}
315318
}
316319

320+
if *electionTTL <= 0 {
321+
*electionTTL = 30 * time.Second
322+
}
323+
317324
histogramBuckets := &collectors.HistogramBuckets{
318325
TimeBuckets: *timeBuckets,
319326
LengthBuckets: *lengthBuckets,
@@ -327,6 +334,7 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
327334
KubeConfigFile: *kubeConfigFile,
328335
UpdateStatus: *updateStatus,
329336
ElectionID: *electionID,
337+
ElectionTTL: *electionTTL,
330338
EnableProfiling: *profiling,
331339
EnableMetrics: *enableMetrics,
332340
MetricsPerHost: *metricsPerHost,

pkg/flags/flags_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package flags
1919
import (
2020
"os"
2121
"testing"
22+
"time"
2223
)
2324

2425
func TestNoMandatoryFlag(t *testing.T) {
@@ -143,3 +144,71 @@ func TestIfLeaderElectionDisabledFlagIsFalse(t *testing.T) {
143144
t.Fatalf("Expected --disable-leader-election and conf.DisableLeaderElection as false, but found: %v", conf.DisableLeaderElection)
144145
}
145146
}
147+
148+
func TestLeaderElectionTTLDefaultValue(t *testing.T) {
149+
ResetForTesting(func() { t.Fatal("Parsing failed") })
150+
151+
oldArgs := os.Args
152+
defer func() { os.Args = oldArgs }()
153+
os.Args = []string{"cmd", "--http-port", "80", "--https-port", "443"}
154+
155+
_, conf, err := ParseFlags()
156+
if err != nil {
157+
t.Fatalf("Unexpected error parsing default flags: %v", err)
158+
}
159+
160+
if conf.ElectionTTL != 30*time.Second {
161+
t.Fatalf("Expected --election-ttl and conf.ElectionTTL as 30s, but found: %v", conf.ElectionTTL)
162+
}
163+
}
164+
165+
func TestLeaderElectionTTLParseValueInSeconds(t *testing.T) {
166+
ResetForTesting(func() { t.Fatal("Parsing failed") })
167+
168+
oldArgs := os.Args
169+
defer func() { os.Args = oldArgs }()
170+
os.Args = []string{"cmd", "--http-port", "80", "--https-port", "443", "--election-ttl", "10s"}
171+
172+
_, conf, err := ParseFlags()
173+
if err != nil {
174+
t.Fatalf("Unexpected error parsing default flags: %v", err)
175+
}
176+
177+
if conf.ElectionTTL != 10*time.Second {
178+
t.Fatalf("Expected --election-ttl and conf.ElectionTTL as 10s, but found: %v", conf.ElectionTTL)
179+
}
180+
}
181+
182+
func TestLeaderElectionTTLParseValueInMinutes(t *testing.T) {
183+
ResetForTesting(func() { t.Fatal("Parsing failed") })
184+
185+
oldArgs := os.Args
186+
defer func() { os.Args = oldArgs }()
187+
os.Args = []string{"cmd", "--http-port", "80", "--https-port", "443", "--election-ttl", "10m"}
188+
189+
_, conf, err := ParseFlags()
190+
if err != nil {
191+
t.Fatalf("Unexpected error parsing default flags: %v", err)
192+
}
193+
194+
if conf.ElectionTTL != 10*time.Minute {
195+
t.Fatalf("Expected --election-ttl and conf.ElectionTTL as 10m, but found: %v", conf.ElectionTTL)
196+
}
197+
}
198+
199+
func TestLeaderElectionTTLParseValueInHours(t *testing.T) {
200+
ResetForTesting(func() { t.Fatal("Parsing failed") })
201+
202+
oldArgs := os.Args
203+
defer func() { os.Args = oldArgs }()
204+
os.Args = []string{"cmd", "--http-port", "80", "--https-port", "443", "--election-ttl", "1h"}
205+
206+
_, conf, err := ParseFlags()
207+
if err != nil {
208+
t.Fatalf("Unexpected error parsing default flags: %v", err)
209+
}
210+
211+
if conf.ElectionTTL != 1*time.Hour {
212+
t.Fatalf("Expected --election-ttl and conf.ElectionTTL as 1h, but found: %v", conf.ElectionTTL)
213+
}
214+
}

0 commit comments

Comments
 (0)