Downscale after work and resume in the morning
Scale every Deployment and StatefulSet in selected development namespaces to zero after work. Restore each workload’s original replica count in the morning. This example only schedules actions; it adds no admission restrictions or warnings.
Complete example
apiVersion: addons.projectcapsule.dev/v1alpha1
kind: ChangeWindow
metadata:
name: after-hours
spec:
namespaceSelectors:
- matchLabels:
environment: development
schedules:
- name: every-night
cron: "0 19 * * *"
timeZone: Europe/Zurich
duration: 12h
serviceAccount:
namespace: schedule-action-controller-system
name: after-hours-executor
targets:
- name: deployments
apiVersion: apps/v1
kind: Deployment
- name: statefulsets
apiVersion: apps/v1
kind: StatefulSet
actions:
- name: sleep-and-resume
targets: [deployments, statefulsets]
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 }}The window starts every day at 19:00 in Europe/Zurich and lasts 12 elapsed
hours, normally restoring workloads at 07:00. timeZone is set per schedule
within the ChangeWindow, so different windows can use different IANA zones without
changing controller configuration. Its default is UTC.
On a night when clocks change for daylight saving, twelve elapsed hours can end at 06:00 or 08:00 local time. The API specifies a duration, not a separate local end time. See time zones.
Workloads and namespace scope
Label the affected namespaces environment=development. Omitting target label
selectors selects all Deployments and StatefulSets in those namespaces. Use
namespaceSelectors: [{}] to include every eligible namespace, and grant executor
permissions in each one. Protected infrastructure namespaces remain excluded.
These workloads expose a /scale endpoint. DaemonSets, Jobs, CronJobs, and standalone
Pods do not share that scaling behavior and are not selected. ReplicaSets managed
by Deployments scale through their owning Deployment.
Each workload’s replica count is captured before downscaling. A workload with three replicas resumes with three; one already at zero stays at zero. Captures survive controller restarts. Newly created workloads join the next window, and deleted workloads or replacements with a different UID are not restored.
Executor permissions
This manifest grants access in the existing development namespace. Repeat the
workload Role and RoleBinding for each selected namespace. Adjust the controller
namespace and manager ServiceAccount subject for your Helm release, following
the
executor setup instructions.
Set spec.serviceAccount.namespace in the ChangeWindow to the same executor
namespace and retain the executor name after-hours-executor.
# Example: an executor in the controller namespace may scale Deployments and StatefulSets only in
# the existing namespace "development". Repeat workload RoleBindings as needed.
apiVersion: v1
kind: ServiceAccount
metadata:
name: after-hours-executor
namespace: schedule-action-controller-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: impersonate-after-hours-executor
namespace: schedule-action-controller-system
rules:
- apiGroups: [""]
resources: [serviceaccounts]
resourceNames: [after-hours-executor]
verbs: [impersonate]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: impersonate-after-hours-executor
namespace: schedule-action-controller-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: impersonate-after-hours-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: after-hours-scale
namespace: development
rules:
- apiGroups: [apps]
resources: [deployments, statefulsets]
verbs: [get, list]
- apiGroups: [apps]
resources: [deployments/scale, statefulsets/scale]
verbs: [get, patch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: after-hours-scale
namespace: development
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: after-hours-scale
subjects:
- kind: ServiceAccount
name: after-hours-executor
namespace: schedule-action-controller-systemDownload after-hours-executor-rbac.yaml
The start action explicitly takes ownership of spec.replicas using force.
Coordinate with HPAs, GitOps reconciliation, and other replica writers: this
action runs once at the start and end, rather than continuously holding replicas
at zero. See
resource actions.