Policy Combinations - Practical Examples
Real-world examples showing how to combine CreationPolicy, DeletionPolicy, ConflictPolicy, and PatchStrategy for different resource types.
Overview
This guide demonstrates how policies work together through four common scenarios:
| Example | Use Case | Key Pattern | Policies |
|---|---|---|---|
| Example 1 | Persistent Data | Immutable + Retained | Once + Retain + Stuck |
| Example 2 | One-time Setup | Run Once + Cleanup | Once + Delete + Force |
| Example 3 | Main Application | Sync + Cleanup | WhenNeeded + Delete + Stuck |
| Example 4 | Shared Config | Sync + Retained | WhenNeeded + Retain + Force |
Example 1: Stateful Data (PVC)
Use Case: Persistent storage that must survive node lifecycle changes and never lose data.
Configuration
persistentVolumeClaims:
- id: data
creationPolicy: Once # Create only once
deletionPolicy: Retain # Keep data after node deletion
conflictPolicy: Stuck # Don't overwrite existing PVCs
patchStrategy: apply # Standard SSA
nameTemplate: "{{ .uid }}-data"
spec:
apiVersion: v1
kind: PersistentVolumeClaim
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10GiLifecycle Flow
Rationale
Once: PVC spec shouldn't change (size immutable in many storage classes)Retain: Data survives node deletion - NO ownerReference set to prevent automatic deletionStuck: Safety - don't overwrite someone else's PVC on initial creationapply: Standard SSA for declarative management
Key Behaviors
- ✅ Created once, never updated (even if template changes)
- ✅ Survives node deletion (label-based tracking)
- ✅ Safe conflict detection on initial creation
- 📊 Data persists indefinitely
- ⚠️ Important: Once
created-onceannotation is set,ApplyResourceis never called again
Delete and Recreate Scenario
CreationPolicy=Once Limitation
With CreationPolicy: Once, the operator SKIPS resources that have the created-once annotation. This means on Node recreation:
- NO re-adoption occurs
- Orphan markers remain on the resource
- NO conflict detection (ApplyResource is not called)
- Resource is counted as Ready but not actively managed
Scenario Timeline:
Manual Recovery:
# Remove the created-once annotation to allow re-adoption
kubectl annotate pvc acme-data lynq.sh/created-once-
# Next reconciliation will call ApplyResource and remove orphan markersExample 2: Init Job
Use Case: One-time initialization task that runs once per node and cleans up after node deletion.
Configuration
jobs:
- id: init
creationPolicy: Once # Run only once
deletionPolicy: Delete # Clean up after node deletion
conflictPolicy: Force # Re-create if needed
patchStrategy: replace # Exact job spec
nameTemplate: "{{ .uid }}-init"
spec:
apiVersion: batch/v1
kind: Job
spec:
template:
spec:
containers:
- name: init
image: busybox
command: ["sh", "-c", "echo Initializing {{ .uid }}"]
restartPolicy: NeverLifecycle Flow
Rationale
Once: Initialization runs only once - even if template changes, job won't re-runDelete: No need to keep job history after node deletionForce: Operator owns this resource exclusively - takes ownership if conflictreplace: Ensures exact job spec match
Key Behaviors
- ✅ Runs once per node lifetime
- ✅ Automatically cleaned up on node deletion
- ✅ Force takes ownership from conflicts
- 🔄 Re-creates if manually deleted (but still runs only once due to created-once annotation)
Example 3: Application Deployment
Use Case: Main application that should stay synchronized with template changes and clean up completely on deletion.
Configuration
deployments:
- id: app
creationPolicy: WhenNeeded # Keep updated
deletionPolicy: Delete # Clean up on deletion
conflictPolicy: Stuck # Safe default
patchStrategy: apply # Kubernetes best practice
nameTemplate: "{{ .uid }}-app"
spec:
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 2
selector:
matchLabels:
app: "{{ .uid }}"
template:
metadata:
labels:
app: "{{ .uid }}"
spec:
containers:
- name: app
image: "nginx:latest"Lifecycle Flow
Rationale
WhenNeeded: Always keep deployment in sync with template and databaseDelete: Standard cleanup via ownerReferenceStuck: Safe default - investigate conflicts rather than force overrideapply: SSA best practice - preserves fields from other controllers (e.g., HPA)
Key Behaviors
- ✅ Continuously synchronized with template
- ✅ Auto-corrects manual drift
- ✅ Plays well with other controllers (HPA, VPA)
- ✅ Complete cleanup on deletion
- ⚠️ Stops on conflicts for safety
Example 4: Shared Infrastructure
Use Case: Configuration data that should stay updated but survive node deletion for debugging or shared resource references.
Configuration
configMaps:
- id: shared-config
creationPolicy: WhenNeeded # Maintain config
deletionPolicy: Retain # Keep config for investigation
conflictPolicy: Force # Operator manages configs
patchStrategy: apply # SSA
nameTemplate: "{{ .uid }}-shared-config"
spec:
apiVersion: v1
kind: ConfigMap
data:
config.json: |
{
"tenantId": "{{ .uid }}",
"environment": "production",
"version": "1.0"
}Lifecycle Flow
Rationale
WhenNeeded: Keep configmap data updated as template/database changesRetain: ConfigMap might be referenced by other resources or needed for debugging - NO ownerReference to prevent deletionForce: Operator is authoritative for this config - takes ownership if conflict existsapply: SSA for declarative configuration management
Key Behaviors
- ✅ Continuously synchronized with changes
- ✅ Force takes ownership from conflicts
- ✅ Survives node deletion (label-based tracking)
- 📊 Available for investigation post-deletion
- 🔗 Can be referenced by non-node resources
Delete and Recreate with WhenNeeded
Unlike Example 1 (PVC with Once), resources with WhenNeeded automatically re-adopt on recreation:
Key Differences from Example 1:
| Aspect | Example 1 (PVC) Once + Retain | Example 4 (ConfigMap) WhenNeeded + Retain |
|---|---|---|
| Updates | 🚫 Never (frozen after creation) | ✅ Always (syncs with template) |
| Retention | ✅ Yes (orphaned on delete) | ✅ Yes (orphaned on delete) |
| Re-adoption | ❌ No (skipped due to created-once) | ✅ Yes (automatic on recreate) |
| Force Ownership | ❌ No (Stuck policy) | ✅ Yes (Force policy) |
Policy Combinations Summary
Quick reference comparing all four examples:
| Aspect | PVC (Stateful) | Init Job | App Deployment | Shared Config |
|---|---|---|---|---|
| CreationPolicy | Once | Once | WhenNeeded | WhenNeeded |
| DeletionPolicy | Retain | Delete | Delete | Retain |
| ConflictPolicy | Stuck | Force | Stuck | Force |
| PatchStrategy | apply | replace | apply | apply |
| ownerReference | ❌ No | ✅ Yes | ✅ Yes | ❌ No |
| Updates | 🚫 Never | 🚫 Never | ✅ Always | ✅ Always |
| Survives Deletion | ✅ Yes | ❌ No | ❌ No | ✅ Yes |
| Auto-Cleanup | ❌ Manual | ✅ Auto (GC) | ✅ Auto (GC) | ❌ Manual |
| Drift Correction | N/A (Once) | N/A (Once) | ✅ Yes | ✅ Yes |
| Conflict Handling | ⚠️ Stop | 💪 Force | ⚠️ Stop | 💪 Force |
Legend:
- ✅ Enabled / Yes
- ❌ Disabled / No
- 🚫 Never updates
- ⚠️ Safe mode (stops on conflict)
- 💪 Aggressive (forces ownership)
- N/A: Not applicable
Decision Tree
Choose the right policy combination for your use case:
See Also
- Policies Guide - Core concepts and policy types
- Field-Level Ignore Control - Fine-grained field management
- Dependencies Guide - Resource ordering
- Troubleshooting - Common policy issues
