← All projects
Kubernetes

Replikate

Stable · v1.4.0 Go · BSD-3-Clause · in-cluster controller

A lightweight Kubernetes controller that replicates ConfigMaps and Secrets across namespaces. Annotate a source object and Replikate copies it into every matching namespace — keeping copies in sync on change, cleaning them up on delete, and populating new namespaces automatically.

Language
Go
License
BSD-3-Clause
Runtime
In-cluster controller
Image
amd64 + arm64
Synopsis
annotation
replikate.ubixsys.com/sync: "<selector>"

  "team=web"   # → namespaces matching the label
  ""           # → every namespace
Description

Source changed → every copy is updated. Source or annotation removed → copies are deleted via a finalizer. A new namespace appears that matches → it is populated automatically.

Replikate never overwrites an object it does not manage, and only writes when something actually changed. It's annotation-compatible with AppsCode's config-syncer, and adopts existing copies in place during a cutover rather than deleting and recreating them.

Examples
install
# install into the cluster (image built by CI)
$ make deploy IMAGE_REPO=ghcr.io/ubixsys/replikate \
       IMAGE_TAG=v1.4.0
annotate a ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: shared-config
  annotations:
    replikate.ubixsys.com/sync: "team=web"
data:
  LOG_LEVEL: "info"
label a namespace
# the namespace gets a copy near-instantly
$ kubectl label namespace some-ns team=web
$ kubectl get configmap shared-config -n some-ns
replicate into another cluster
# on the hub: turn on cross-cluster, register each spoke
$ helm upgrade --install replikate charts/replikate \
       -n replikate-system --set crossCluster.enabled=true
$ kubectl -n replikate-system create secret generic green \
       --from-file=kubeconfig=green.kubeconfig
$ kubectl -n replikate-system label secret green \
       replikate.ubixsys.com/cluster-credential=true

# then on a source: repeat a cluster for several namespaces (v1.4+)
    replikate.ubixsys.com/target-clusters: "green:web,green:live,blue:web,blue:live"
Capabilities
Selector or cluster-wide
Target namespaces by label selector, or leave the value empty to reach all of them.
Kept in lockstep
Copies are watched, not left until the next resync — a hand-edited replica is restored near-instantly.
Finalizer cleanup
Delete the source or drop the annotation and every managed copy is removed cleanly.
Auto-populate
A new namespace that matches the selector is filled in without any manual step.
Cross-cluster
Opt-in hub-and-spoke: copy a source into other clusters, and into several namespaces on each, with one annotation.
Conflict-safe migration
Adopts config-syncer copies in place, and refuses to fight another source over a copy.
Configuration

Configuration reference.

Controller flags and the matching Helm values — sensible defaults, tune what you need.

Controller flags
FlagDefaultNotes
-annotation-domainreplikate.ubixsys.comPrimary prefix the controller writes and watches.
-previous-annotation-domainreplikate.brainchurts.comPrior prefix still honored for reads / matching / adoption; copies self-migrate. Set empty to finish the migration.
-exclude-namespaceskube-system,kube-public,kube-node-leaseNever replicate copies into these namespaces.
-leader-electfalseElect a single active replica (the Helm chart turns this on).
-metrics-bind-address:8080Prometheus metrics endpoint.
-health-probe-bind-address:8081Liveness / readiness probes.
-enable-webhookfalseOptional validating admission webhook.
-enable-cross-clusterfalseOpt-in cross-cluster replication (discover spokes from credential Secrets).
-cluster-credential-namespace$POD_NAMESPACEWhere spoke credential Secrets live.
Helm chart · values.yaml
ValueDefaultNotes
annotationDomainreplikate.ubixsys.comWires the flag above (the primary prefix).
previousAnnotationDomainreplikate.brainchurts.comNon-breaking domain migration — the old prefix stays honored until you set it empty.
excludeNamespaceskube-system, kube-public, kube-node-leaseNamespace skip-list.
leaderElection.enabledtrueHA-safe; only one replica reconciles at a time.
rbac.createtrueClusterRole/Binding for ConfigMap + Secret access.
resources (req → lim)50m/64Mi → 200m/128MiLightweight footprint out of the box.
metrics.serviceMonitor.enabledfalseScrape via the Prometheus Operator.
webhook.enabledfalseValidating webhook (port 9443, failurePolicy Fail).
crossCluster.enabledfalseMake this install a cross-cluster hub (chart 1.3.1+).
crossCluster.credentialNamespacerelease namespaceWhere spoke credential Secrets live.
podDisruptionBudget.enabledfalseKeep at least one replica during disruptions.
Architecture

One controller, one reconcile loop.

Watch the sources and the namespaces; make the copies match; only write when something changed.

The loop
Annotated source
ConfigMap / Secret with replikate.ubixsys.com/sync
↓
Controller · reconcile
watches sources + namespaces · leader-elected
↓
Managed copies
one per matching namespace · kept in sync
How it behaves

Replikate is a single controller built on controller-runtime. It watches two things — annotated source objects and the set of namespaces — and on any change reconciles the desired state: a managed copy of each source in every namespace its selector matches. It only writes when something actually differs, so the logs stay meaningful.

Ownership is explicit. Every copy is stamped managed-by=replikate, and the controller refuses to touch an object it doesn't own — emitting a Conflict event instead of fighting another source. A finalizer guarantees copies are removed when the source or annotation goes away, and the namespace watch means a new matching namespace is populated automatically.

It runs leader-elected, so multiple replicas are HA-safe with exactly one active reconciler. Cross-cluster (hub-and-spoke) replication is opt-in: set crossCluster.enabled, register each spoke as a labeled credential Secret (apply deploy/spoke-rbac.yaml on the spoke to mint it), and add a target-clusters annotation. Each entry places one copy: a bare cluster uses the source's namespace, cluster:namespace names one, and as of v1.4 a cluster can be repeated to reach several namespaces (green:web,green:live); dropping an entry prunes its copy. For blue/green, a separate infrastructure cluster makes the best hub, so neither colour depends on the other. A down spoke never blocks the others or the local path. Remote copies are stamped with the hub's cluster UID, so two hubs can share a spoke. Deleting the source removes its remote copies too, so deregister a spoke before retiring its hub. Remote copies re-sync on source change and on a ~2-minute recheck; instant remote drift repair and selector fan-out on spokes are next on the roadmap. The sync selector still applies on the hub itself, so give hub-only sources a selector that matches none of its namespaces.

As of v1.3 the annotation prefix moved to replikate.ubixsys.com, but the change is non-breaking: the previous replikate.brainchurts.com prefix is still honored for reads, matching, and adoption, and every reconcile self-migrates a copy to the new prefix in place — no coordinated re-annotation, and live secrets are never deleted and recreated. A replikate_copies_by_domain gauge shows the migration finishing; set previousAnnotationDomain empty once it reaches zero.