From d45194b89224f633372adba5c16a473afaa3167a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=BE=E7=A1=95?= Date: Fri, 22 May 2026 16:31:13 +0800 Subject: [PATCH] Add configurable leader election timing via env vars --- README.md | 13 ++++- .../nfs-subdir-external-provisioner/README.md | 3 ++ .../templates/deployment.yaml | 9 +++- .../values.yaml | 9 ++++ .../provisioner.go | 53 ++++++++++++++++++- deploy/deployment.yaml | 6 +++ 6 files changed, 90 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fa0588e3..9c375e4c 100644 --- a/README.md +++ b/README.md @@ -228,7 +228,18 @@ spec: Note: If you want to change the PROVISIONER_NAME above from `k8s-sigs.io/nfs-subdir-external-provisioner` to something else like `myorg/nfs-storage`, remember to also change the PROVISIONER_NAME in the storage class definition below. -To disable leader election, define an env variable named ENABLE_LEADER_ELECTION and set its value to false. +**Leader election configuration:** + +The provisioner supports leader election to ensure only one replica is active at a time. The following environment variables configure leader election: + +| Env Variable | Default | Description | +|-------------|---------|-------------| +| `ENABLE_LEADER_ELECTION` | `true` | Set to `"false"` to disable leader election entirely. | +| `LEADER_ELECTION_LEASE_DURATION` | `15s` | Time that non-leader candidates wait before attempting to acquire leadership. Must be greater than renew deadline. | +| `LEADER_ELECTION_RENEW_DEADLINE` | `10s` | Time the current leader will retry refreshing leadership before giving up. Must be greater than retry period. | +| `LEADER_ELECTION_RETRY_PERIOD` | `2s` | Interval between leadership renewal attempts. | + +> **Tuning for large clusters:** If you experience leader election timeouts due to etcd compaction or API server latency spikes, increase `LEADER_ELECTION_RENEW_DEADLINE` (e.g., `30s` or `60s`) and adjust `LEADER_ELECTION_RETRY_PERIOD` proportionally. Both `renewDeadline > retryPeriod` and `leaseDuration > renewDeadline` must hold. **Step 5: Deploying your storage class** diff --git a/charts/nfs-subdir-external-provisioner/README.md b/charts/nfs-subdir-external-provisioner/README.md index eb4e41e5..dbbca502 100644 --- a/charts/nfs-subdir-external-provisioner/README.md +++ b/charts/nfs-subdir-external-provisioner/README.md @@ -68,6 +68,9 @@ The following tables lists the configurable parameters of this chart and their d | `storageClass.volumeBindingMode` | Set volume binding mode for Storage Class | `Immediate` | | `storageClass.annotations` | Set additional annotations for the StorageClass | `{}` | | `leaderElection.enabled` | Enables or disables leader election | `true` | +| `leaderElection.leaseDuration` | Leader election lease duration | `15s` | +| `leaderElection.renewDeadline` | Leader election renew deadline | `10s` | +| `leaderElection.retryPeriod` | Leader election retry period | `2s` | | `nfs.server` | Hostname of the NFS server (required) | null (ip or hostname) | | `nfs.path` | Basepath of the mount point to be used | `/nfs-storage` | | `nfs.mountOptions` | Mount options (e.g. 'nfsvers=3') | null | diff --git a/charts/nfs-subdir-external-provisioner/templates/deployment.yaml b/charts/nfs-subdir-external-provisioner/templates/deployment.yaml index 9efccbca..9a70dbea 100644 --- a/charts/nfs-subdir-external-provisioner/templates/deployment.yaml +++ b/charts/nfs-subdir-external-provisioner/templates/deployment.yaml @@ -64,7 +64,14 @@ spec: value: {{ .Values.nfs.defaultUid }} - name: NFS_DEFAULT_GID value: {{ .Values.nfs.defaultGid }} - {{- if eq .Values.leaderElection.enabled false }} + {{- if ne .Values.leaderElection.enabled false }} + - name: LEADER_ELECTION_LEASE_DURATION + value: {{ .Values.leaderElection.leaseDuration | quote }} + - name: LEADER_ELECTION_RENEW_DEADLINE + value: {{ .Values.leaderElection.renewDeadline | quote }} + - name: LEADER_ELECTION_RETRY_PERIOD + value: {{ .Values.leaderElection.retryPeriod | quote }} + {{- else }} - name: ENABLE_LEADER_ELECTION value: "false" {{- end }} diff --git a/charts/nfs-subdir-external-provisioner/values.yaml b/charts/nfs-subdir-external-provisioner/values.yaml index 7d37ba87..fb52c35c 100644 --- a/charts/nfs-subdir-external-provisioner/values.yaml +++ b/charts/nfs-subdir-external-provisioner/values.yaml @@ -64,6 +64,15 @@ leaderElection: # When set to false leader election will be disabled enabled: true + # Leader election lease duration. Must be greater than renewDeadline. + leaseDuration: 15s + + # Leader election renew deadline. Must be greater than retryPeriod. + renewDeadline: 10s + + # Leader election retry period. + retryPeriod: 2s + ## For RBAC support: rbac: # Specifies whether RBAC resources should be created diff --git a/cmd/nfs-subdir-external-provisioner/provisioner.go b/cmd/nfs-subdir-external-provisioner/provisioner.go index 02ec6ef9..96d06b78 100644 --- a/cmd/nfs-subdir-external-provisioner/provisioner.go +++ b/cmd/nfs-subdir-external-provisioner/provisioner.go @@ -26,6 +26,7 @@ import ( "regexp" "strconv" "strings" + "time" "github.com/golang/glog" v1 "k8s.io/api/core/v1" @@ -347,6 +348,56 @@ func main() { } } + options := []func(*controller.ProvisionController) error{ + controller.LeaderElection(leaderElection), + } + + if leaderElection { + leaseDuration := controller.DefaultLeaseDuration + renewDeadline := controller.DefaultRenewDeadline + retryPeriod := controller.DefaultRetryPeriod + + if v := os.Getenv("LEADER_ELECTION_LEASE_DURATION"); v != "" { + d, err := time.ParseDuration(v) + if err != nil { + glog.Fatalf("Unable to parse LEADER_ELECTION_LEASE_DURATION env var: %v", err) + } + leaseDuration = d + } + if v := os.Getenv("LEADER_ELECTION_RENEW_DEADLINE"); v != "" { + d, err := time.ParseDuration(v) + if err != nil { + glog.Fatalf("Unable to parse LEADER_ELECTION_RENEW_DEADLINE env var: %v", err) + } + renewDeadline = d + } + if v := os.Getenv("LEADER_ELECTION_RETRY_PERIOD"); v != "" { + d, err := time.ParseDuration(v) + if err != nil { + glog.Fatalf("Unable to parse LEADER_ELECTION_RETRY_PERIOD env var: %v", err) + } + retryPeriod = d + } + + options = append(options, + controller.LeaseDuration(leaseDuration), + controller.RenewDeadline(renewDeadline), + controller.RetryPeriod(retryPeriod), + ) + + if leaseDuration <= renewDeadline { + glog.Fatalf("LEADER_ELECTION_LEASE_DURATION (%v) must be greater than LEADER_ELECTION_RENEW_DEADLINE (%v)", + leaseDuration, renewDeadline) + } + if renewDeadline <= retryPeriod { + glog.Fatalf("LEADER_ELECTION_RENEW_DEADLINE (%v) must be greater than LEADER_ELECTION_RETRY_PERIOD (%v)", + renewDeadline, retryPeriod) + } + + glog.Infof("leader election: leaseDuration=%v renewDeadline=%v retryPeriod=%v", + leaseDuration, renewDeadline, retryPeriod) + } + clientNFSProvisioner := &nfsProvisioner{ client: clientset, server: server, @@ -361,7 +412,7 @@ func main() { provisionerName, clientNFSProvisioner, serverVersion.GitVersion, - controller.LeaderElection(leaderElection), + options..., ) // Never stops. pc.Run(context.Background()) diff --git a/deploy/deployment.yaml b/deploy/deployment.yaml index 050aa474..da24e102 100644 --- a/deploy/deployment.yaml +++ b/deploy/deployment.yaml @@ -32,6 +32,12 @@ spec: value: 10.3.243.101 - name: NFS_PATH value: /ifs/kubernetes + - name: LEADER_ELECTION_LEASE_DURATION + value: "15s" + - name: LEADER_ELECTION_RENEW_DEADLINE + value: "10s" + - name: LEADER_ELECTION_RETRY_PERIOD + value: "2s" volumes: - name: nfs-client-root nfs: