churnless

module
v0.0.0-...-2def651 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: Apache-2.0

README

Churnless

Keep Pod identity stable during supported in-place rollouts.

Churnless provides native-shaped Kubernetes Deployment and ReplicaSet APIs that apply mutable metadata, images, and supported resources without replacing healthy Pods. During a successful in-place rollout, Pod names, UIDs, and IPs stay the same.

[!IMPORTANT] Churnless is experimental and its API is v1alpha1. Test it carefully before using it for production workloads.

Why

A native Kubernetes Deployment creates a new ReplicaSet whenever its Pod template changes. An image rollout therefore creates replacement Pods and may churn their IPs. Churnless treats supported metadata, images, and opted-in CPU and memory changes as mutable revisions inside a ReplicaSet and patches the existing Pods when Kubernetes permits it.

Stable Pod IPs also reduce the risk of control-plane propagation lag. In a large cluster under pressure, components such as CoreDNS or Envoy Gateway may observe Pod or EndpointSlice changes late. If a rollout replaces Pods and changes their IPs faster than those updates propagate, data-plane clients can temporarily resolve or route to stale addresses, causing lookup, connection, or availability failures. In-place updates avoid unnecessary endpoint churn and narrow that failure window.

Where rollout time goes

A typical image-only RollingUpdate follows these paths. Exact ordering depends on the rollout strategy, but a native rollout must establish replacement Pods; a successful Churnless rollout keeps the existing Pod sandbox and network.

sequenceDiagram
    participant Change as Image update
    participant Control as API and controllers
    participant Scheduler
    participant Kubelet
    participant Network as CNI and IPAM
    participant DataPlane as DNS, gateways, and proxies

    Note over Change,DataPlane: Native Deployment replacement path
    rect rgb(255, 235, 235)
        Note over Control,Network: Replacement setup span skipped by Churnless
        Change->>Control: Create a new ReplicaSet and Pod
        Control->>Scheduler: Wait for scheduling
        Scheduler->>Kubelet: Bind replacement Pod
        Kubelet->>Network: Create sandbox and allocate a Pod IP
        Network-->>Kubelet: Network ready
    end
    Kubelet->>Kubelet: Pull image and start container
    Kubelet-->>Control: Replacement Pod Ready
    rect rgb(255, 235, 235)
        Note over Control,DataPlane: Address churn and teardown span skipped by Churnless
        Control-->>DataPlane: Propagate the new endpoint address
        Control->>Kubelet: Delete the old Pod
        Kubelet->>Network: Tear down network and release the old IP
    end

    Note over Change,DataPlane: Churnless in-place path
    rect rgb(240, 255, 245)
        Change->>Control: Patch the image on the existing Pod
        Control->>Kubelet: Deliver the updated Pod spec
        Note over Scheduler,Network: Reuse the existing Pod sandbox and IP
        Kubelet->>Kubelet: Pull image and restart container
        Kubelet-->>Control: The same Pod becomes Ready
        Control-->>DataPlane: Readiness may change, while the endpoint address stays the same
    end

The red spans are replacement-only work that a successful Churnless rollout skips: scheduling, Pod sandbox startup, CNI/IPAM allocation, endpoint-address churn, network teardown, and IP release. Teardown may happen asynchronously after a native rollout reports success. Image pull, container startup, and readiness checks remain unshaded because both paths still pay those costs. The benchmark below measures the end-to-end result rather than assigning fixed durations to these cluster-dependent stages.

Deployment.churnless.io
└── ReplicaSet.churnless.io
    └── Pod

Churnless uses no native Deployment or ReplicaSet shadow objects.

Highlights:

  • Deployment and ReplicaSet under churnless.io/v1alpha1
  • Native apps/v1 specs and statuses embedded in the Go API
  • In-place Pod-template label, annotation, and container image updates
  • Opt-in best-effort regular-container CPU/memory resize
  • RollingUpdate and Recreate for structural template changes
  • Scaling, self-healing, Pod adoption, availability, and rollout status
  • Standard /scale support for kubectl scale and HPA
  • Upstream Kubernetes v1.36 workload defaulting and validation
  • Kubebuilder-native manifests and an isolated kind test workflow

Try it with kind

Prerequisites:

Create a local cluster, build and load the controller, install the CRDs, and deploy a two-replica sample. The setup also installs pinned cert-manager and Metrics Server releases for webhook and HPA testing:

make kind-up

Inspect the custom Deployment, its Churnless ReplicaSet, and the Pods:

make kind-status

Patch the sample image using the Churnless Deployment short name:

kubectl patch cdeploy deployment-sample \
  --type=merge \
  -p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx","image":"nginx:1.28-alpine","ports":[{"containerPort":80}]}]}}}}'

Compare Pod identity before and after the rollout:

kubectl get pods -l app=deployment-sample \
  -o 'custom-columns=NAME:.metadata.name,UID:.metadata.uid,IP:.status.podIP,IMAGE:.spec.containers[0].image'

Opt a workload into best-effort CPU/memory resize:

kubectl annotate deployment.churnless.io/deployment-sample \
  churnless.io/in-place-resources=best-effort

If Kubernetes rejects a resize, Churnless replaces that Pod under the normal rollout availability budget.

Explicitly replace every Pod even when the template is otherwise unchanged:

kubectl annotate deployment.churnless.io/deployment-sample \
  kubectl.kubernetes.io/restartedAt="$(date -u +%Y-%m-%dT%H:%M:%SZ)" --overwrite

The built-in kubectl rollout restart command cannot decode custom Deployment GVKs. Churnless accepts its standard annotation key through generic kubectl annotate; churnless.io/redeploy-at remains an equivalent alias.

Clean up:

make kind-down

Use the API

For supported behavior, migrate a native manifest by changing its API version:

apiVersion: churnless.io/v1alpha1
kind: Deployment

Use the distinct Churnless short names for interactive commands:

kubectl get cdeploy
kubectl get chrs
kubectl get churnless
kubectl scale cdeploy/deployment-sample --replicas=3

For scripts, use fully qualified resource names such as deployments.churnless.io and replicasets.churnless.io.

HPA can target the Churnless GVK directly through its standard /scale subresource.

Design

See DESIGN.md for the compatibility contract, controller responsibilities, revision model, invariants, known gaps, and required acceptance tests.

Development

The project was bootstrapped with Kubebuilder and follows its standard layout.

Run the local checks:

make manifests generate
make test
make lint

Run the isolated kind end-to-end suite:

make test-e2e

Compare image-only rollouts with native Deployments on a dedicated kind cluster. The default run uses 100 replicas, three alternating image rollouts, and preloaded images so registry latency is outside the measurement:

make benchmark-rollout
make benchmark-rollout-cleanup

Override BENCHMARK_REPLICAS and BENCHMARK_ITERATIONS for larger or longer runs. The benchmark fails if either rollout violates its surge/availability budget or if Pod identity behavior differs from the expected native and Churnless models.

Contributing

Issues and pull requests are welcome. Please include tests for behavior changes and keep the design contract current.

License

Licensed under the Apache License 2.0.

Directories

Path Synopsis
api
v1alpha1
Package v1alpha1 contains API Schema definitions for the churnless v1alpha1 API group.
Package v1alpha1 contains API Schema definitions for the churnless v1alpha1 API group.
internal
kubecompat
Package kubecompat isolates Churnless from Kubernetes's non-staging Go packages.
Package kubecompat isolates Churnless from Kubernetes's non-staging Go packages.
test
benchmark command
Command benchmark compares image-only rollouts for native and Churnless Deployments on the same Kubernetes cluster.
Command benchmark compares image-only rollouts for native and Churnless Deployments on the same Kubernetes cluster.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL