mirror of
https://github.com/lukaszraczylo/kubemirror.git
synced 2026-06-27 04:53:11 +00:00
docs: fix flag defaults, drop phantom annotations, add chart README
Correct two wrong CLI flag defaults (leader-elect, verify-source-freshness) and add missing flags/Helm values. Remove documented-but-nonexistent annotations (excluded-namespaces, namespace-pattern) that silently did nothing, document the real exclude/paused and glob targeting, fix the mirror ownership-check example, and add the missing charts/kubemirror/README.md that README linked to.
This commit is contained in:
@@ -271,6 +271,34 @@ metadata:
|
||||
kubemirror.raczylo.com/allow-mirrors: "true"
|
||||
```
|
||||
|
||||
### Pause or Exclude a Resource
|
||||
|
||||
Two annotations control opting a source out of mirroring:
|
||||
|
||||
- `kubemirror.raczylo.com/exclude: "true"` — opt the resource out entirely. It is
|
||||
not mirrored, and any mirrors it previously created are **deleted**.
|
||||
- `kubemirror.raczylo.com/paused: "true"` — **freeze** the resource. Existing
|
||||
mirrors are left exactly as they are (no updates, no cleanup) until the
|
||||
annotation is removed. Useful during maintenance when you want mirrors to
|
||||
persist but stop tracking source changes.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: shared-credentials
|
||||
namespace: default
|
||||
labels:
|
||||
kubemirror.raczylo.com/enabled: "true"
|
||||
annotations:
|
||||
kubemirror.raczylo.com/sync: "true"
|
||||
kubemirror.raczylo.com/target-namespaces: "all"
|
||||
# Freeze mirrors in place (or use /exclude to remove them):
|
||||
kubemirror.raczylo.com/paused: "true"
|
||||
data:
|
||||
password: c2VjcmV0
|
||||
```
|
||||
|
||||
### Mirror Custom Resources (CRDs)
|
||||
|
||||
KubeMirror works with any custom resource:
|
||||
@@ -555,12 +583,17 @@ Complete configuration reference:
|
||||
| **Resource Discovery** | | | |
|
||||
| `controller.resourceTypes` | Explicit resource type list (empty = auto-discover all) | `[]` | `["Secret.v1", "ConfigMap.v1", "Ingress.v1.networking.k8s.io"]` |
|
||||
| `controller.discoveryInterval` | Rediscovery interval for auto-discovery mode | `5m` | `10m`, `1h` |
|
||||
| `controller.lazyWatcherInit` | Only watch resource types in use; lowers memory | `false` | `true`, `false` |
|
||||
| `controller.watcherScanInterval` | Scan interval for new types in lazy mode | `5m` | `10m` |
|
||||
| **Performance & Limits** | | | |
|
||||
| `controller.leaderElect` | Enable leader election for HA | `true` | `true`, `false` |
|
||||
| `controller.leaderElectionID` | Leader election lease name | `kubemirror-controller-leader` | |
|
||||
| `controller.maxTargets` | Maximum mirrors per source resource | `100` | `50`, `200`, `500` |
|
||||
| `controller.workerThreads` | Concurrent reconciliation workers | `5` | `10`, `20` |
|
||||
| `controller.rateLimitQPS` | API rate limit (queries per second) | `50.0` | `100.0`, `200.0` |
|
||||
| `controller.rateLimitBurst` | API burst allowance | `100` | `200`, `500` |
|
||||
| `controller.resyncPeriod` | Full cache resync period | `10m` | `30m` |
|
||||
| `controller.verifySourceFreshness` | Verify cache against a direct API read before mirroring | `false` | `true`, `false` |
|
||||
| **Namespace Filtering** | | | |
|
||||
| `controller.excludedNamespaces` | Comma-separated namespace exclusion list | `""` | `kube-system,kube-public,kube-node-lease` |
|
||||
| `controller.includedNamespaces` | Comma-separated namespace inclusion list | `""` | `app-*,prod-*` |
|
||||
@@ -579,15 +612,19 @@ When running the binary directly:
|
||||
|
||||
**Resource Discovery:**
|
||||
- `--resource-types string` - Comma-separated list (e.g., `Secret.v1,ConfigMap.v1,Ingress.v1.networking.k8s.io`)
|
||||
- `--discovery-interval duration` - Rediscovery interval (default: 5m)
|
||||
- `--discovery-interval duration` - Rediscovery interval for auto-discovery mode (default: 5m)
|
||||
- `--lazy-watcher-init` - Only create watchers for resource types actually in use; lowers memory (default: false)
|
||||
- `--watcher-scan-interval duration` - Scan interval for new types in lazy mode (default: 5m)
|
||||
|
||||
**Performance & Limits:**
|
||||
- `--leader-elect` - Enable leader election (default: true)
|
||||
- `--leader-elect` - Enable leader election (default: false)
|
||||
- `--leader-election-id string` - Leader election lease name (default: kubemirror-controller-leader)
|
||||
- `--max-targets int` - Max mirrors per source (default: 100)
|
||||
- `--worker-threads int` - Concurrent workers (default: 5)
|
||||
- `--rate-limit-qps float32` - API rate limit (default: 50.0)
|
||||
- `--rate-limit-burst int` - API burst limit (default: 100)
|
||||
- `--verify-source-freshness` - Verify cache freshness before mirroring (default: false)
|
||||
- `--resync-period duration` - Full cache resync period (default: 10m)
|
||||
- `--verify-source-freshness` - Verify cache against a direct API read before mirroring (default: true)
|
||||
|
||||
**Namespace Filtering:**
|
||||
- `--excluded-namespaces string` - Comma-separated exclusion list
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# kubemirror Helm chart
|
||||
|
||||
Deploys the [kubemirror](https://github.com/lukaszraczylo/kubemirror) controller,
|
||||
which mirrors Kubernetes resources (Secrets, ConfigMaps, and other types) across
|
||||
namespaces.
|
||||
|
||||
- Chart version: `0.1.0`
|
||||
- App version: `0.1.0`
|
||||
- Image: `ghcr.io/lukaszraczylo/kubemirror`
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
helm install kubemirror ./charts/kubemirror -n kubemirror --create-namespace
|
||||
```
|
||||
|
||||
With a values override:
|
||||
|
||||
```bash
|
||||
helm install kubemirror ./charts/kubemirror -n kubemirror --create-namespace \
|
||||
-f my-values.yaml
|
||||
```
|
||||
|
||||
## Uninstall
|
||||
|
||||
```bash
|
||||
helm uninstall kubemirror -n kubemirror
|
||||
```
|
||||
|
||||
## What it creates
|
||||
|
||||
A single-replica `Deployment`, a `ServiceAccount`, a cluster-scoped `ClusterRole`
|
||||
+ `ClusterRoleBinding` (the controller watches resources across all namespaces),
|
||||
and a `Service` exposing the metrics (`8080`) and health (`8081`) ports. The
|
||||
container runs as non-root (uid `65532`) with a read-only root filesystem and all
|
||||
Linux capabilities dropped.
|
||||
|
||||
## Values
|
||||
|
||||
Defaults are taken from [`values.yaml`](values.yaml).
|
||||
|
||||
| Key | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `replicaCount` | `1` | Number of controller replicas. |
|
||||
| `image.repository` | `ghcr.io/lukaszraczylo/kubemirror` | Controller image. |
|
||||
| `image.tag` | `"0.1.0"` | Image tag (falls back to chart `appVersion` if empty). |
|
||||
| `image.pullPolicy` | `IfNotPresent` | Image pull policy. |
|
||||
| `serviceAccount.create` | `true` | Create a ServiceAccount. |
|
||||
| `serviceAccount.name` | `""` | Override the generated ServiceAccount name. |
|
||||
| `controller.metricsBindAddress` | `":8080"` | `--metrics-bind-address`. |
|
||||
| `controller.healthProbeBindAddress` | `":8081"` | `--health-probe-bind-address`. |
|
||||
| `controller.leaderElect` | `true` | Enable leader election (`--leader-elect`). |
|
||||
| `controller.leaderElectionID` | `"kubemirror-controller-leader"` | Lease name (`--leader-election-id`). |
|
||||
| `controller.resourceTypes` | `[]` | Resource types to mirror (`--resource-types`). Empty enables auto-discovery. |
|
||||
| `controller.discoveryInterval` | `"5m"` | Auto-discovery interval (`--discovery-interval`). |
|
||||
| `controller.resyncPeriod` | `"10m"` | Cache resync period (`--resync-period`). |
|
||||
| `controller.maxTargets` | `100` | Max target namespaces per resource (`--max-targets`). |
|
||||
| `controller.workerThreads` | `5` | Concurrent reconcile workers (`--worker-threads`). |
|
||||
| `controller.rateLimitQPS` | `50.0` | API QPS limit (`--rate-limit-qps`). |
|
||||
| `controller.rateLimitBurst` | `100` | API burst limit (`--rate-limit-burst`). |
|
||||
| `controller.verifySourceFreshness` | `false` | Verify cache against a direct API read (`--verify-source-freshness`). |
|
||||
| `controller.lazyWatcherInit` | `false` | Only watch resource types actually in use (`--lazy-watcher-init`). Lowers memory; recommended for production. |
|
||||
| `controller.watcherScanInterval` | `"5m"` | Scan interval for new types in lazy mode (`--watcher-scan-interval`). |
|
||||
| `controller.excludedNamespaces` | `""` | Comma-separated namespaces never mirrored to (`--excluded-namespaces`). |
|
||||
| `controller.includedNamespaces` | `""` | Comma-separated namespace patterns to include (`--included-namespaces`). |
|
||||
| `service.type` | `ClusterIP` | Service type. |
|
||||
| `service.metricsPort` | `8080` | Metrics port. |
|
||||
| `service.healthPort` | `8081` | Health-probe port. |
|
||||
| `resources.requests` | `100m` CPU / `128Mi` | Container requests. |
|
||||
| `resources.limits` | `500m` CPU / `512Mi` | Container limits. |
|
||||
| `nodeSelector` / `tolerations` / `affinity` | `{}` / `[]` / `{}` | Standard scheduling controls. |
|
||||
| `priorityClassName` | `""` | Pod priority class. |
|
||||
|
||||
> **Memory tip:** setting `controller.resourceTypes` to the exact types you mirror
|
||||
> (e.g. `["Secret.v1", "ConfigMap.v1"]`), or enabling `controller.lazyWatcherInit`,
|
||||
> avoids creating watchers for unused resource types and cuts memory use
|
||||
> substantially versus full auto-discovery.
|
||||
|
||||
## Usage
|
||||
|
||||
After install, mark a source resource for mirroring and opt a target namespace
|
||||
in. See the [project README](../../README.md) and [examples](../../examples/) for
|
||||
the full annotation/label reference and worked scenarios.
|
||||
+42
-26
@@ -113,13 +113,15 @@ kubectl get middleware headers -n namespace-3
|
||||
Verify that mirrored resources have the correct ownership labels:
|
||||
|
||||
```bash
|
||||
# Check labels on a mirrored secret
|
||||
kubectl get secret shared-credentials -n namespace-3 -o yaml | grep -A 5 labels
|
||||
# Inspect a mirrored secret's metadata
|
||||
kubectl get secret shared-credentials -n namespace-3 -o yaml
|
||||
|
||||
# Should include:
|
||||
# kubemirror.raczylo.com/mirrored: "true"
|
||||
# kubemirror.raczylo.com/source-namespace: namespace-1
|
||||
# kubemirror.raczylo.com/source-name: shared-credentials
|
||||
# Labels should include:
|
||||
# kubemirror.raczylo.com/managed-by: kubemirror
|
||||
# kubemirror.raczylo.com/mirror: "true"
|
||||
# Annotations should include:
|
||||
# kubemirror.raczylo.com/source-namespace: namespace-1
|
||||
# kubemirror.raczylo.com/source-name: shared-credentials
|
||||
```
|
||||
|
||||
## Testing Update Propagation
|
||||
@@ -213,26 +215,12 @@ kubectl get pods -n kubemirror-system
|
||||
|
||||
## Advanced Examples
|
||||
|
||||
### Mirror to All Except Specific Namespaces
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: almost-all
|
||||
namespace: namespace-1
|
||||
annotations:
|
||||
kubemirror.raczylo.com/sync: "true"
|
||||
kubemirror.raczylo.com/target-namespaces: "all"
|
||||
kubemirror.raczylo.com/excluded-namespaces: "namespace-3"
|
||||
labels:
|
||||
kubemirror.raczylo.com/enabled: "true"
|
||||
data:
|
||||
key: dmFsdWU= # "value" in base64
|
||||
```
|
||||
|
||||
### Pattern-Based Mirroring
|
||||
|
||||
`target-namespaces` accepts glob patterns (`*` and `?`, matched with Go's
|
||||
`filepath.Match`), so you can target a family of namespaces without listing each
|
||||
one. Comma-separate multiple patterns, e.g. `"app-*,prod-*"`.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
@@ -241,14 +229,42 @@ metadata:
|
||||
namespace: namespace-1
|
||||
annotations:
|
||||
kubemirror.raczylo.com/sync: "true"
|
||||
kubemirror.raczylo.com/target-namespaces: "all"
|
||||
kubemirror.raczylo.com/namespace-pattern: "app-.*"
|
||||
# Mirror to every namespace whose name starts with "app-"
|
||||
kubemirror.raczylo.com/target-namespaces: "app-*"
|
||||
labels:
|
||||
kubemirror.raczylo.com/enabled: "true"
|
||||
data:
|
||||
config: "value"
|
||||
```
|
||||
|
||||
> **Note:** Target patterns are include-only; there is no "all except namespace
|
||||
> X" target syntax. For the two real exclusion mechanisms:
|
||||
>
|
||||
> - To stop a single source resource from being mirrored (and tear down any
|
||||
> mirrors it already created), set `kubemirror.raczylo.com/exclude: "true"` on
|
||||
> that resource.
|
||||
> - To stop specific namespaces from ever receiving mirrors cluster-wide, use the
|
||||
> controller's `--excluded-namespaces` flag.
|
||||
|
||||
### Excluding a Specific Resource
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: do-not-mirror
|
||||
namespace: namespace-1
|
||||
annotations:
|
||||
kubemirror.raczylo.com/sync: "true"
|
||||
kubemirror.raczylo.com/target-namespaces: "all"
|
||||
# Opt this resource out: it will not be mirrored even though sync is set.
|
||||
kubemirror.raczylo.com/exclude: "true"
|
||||
labels:
|
||||
kubemirror.raczylo.com/enabled: "true"
|
||||
data:
|
||||
key: dmFsdWU=
|
||||
```
|
||||
|
||||
## ExternalSecrets Integration
|
||||
|
||||
KubeMirror integrates seamlessly with the [ExternalSecrets Operator](https://external-secrets.io/) to distribute secrets from external stores (1Password, Vault, AWS Secrets Manager, etc.) across multiple namespaces.
|
||||
|
||||
Reference in New Issue
Block a user