On this page
Downscale and restore workloads
Reduce selected Deployments to zero replicas overnight and restore the captured replica count when the window ends. Overlapping schedules merge into one window, so workloads remain downscaled across adjoining periods.
Complete example
apiVersion: addons.projectcapsule.dev/v1alpha1
kind: ChangeWindow
metadata:
name: development-downtime
spec:
namespaceSelectors:
- matchLabels:
environment: development
- matchLabels:
environment: staging
schedules:
- name: weekday-nights
cron: "0 19 * * 1-5"
timeZone: Europe/Zurich
duration: 12h
- name: weekend
cron: "0 7 * * 6"
timeZone: Europe/Zurich
duration: 48h
serviceAccount:
namespace: schedule-action-controller-system
name: change-window-executor
targets:
- name: deployments
apiVersion: apps/v1
kind: Deployment
selector:
matchLabels:
downscaling: enabled
actions:
- name: downscale
targets: [deployments]
capture:
replicas:
subresource: scale
path: /spec/replicas
onStart:
apply:
subresource: scale
force: true
template: |
spec:
replicas: 0
onEnd:
apply:
subresource: scale
template: |
spec:
replicas: {{ .captured.replicas }}
admission:
- name: freeze-deployments
targets: [deployments]
operations: [CREATE, UPDATE, DELETE]
subresources: ["", scale]
when: Active
action: Deny
message: >-
Deployment changes are blocked during maintenance. Retry after {{ .window.end }}.
config:
admission:
warnings:
- name: upcoming-maintenance
targets: [deployments]
operations: [CREATE, UPDATE, DELETE]
subresources: ["", scale]
when: BeforeStart
within: 1h
message: >-
Maintenance starts at {{ .window.start }} (in {{ .window.startsIn }}).
- name: active-maintenance
targets: [deployments]
operations: [CREATE, UPDATE, DELETE]
subresources: ["", scale]
when: Active
message: Maintenance is active until {{ .window.end }}.Download addons_v1alpha1_changewindow.yaml
Executor permissions
Create the executor ServiceAccount and its narrowly scoped permissions first.
Follow the
executor setup instructions
to adapt the sample to your Helm release. Repeat the workload Role and RoleBinding
in every permitted namespace the window selects.
The example’s serviceAccount must match the account granted these permissions.
# Example: an executor in the controller namespace may scale Deployments only in
# the existing namespace "development". Repeat workload RoleBindings as needed.
apiVersion: v1
kind: ServiceAccount
metadata:
name: change-window-executor
namespace: schedule-action-controller-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: impersonate-change-window-executor
namespace: schedule-action-controller-system
rules:
- apiGroups: [""]
resources: [serviceaccounts]
resourceNames: [change-window-executor]
verbs: [impersonate]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: impersonate-change-window-executor
namespace: schedule-action-controller-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: impersonate-change-window-executor
subjects:
- kind: ServiceAccount
name: schedule-action-controller-controller-manager
namespace: schedule-action-controller-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: change-window-scale
namespace: development
rules:
- apiGroups: [apps]
resources: [deployments]
verbs: [get, list]
- apiGroups: [apps]
resources: [deployments/scale]
verbs: [get, patch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: change-window-scale
namespace: development
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: change-window-scale
subjects:
- kind: ServiceAccount
name: change-window-executor
namespace: schedule-action-controller-systemStart actions capture state before applying changes. Captures survive controller restarts. End actions restore the recorded resource UID, avoiding replacements that happen to reuse a deleted Deployment’s name. See resource actions for SSA ownership, subresources, restoration, and failure handling.