Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f6887b4
Added support for CSI secret provider
ZanisO Dec 24, 2024
6d1d017
Don't reload existing config
ZanisO Jan 2, 2025
3c39406
Added capability to use OnChangeAnnotation and TypeAutoAnnotation
ZanisO Jan 9, 2025
75f9a23
Added tests
ZanisO Jan 14, 2025
717291f
Added check to see if CSI CRDs are installed before running controller
ZanisO Jan 19, 2025
69b0d93
Added controller tests
ZanisO Jan 20, 2025
570649e
Minor improvements to tests and handlers
ZanisO Feb 5, 2025
e7e095c
Fixed tests
ZanisO Feb 5, 2025
cdaed4a
Merge branch 'master' into add-csi-support
msafwankarim Nov 24, 2025
4f8b22e
resolved comments
msafwankarim Nov 24, 2025
1725f17
fixed namespace behavior issue
msafwankarim Nov 24, 2025
779c3b0
Merge branch 'master' into add-csi-support
msafwankarim Dec 26, 2025
eb96bab
Merge branch 'add-csi-support' into feature/add-csi-support
faizanahmad055 Dec 30, 2025
c9cab4f
Update chart for CSI driver
faizanahmad055 Jan 3, 2026
109971d
prioritize named resource
msafwankarim Dec 27, 2025
9c8c511
Update dependencies and fix shouldReload issue
faizanahmad055 Jan 3, 2026
85f1c13
Add CSI integration in rbac
faizanahmad055 Jan 3, 2026
0f1d02e
Readme update and code refactor
faizanahmad055 Jan 4, 2026
7e9d571
Readme update and change SHA1 to SHA512
faizanahmad055 Jan 4, 2026
4b90335
Readme update and fix tests
faizanahmad055 Jan 4, 2026
eb38bf7
Fix linting errors
faizanahmad055 Jan 4, 2026
e1db875
Fix failing tests
faizanahmad055 Jan 6, 2026
8b64c9b
Fix failing SHA test
faizanahmad055 Jan 6, 2026
b0ca635
Add file filtering in UBI docker image
faizanahmad055 Jan 7, 2026
703319e
Improve file filtering in UBI docker image
faizanahmad055 Jan 7, 2026
6fd7c82
Update filtering in UBI image
faizanahmad055 Jan 7, 2026
157cf0f
Remove SHA1 changes
faizanahmad055 Jan 7, 2026
8373b1e
Merge branch 'master' of github.com:stakater/Reloader into csi-suppor…
faizanahmad055 Jan 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 64 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

## 🔁 What is Reloader?

Reloader is a Kubernetes controller that automatically triggers rollouts of workloads (like Deployments, StatefulSets, and more) whenever referenced `Secrets` or `ConfigMaps` are updated.
Reloader is a Kubernetes controller that automatically triggers rollouts of workloads (like Deployments, StatefulSets, and more) whenever referenced `Secrets`, `ConfigMaps` or **optionally CSI-mounted secrets** are updated.

In a traditional Kubernetes setup, updating a `Secret` or `ConfigMap` does not automatically restart or redeploy your workloads. This can lead to stale configurations running in production, especially when dealing with dynamic values like credentials, feature flags, or environment configs.

Expand Down Expand Up @@ -169,9 +169,11 @@ metadata:

This instructs Reloader to skip all reload logic for that resource across all workloads.

### 4. ⚙️ Workload-Specific Rollout Strategy
### 4. ⚙️ Workload-Specific Rollout Strategy (Argo Rollouts Only)

By default, Reloader uses the **rollout** strategy — it updates the pod template to trigger a new rollout. This works well in most cases, but it can cause problems if you're using GitOps tools like ArgoCD, which detect this as configuration drift.
Note: This is only applicable when using [Argo Rollouts](https://argoproj.github.io/argo-rollouts/). It is ignored for standard Kubernetes `Deployments`, `StatefulSets`, or `DaemonSets`. To use this feature, Argo Rollouts support must be enabled in Reloader (for example via --is-argo-rollouts=true).

By default, Reloader triggers the Argo Rollout controller to perform a standard rollout by updating the pod template. This works well in most cases, however, because this modifies the workload spec, GitOps tools like ArgoCD will detect this as "Configuration Drift" and mark your application as OutOfSync.

To avoid that, you can switch to the **restart** strategy, which simply restarts the pod without changing the pod template.

Expand All @@ -192,6 +194,8 @@ metadata:
1. You want a quick restart without changing the workload spec
1. Your platform restricts metadata changes

This setting affects Argo Rollouts behavior, not Argo CD sync settings.

### 5. ❗ Annotation Behavior Rules & Compatibility

- `reloader.stakater.com/auto` and `reloader.stakater.com/search` **cannot be used together** — the `auto` annotation takes precedence.
Expand Down Expand Up @@ -239,6 +243,61 @@ This feature allows you to pause rollouts for a deployment for a specified durat
1. ✅ Your deployment references multiple ConfigMaps or Secrets that may be updated at the same time.
1. ✅ You want to minimize unnecessary rollouts and reduce downtime caused by back-to-back configuration changes.

### 8. 🔐 CSI Secret Provider Support

Reloader supports the [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/), which allows mounting secrets from external secret stores (like AWS Secrets Manager, Azure Key Vault, HashiCorp Vault) directly into pods.
Unlike Kubernetes Secret objects, CSI-mounted secrets do not always trigger native Kubernetes update events. Reloader solves this by watching CSI status resources and restarting affected workloads when mounted secret versions change.

#### How it works

When secret rotation is enabled, the Secrets Store CSI Driver updates a Kubernetes resource called: `SecretProviderClassPodStatus`

This resource reflects the currently mounted secret versions for a pod.
Reloader watches these updates and triggers a rollout when a change is detected.

#### Prerequisites

- Secrets Store CSI Driver must be installed in your cluster
- Secret rotation enabled in the CSI driver.
- Enable CSI integration in Reloader: `--enable-csi-integration=true`

#### Annotations for CSI-mounted Secrets

| Annotation | Description |
|------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| `reloader.stakater.com/auto: "true"` | Global Discovery: Automatically discovers and reloads the workload when any mounted ConfigMap or Secret is updated. |
| `secretproviderclass.reloader.stakater.com/auto: 'true'` | CSI Discovery: Specifically watches for updates to all SecretProviderClasses used by the workload (CSI driver integration). |
| `secretproviderclass.reloader.stakater.com/reload: "my-secretproviderclass"` | Targeted Reload: Only reloads the workload when the specifically named SecretProviderClass(es) are updated. |

Reloader monitors changes at the **per-secret level** by watching the `SecretProviderClassPodStatus`. Make sure each secret you want to monitor is properly defined with a `secretKey` in your `SecretProviderClass`:

```yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: vault-reloader-demo
namespace: test
spec:
provider: vault
parameters:
vaultAddress: "http://vault.vault.svc:8200"
vaultSkipTLSVerify: "true"
roleName: "demo-role"
objects: |
- objectName: "password"
secretPath: "secret/data/reloader-demo"
secretKey: "password"
```

***Important***: Reloader tracks changes to individual secrets (identified by `secretKey`). If your SecretProviderClass doesn't specify `secretKey` for each object, Reloader may not detect updates correctly.

#### Notes & Limitations

Reloader reacts to CSI status changes, not direct updates to external secret stores
Secret rotation must be enabled in the CSI driver for updates to be detected
CSI limitations (such as `subPath` mounts) still apply and may require pod restarts
If secrets are synced to Kubernetes Secret objects, standard Reloader behavior applies and CSI support may not be required

## 🚀 Installation

### 1. 📦 Helm
Expand Down Expand Up @@ -430,7 +489,7 @@ PRs are welcome. In general, we follow the "fork-and-pull" Git workflow:

## Release Processes

_Repository GitHub releases_: As requested by the community in [issue 685](https://github.com/stakater/Reloader/issues/685), Reloader is now based on a manual release process. Releases are no longer done on every merged PR to the main branch, but manually on request.
*Repository GitHub releases*: As requested by the community in [issue 685](https://github.com/stakater/Reloader/issues/685), Reloader is now based on a manual release process. Releases are no longer done on every merged PR to the main branch, but manually on request.

To make a GitHub release:

Expand All @@ -443,7 +502,7 @@ To make a GitHub release:
1. Code owners create another branch from `master` and bump the helm chart version as well as Reloader image version.
- Code owners create a PR with `release/helm-chart` label, example: [PR-846](https://github.com/stakater/Reloader/pull/846)

_Repository git tagging_: Push to the main branch will create a merge-image and merge-tag named `merge-${{ github.event.number }}`, for example `merge-800` when pull request number 800 is merged.
*Repository git tagging*: Push to the main branch will create a merge-image and merge-tag named `merge-${{ github.event.number }}`, for example `merge-800` when pull request number 800 is merged.

## Changelog

Expand Down
11 changes: 11 additions & 0 deletions deployments/kubernetes/chart/reloader/templates/clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ rules:
- create
- get
- update
{{- end}}
{{- if .Values.reloader.enableCSIIntegration }}
- apiGroups:
- "secrets-store.csi.x-k8s.io"
resources:
- secretproviderclasspodstatuses
- secretproviderclasses
verbs:
- list
- get
- watch
{{- end}}
- apiGroups:
- ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ spec:
{{- . | toYaml | nindent 10 }}
{{- end }}
{{- end }}
{{- if or (.Values.reloader.logFormat) (.Values.reloader.logLevel) (.Values.reloader.ignoreSecrets) (.Values.reloader.ignoreNamespaces) (include "reloader-namespaceSelector" .) (.Values.reloader.resourceLabelSelector) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (eq .Values.reloader.reloadOnDelete true) (ne .Values.reloader.reloadStrategy "default") (.Values.reloader.enableHA) (.Values.reloader.autoReloadAll) (.Values.reloader.ignoreJobs) (.Values.reloader.ignoreCronJobs)}}
{{- if or (.Values.reloader.logFormat) (.Values.reloader.logLevel) (.Values.reloader.ignoreSecrets) (.Values.reloader.ignoreNamespaces) (include "reloader-namespaceSelector" .) (.Values.reloader.resourceLabelSelector) (.Values.reloader.ignoreConfigMaps) (.Values.reloader.custom_annotations) (eq .Values.reloader.isArgoRollouts true) (eq .Values.reloader.reloadOnCreate true) (eq .Values.reloader.reloadOnDelete true) (ne .Values.reloader.reloadStrategy "default") (.Values.reloader.enableHA) (.Values.reloader.autoReloadAll) (.Values.reloader.ignoreJobs) (.Values.reloader.ignoreCronJobs) (.Values.reloader.enableCSIIntegration)}}
args:
{{- if .Values.reloader.logFormat }}
- "--log-format={{ .Values.reloader.logFormat }}"
Expand Down Expand Up @@ -246,6 +246,9 @@ spec:
- "--pprof-addr={{ .Values.reloader.pprofAddr }}"
{{- end }}
{{- end }}
{{- if .Values.reloader.enableCSIIntegration }}
- "--enable-csi-integration=true"
{{- end }}
{{- if .Values.reloader.custom_annotations }}
{{- if .Values.reloader.custom_annotations.configmap }}
- "--configmap-annotation"
Expand Down
11 changes: 11 additions & 0 deletions deployments/kubernetes/chart/reloader/templates/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ rules:
- create
- get
- update
{{- end}}
{{- if .Values.reloader.enableCSIIntegration }}
- apiGroups:
- "secrets-store.csi.x-k8s.io"
resources:
- secretproviderclasspodstatuses
- secretproviderclasses
verbs:
- list
- get
- watch
{{- end}}
- apiGroups:
- ""
Expand Down
1 change: 1 addition & 0 deletions deployments/kubernetes/chart/reloader/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ reloader:
enableHA: false
# Set to true to enable pprof for profiling
enablePProf: false
enableCSIIntegration: false
# Address to start pprof server on. Default is ":6060"
pprofAddr: ":6060"
# Set to true if you have a pod security policy that enforces readOnlyRootFilesystem
Expand Down
14 changes: 7 additions & 7 deletions docs/Reloader-vs-ConfigmapController.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

Reloader is inspired from [`configmapcontroller`](https://github.com/fabric8io/configmapcontroller) but there are many ways in which it differs from `configmapcontroller`. Below is the small comparison between these two controllers.

| Reloader | ConfigMap |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Reloader can watch both `Secrets` and `ConfigMaps`. | `configmapcontroller` can only watch changes in `ConfigMaps`. It cannot detect changes in other resources like `Secrets`. |
| Reloader can perform rolling upgrades on `deployments` as well as on `statefulsets` and `daemonsets` | `configmapcontroller` can only perform rolling upgrades on `deployments`. It currently does not support rolling upgrades on `statefulsets` and `daemonsets` |
| Reloader provides both unit test cases and end to end integration test cases for future updates. So one can make sure that new changes do not break any old functionality. | Currently there are not any unit test cases or end to end integration test cases in `configmap-controller`. It add difficulties for any additional updates in `configmap-controller` and one can not know for sure whether new changes breaks any old functionality or not. |
| Reloader uses SHA1 to encode the change in `ConfigMap` or `Secret`. It then saves the SHA1 value in `STAKATER_FOO_CONFIGMAP` or `STAKATER_FOO_SECRET` environment variable depending upon where the change has happened. The use of SHA1 provides a concise 40 characters encoded value that is very less prone to collision. | `configmap-controller` uses `FABRICB_FOO_REVISION` environment variable to store any change in `ConfigMap` controller. It does not encode it or convert it in suitable hash value to avoid data pollution in deployment. |
| Reloader allows you to customize your own annotation (for both `Secrets` and `ConfigMaps`) using command line flags | `configmap-controller` restricts you to only their provided annotation |
| Reloader | ConfigMap |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Reloader can watch both `Secrets` and `ConfigMaps`. | `configmapcontroller` can only watch changes in `ConfigMaps`. It cannot detect changes in other resources like `Secrets`. |
| Reloader can perform rolling upgrades on `deployments` as well as on `statefulsets` and `daemonsets` | `configmapcontroller` can only perform rolling upgrades on `deployments`. It currently does not support rolling upgrades on `statefulsets` and `daemonsets` |
| Reloader provides both unit test cases and end to end integration test cases for future updates. So one can make sure that new changes do not break any old functionality. | Currently there are not any unit test cases or end to end integration test cases in `configmap-controller`. It adds difficulties for any additional updates in `configmap-controller` and one can not know for sure whether new changes breaks any old functionality or not. |
| Reloader uses SHA1 to encode the change in `ConfigMap` or `Secret`. It then saves the SHA1 value in `STAKATER_FOO_CONFIGMAP` or `STAKATER_FOO_SECRET` environment variable depending upon where the change has happened. The use of SHA1 provides a concise 40 characters encoded value that is very less prone to collision. | `configmap-controller` uses `FABRICB_FOO_REVISION` environment variable to store any change in `ConfigMap` controller. It does not encode it or convert it in suitable hash value to avoid data pollution in deployment. |
| Reloader allows you to customize your own annotation (for both `Secrets` and `ConfigMaps`) using command line flags | `configmap-controller` restricts you to only their provided annotation |
2 changes: 1 addition & 1 deletion docs/Reloader-vs-k8s-trigger-controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Reloader and k8s-trigger-controller are both built for same purpose. So there ar

- Both controllers support change detection in `ConfigMaps` and `Secrets`
- Both controllers support deployment `rollout`
- Both controllers use SHA1 for hashing
- Reloader controller use SHA1 for hashing
- Both controllers have end to end as well as unit test cases.

## Differences
Expand Down
Loading
Loading