Configuration reference
Helm values
Core
| Value | Default | Description |
|---|---|---|
replicaCount | 1 | Controller replicas. Set to 2 to remove the window during an upgrade where evictions bypass the webhook. |
image.repository | ghcr.io/stonal-tech/graceful-drain-controller | Controller image. |
image.tag | "" | Defaults to the chart’s appVersion. |
image.pullPolicy | IfNotPresent | |
imagePullSecrets | [] | Required while the GHCR package is private. |
resources | 50m CPU / 128Mi requested, 256Mi limit | |
logLevel | info | debug, info, warn, error. JSON output. |
port | 8081 | Health probe port (/healthz, /readyz). |
webhookPort | 9443 | HTTPS port for the admission webhook. |
nodeSelector / tolerations / affinity | {} / [] / {} | Standard scheduling controls. |
Behaviour
| Value | Default | Description |
|---|---|---|
enabledAnnotation | "" | If set, only Deployments carrying this annotation set to "true" are protected. Empty means every replicas: 1 Deployment is. |
rolloutTimeout | 10m | How long the webhook keeps denying before it gives up and lets the drain proceed. |
requeueInterval | 10s | How often the reconciler re-checks a rollout in progress. |
rolloutTimeout is the important one. It must be longer than a worst-case pod start (image pull on a cold node, slow readiness probe) and shorter than your autoscaler’s own drain ceiling — Karpenter’s terminationGracePeriod, Cluster Autoscaler’s --max-graceful-termination-sec. Sitting between the two means the controller gives up on its own terms, emitting a GracefulDrainTimeout event you can alert on, rather than being cut off mid-flight by a forceful pod deletion.
Webhook
| Value | Default | Description |
|---|---|---|
webhook.failurePolicy | Ignore | Ignore: an unreachable controller means evictions proceed normally. Fail: an unreachable controller blocks every eviction in scope. |
webhook.timeoutSeconds | 5 | How long the API server waits for the webhook. |
webhook.namespaceSelector | excludes kube-system | Which namespaces the webhook is called for. |
Think hard before setting
failurePolicy: Fail. It puts this controller in the critical path of every eviction in every selected namespace — including the evictions the cluster needs in order to recover.Ignoredegrades to “as if not installed”;Faildegrades to “nothing can be evicted”. Two replicas is the better way to buy availability.
The default namespaceSelector excludes kube-system, which is also where the chart expects to be installed. That is deliberate: it keeps the controller out of the control plane’s way, and stops it from intercepting the eviction of its own pod.
TLS
| Value | Default | Description |
|---|---|---|
certManager.enabled | true | Create a self-signed cert-manager Issuer + Certificate and let cert-manager inject the CA bundle. |
tls.existingSecret | "" | Required when certManager.enabled is false. A TLS secret in the release namespace with tls.crt / tls.key. |
tls.caBundle | "" | Base64-encoded CA for the API server to trust. Leave empty if something else injects it. |
See bring your own certificate.
Command-line flags
Every flag has an environment variable equivalent. The Helm chart sets them as flags.
| Flag | Environment variable | Default | Description |
|---|---|---|---|
--port | PORT | 8081 | Health probe port |
--webhook-port | GRACEFUL_DRAIN_WEBHOOK_PORT | 9443 | Webhook HTTPS port |
--cert-dir | GRACEFUL_DRAIN_CERT_DIR | "" | Directory holding tls.crt / tls.key |
--log-level | GRACEFUL_DRAIN_LOG_LEVEL | info | debug, info, warn, error |
--enabled-annotation | GRACEFUL_DRAIN_ENABLED_ANNOTATION | "" | Restrict to Deployments with this annotation |
--requeue-interval | GRACEFUL_DRAIN_REQUEUE_INTERVAL | 5s | Rollout re-check interval |
--rollout-timeout | GRACEFUL_DRAIN_ROLLOUT_TIMEOUT | 5m | Give-up deadline |
The binary’s defaults for
--requeue-interval(5s) and--rollout-timeout(5m) differ from the chart’s (10sand10m). The chart values are the ones that apply to a Helm install.
Annotations
| Annotation | Set on | Set by | Meaning |
|---|---|---|---|
graceful-drain.stonal.com/restarted-at | Deployment metadata | the webhook | A graceful drain is in progress. RFC 3339 timestamp, used for the timeout check. Removed by the reconciler when the rollout completes or times out. |
kubectl.kubernetes.io/restartedAt | Deployment pod template | the reconciler | The standard kubectl rollout restart annotation. Patching it is what starts the rollout. |
| (your key) | Deployment metadata | you | Opt-in marker, when enabledAnnotation is configured. |
RBAC
The controller runs with a ClusterRole granting:
| Resource | Verbs | Why |
|---|---|---|
pods | get, list, watch | Resolve the pod named in the eviction |
replicasets | get, list, watch | Walk pod → ReplicaSet → Deployment |
deployments | get, list, watch, patch | Read rollout status, set annotations |
events | create, patch | Report progress on the Deployment |
leases | get, create, update | Leader election |
Note what is absent: no write access to nodes, no delete on pods, no cluster-admin. The controller never removes a workload — it only ever asks the Deployment controller to roll one.