Field-Level Ignore Control β
Overview β
The ignoreFields feature provides fine-grained control over which fields should be excluded from synchronization. This allows you to manage most resource fields declaratively through templates while letting specific fields be controlled externally (e.g., by HPA, manual scaling, or other operators).
Problem Statement β
Standard CreationPolicy options are too coarse-grained:
Once: Creates resource once, never syncs any fields (all-or-nothing)WhenNeeded(default): Continuously syncs all fields
Real-world scenario: You want HPA to dynamically control spec.replicas, but still want the operator to manage container images, environment variables, and other configuration.
Solution: Selective Field Ignoring β
The ignoreFields array accepts standard JSONPath expressions to specify which fields should be excluded from synchronization.
apiVersion: operator.lynq.sh/v1
kind: LynqForm
spec:
deployments:
- id: web-app
creationPolicy: WhenNeeded # Default - continues syncing
ignoreFields:
- "$.spec.replicas" # Let HPA control this
- "$.spec.template.spec.containers[0].resources" # Allow manual tuning
spec:
apiVersion: apps/v1
kind: Deployment
metadata:
name: "{{ .uid }}-web"
spec:
replicas: 3 # Initial value, then ignored
template:
spec:
containers:
- name: app
image: "nginx:{{ .version }}" # Continues to syncHow It Works β
Initial Creation β
When a resource is first created:
- β All fields (including ignored ones) are applied
- β Resource created with complete specification
Subsequent Reconciliations β
When the resource already exists:
- π Operator detects resource exists
- ποΈ Removes ignored fields from desired state
- β Applies only non-ignored fields via SSA
- β¨ Result: Ignored fields preserve cluster values, others sync to template
Example Scenario β
Step 1: Initial Deployment β
Template:
ignoreFields: ["$.spec.replicas"]
spec:
replicas: 3
template:
spec:
containers:
- name: app
image: nginx:1.20Result: Deployment created with replicas: 3, image: nginx:1.20
Step 2: HPA Scales Up β
HPA scales deployment to replicas: 5
Step 3: Template Update β
Template updated:
ignoreFields: ["$.spec.replicas"]
spec:
replicas: 3 # Template still shows 3
template:
spec:
containers:
- name: app
image: nginx:1.21 # Image updatedStep 4: Reconciliation β
- Cluster state:
replicas: 5,image: nginx:1.20 - Desired state:
replicas: 3,image: nginx:1.21 - Operator removes
replicasfrom desired state - Operator applies:
image: nginx:1.21only
Final Result:
- β
replicas: 5(preserved - HPA in control) - β
image: nginx:1.21(synced - operator in control)
Supported JSONPath Expressions β
This feature uses the ojg/jp library, providing complete JSONPath standard support.
Basic Path Navigation β
ignoreFields:
# Simple field
- "$.spec.replicas"
# Nested field
- "$.spec.template.spec.securityContext"
# Deeply nested field
- "$.spec.template.spec.containers[0].image"Array Element Access β
ignoreFields:
# First container's image
- "$.spec.template.spec.containers[0].image"
# Second container's resources
- "$.spec.template.spec.containers[1].resources"
# Init container resources
- "$.spec.template.spec.initContainers[0].resources"Wildcard Support β
ignoreFields:
# All containers' images
- "$.spec.template.spec.containers[*].image"
# All containers' environment variables
- "$.spec.template.spec.containers[*].env"
# All init containers' resources
- "$.spec.template.spec.initContainers[*].resources"Map Keys with Special Characters β
ignoreFields:
# Annotation with dots and slashes
- "$.metadata.annotations['app.kubernetes.io/version']"
# Label with special chars
- "$.metadata.labels['app.kubernetes.io/managed-by']"
# ConfigMap data key
- "$.data['application.properties']"Common Use Cases β
1. HPA-Controlled Replicas β
Let HPA manage scaling while operator manages configuration:
deployments:
- id: api-server
ignoreFields:
- "$.spec.replicas"
spec:
replicas: 3 # Initial/default value
# ... rest of spec2. Manual Resource Tuning β
Allow manual resource adjustments while syncing code changes:
deployments:
- id: backend
ignoreFields:
- "$.spec.template.spec.containers[0].resources"
spec:
template:
spec:
containers:
- name: app
image: "backend:{{ .version }}" # Syncs
resources: # Ignored after creation
limits:
memory: "2Gi"3. Multiple Containers β
Different ignore policies per container:
deployments:
- id: multi-container-app
ignoreFields:
# Main app: ignore resources
- "$.spec.template.spec.containers[0].resources"
# Sidecar: ignore image (updated separately)
- "$.spec.template.spec.containers[1].image"
spec:
template:
spec:
containers:
- name: app
image: "app:latest"
- name: sidecar
image: "sidecar:stable"4. Bulk Ignoring with Wildcards β
Ignore same field across all containers:
deployments:
- id: microservice
ignoreFields:
# All containers can be manually scaled
- "$.spec.template.spec.containers[*].resources.limits"
# All containers' liveness probes can be tuned
- "$.spec.template.spec.containers[*].livenessProbe"Validation β
Admission Webhook β
JSONPath expressions are validated at admission time:
# Valid
ignoreFields: ["$.spec.replicas"] β
# Invalid - missing $ prefix
ignoreFields: ["spec.replicas"] β
Error: invalid JSONPath "spec.replicas"
# Invalid - malformed bracket
ignoreFields: ["$[invalid"] β
Error: invalid JSONPath "$[invalid"Runtime Behavior β
- Non-existent paths: Silently skipped (no error)
- Array out of bounds: Silently skipped (no error)
- Type mismatches: Silently skipped (no error)
This graceful handling ensures reconciliation continues even if ignored fields don't exist.
Interaction with Policies β
CreationPolicy: Once β
When combined with CreationPolicy: Once, ignoreFields has no effect:
deployments:
- id: init-job
creationPolicy: Once
ignoreFields: ["$.spec.replicas"] # No effect - resource never reconciledReason: Once policy means resource is created once and never touched again, so field-level control is irrelevant.
ConflictPolicy β
Ignored fields do not participate in conflict detection:
deployments:
- id: app
conflictPolicy: Stuck
ignoreFields: ["$.spec.replicas"]If another controller modifies replicas, no conflict is detected because it's ignored.
DeletionPolicy β
ignoreFields does not affect deletion behavior:
deployments:
- id: app
deletionPolicy: Retain
ignoreFields: ["$.spec.replicas"]When LynqNode is deleted, deletion policy is still respected (resources retained).
Best Practices β
1. Document Why Fields Are Ignored β
deployments:
- id: api-server
# Replicas controlled by HPA based on CPU/memory
ignoreFields: ["$.spec.replicas"]2. Use Specific Paths Over Wildcards β
# β
Good - explicit and clear
ignoreFields:
- "$.spec.template.spec.containers[0].resources"
# β οΈ Use with caution - affects all containers
ignoreFields:
- "$.spec.template.spec.containers[*].resources"3. Test Ignored Fields in Staging β
Before production, verify:
- Initial creation includes ignored fields β
- Manual changes to ignored fields are preserved β
- Template changes to other fields still sync β
4. Monitor Drift β
While ignored fields won't trigger reconciliation, monitor them separately:
# Alert if replicas drift significantly from template
abs(
kube_deployment_spec_replicas -
tenant_template_spec_replicas
) > 10Troubleshooting β
Issue: Ignored Field Still Being Overwritten β
Check:
- Is
creationPolicyset toWhenNeeded? (default) - Is JSONPath expression valid?
- Does path exactly match the field structure?
# Verify JSONPath
kubectl get lynqnode -o yaml
# Check ignoreFields syntaxIssue: Template Changes Not Applying β
Possible causes:
- Field is accidentally in
ignoreFields - Wrong JSONPath (typo in path)
# Wrong
ignoreFields: ["$.spec.template.spec.container[0].image"]
# ^^^ missing 's'
# Correct
ignoreFields: ["$.spec.template.spec.containers[0].image"]Issue: Validation Error on Admission β
Check JSONPath syntax:
# Test JSONPath locally
echo '{"spec":{"replicas":3}}' | jq '.spec.replicas'
# Valid JSONPath must start with $
ignoreFields: ["$.spec.replicas"] β
ignoreFields: ["spec.replicas"] βPerformance Considerations β
Minimal Overhead β
- Parsing: JSONPath expressions parsed once at filter creation
- Filtering: O(n) where n = number of ignored fields (typically < 5)
- Memory: Negligible (~100 bytes per expression)
Large-Scale Deployments β
For 1000+ nodes with ignored fields:
- CPU impact: < 1% overhead
- Reconciliation time: < 10ms additional latency
Migration Guide β
Adding ignoreFields to Existing Resources β
Step 1: Identify fields to ignore
# Check what's being managed
kubectl get deployment myapp -o yaml | grep replicasStep 2: Add to template
deployments:
- id: myapp
ignoreFields: ["$.spec.replicas"]
# ... existing specStep 3: Apply template
kubectl apply -f lynqnode-template.yamlStep 4: Verify
# Make a manual change
kubectl scale deployment myapp --replicas=10
# Update template (change something else)
# Apply template
# Verify replicas unchanged
kubectl get deployment myapp -o jsonpath='{.spec.replicas}'
# Should still show 10Removing ignoreFields β
Warning: Removing ignoreFields will cause operator to overwrite cluster values with template values on next reconciliation.
# Before
ignoreFields: ["$.spec.replicas"] # replicas=10 in cluster
spec:
replicas: 3 # template value
# After removal
ignoreFields: [] # β Removed
# Next reconciliation: replicas will be reset to 3Related Features β
- Policies - Overall resource management policies
- Dependencies - Resource creation ordering
- Templates - Template variable system
