Production-Grade Setup (Capstone)¶
You are on the platform team, rolling out hibernation for the production environment. The constraints are real this time:
- The Hibernator operator runs in the ops account (
111122223333); production resources live in the workloads account (456789012345). Cross-account access must go through role assumption — no long-lived credentials. - Shutdown must be ordered: applications → compute → database.
- The on-call channel must know when cycles start, succeed, and fail — in Slack.
- A code-freeze week is coming, and governance wants the schedule override on record.
This capstone composes everything from the earlier scenarios into one setup.
Architecture¶
graph TD
subgraph Ops["Ops Account (111122223333)"]
OP[Hibernator Operator] --> SA[Runner ServiceAccount<br/>IRSA]
end
subgraph WL["Workloads Account (456789012345)"]
SA -->|AssumeRole| ROLE[HibernatorRole]
ROLE --> EKS[prod-cluster node groups]
ROLE --> RDS[prod-postgres]
ROLE --> KP[prod-cluster in-cluster resources<br/>via prod-eks connector]
end
OP -->|Lifecycle events| SLACK[Slack #oncall]
Step 1 — Connectors (cross-account)¶
The aws-workloads CloudProvider authenticates with the runner pod's IRSA identity from the ops account, then assumes HibernatorRole in the workloads account before touching anything. The prod-eks K8SCluster inherits that authentication through providerRef.
apiVersion: hibernator.ardikabs.com/v1alpha1
kind: CloudProvider
metadata:
name: aws-workloads
namespace: hibernator-system
spec:
type: aws
aws:
accountId: "456789012345"
region: ap-southeast-3
assumeRoleArn: arn:aws:iam::456789012345:role/HibernatorRole
auth:
serviceAccount: {}
---
apiVersion: hibernator.ardikabs.com/v1alpha1
kind: K8SCluster
metadata:
name: prod-eks
namespace: hibernator-system
spec:
providerRef:
name: aws-workloads
namespace: hibernator-system
eks:
name: prod-cluster
region: ap-southeast-3
See Connectors for the IRSA trust-policy setup and static-credential fallback.
Step 2 — The Plan (ordered, labeled)¶
Two details matter beyond the DAG shape:
metadata.labels— the notification resource matches plans by label. No labels, no alerts.- Opt-in workloads — production workloads hibernate only when explicitly labeled
hibernator.ardikabs.com/enabled: "true".
apiVersion: hibernator.ardikabs.com/v1alpha1
kind: HibernatePlan
metadata:
name: prod-main
namespace: hibernator-system
labels:
env: production
team: platform
spec:
schedule:
timezone: "Asia/Jakarta"
offHours:
- start: "23:00"
end: "05:30"
daysOfWeek: ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]
execution:
strategy:
type: DAG
maxConcurrency: 2
dependencies:
- from: app-workloads
to: karpenter-pools
- from: karpenter-pools
to: eks-nodegroups
- from: eks-nodegroups
to: database
behavior:
mode: Strict
retries: 3
targets:
- name: app-workloads
type: workloadscaler
connectorRef:
kind: K8SCluster
name: prod-eks
parameters:
namespace:
selector:
environment: production
workloadSelector:
matchExpressions:
- key: hibernator.ardikabs.com/enabled
operator: In
values: ["true"]
includedGroups: [Deployment]
awaitCompletion:
enabled: true
- name: karpenter-pools
type: karpenter
connectorRef:
kind: K8SCluster
name: prod-eks
parameters:
nodePools: []
awaitCompletion:
enabled: true
timeout: "5m"
- name: eks-nodegroups
type: eks
connectorRef:
kind: CloudProvider
name: aws-workloads
parameters:
clusterName: prod-cluster
nodeGroups: []
awaitCompletion:
enabled: true
timeout: "10m"
- name: database
type: rds
connectorRef:
kind: CloudProvider
name: aws-workloads
parameters:
selector:
instanceIds: [prod-postgres]
snapshotBeforeStop: true
awaitCompletion:
enabled: true
timeout: "15m"
Shutdown order: app-workloads → karpenter-pools → eks-nodegroups → database. Wakeup reverses it. (Why Karpenter before managed node groups: combined pattern.)
Step 3 — Notifications (Slack to #oncall)¶
apiVersion: v1
kind: Secret
metadata:
name: slack-oncall
namespace: hibernator-system
type: Opaque
stringData:
config: |
{
"webhook_url": "https://hooks.slack.com/services/T00/B00/xxxx"
}
---
apiVersion: hibernator.ardikabs.com/v1alpha1
kind: HibernateNotification
metadata:
name: prod-oncall
namespace: hibernator-system
spec:
selector:
matchLabels:
env: production
onEvents: [Start, Success, Failure, Recovery]
sinks:
- name: slack-oncall
type: slack
secretRef:
name: slack-oncall
Start gives the channel a heads-up, Success closes the loop, Failure + Recovery page the humans. For thread-mode delivery, Telegram, or custom templates, see Notifications and the sink reference.
Step 4 — Governance: the code-freeze week¶
Attach a replace exception for the freeze week — full-day hibernation, on record, auto-expiring:
apiVersion: hibernator.ardikabs.com/v1alpha1
kind: ScheduleException
metadata:
name: code-freeze-week
namespace: hibernator-system
spec:
planRef:
name: prod-main
type: replace
validFrom: "2026-12-21T00:00:00Z"
validUntil: "2026-12-27T23:59:59Z"
windows:
- start: "00:00"
end: "23:59"
daysOfWeek: ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]
Deep dive: Holiday Schedule Replacement and Composing Multiple Exceptions.
Verification — Go-Live Checklist¶
- Notification matching —
kubectl get hnotif prod-oncall -n hibernator-systemshowsMatched: 1. - First cycle — watch the phase:
kubectl get hibernateplan prod-main -n hibernator-system -w. -
Ordering — confirm DAG levels via the ledger:
-
Slack — a
Startmessage lands in #oncall at 23:00;Successfollows when all targets complete. - Morning — wakeup runs in reverse order; plan returns to
Active. - Metrics — add the operator's Prometheus metrics to your dashboards: Metrics reference.
Do not skip the rehearsal
Run this exact plan shape through a Dry-Run Rehearsal on the noop executor before the first production window. And keep the Troubleshooting guide bookmarked for IRSA and permission issues on first contact with the workloads account.
Next Steps¶
- Notifications — events, sinks, templates, thread mode
- Error Recovery — what happens when prod misbehaves
- Metrics — dashboards and alerts on the operator itself