Is your feature request related to a problem?
Fleet should skip deployment when no targetCustomization matches the cluster
Problem Description
When a GitRepo monitors a path containing an application, but the application's fleet.yaml contains targetCustomizations that don't match the current cluster, Fleet still attempts to deploy the application instead of gracefully skipping it. This results in deployment errors that should not occur.
Current Behavior
GitRepo Configuration:
apiVersion: fleet.cattle.io/v1alpha1
kind: GitRepo
metadata:
name: xgcd
namespace: fleet-local
spec:
repo: http://gerrit.guasemi.com/devops/xgcd.git
branch: master
paths:
- apps/* # Monitors all applications (including apps/2/*)
targets:
- clusterSelector:
matchExpressions:
- key: provider.cattle.io
operator: NotIn
values:
- harvester # Targets all non-harvester clusters (including local)
Application fleet.yaml:
# apps/2/10005/fleet.yaml
defaultNamespace: default
helm:
chart: ./
releaseName: app-2-10005
targetCustomizations:
- name: prod
clusterSelector:
matchLabels:
env: procluster # Only matches downstream cluster
namespace: default
helm:
valuesFiles:
- values-prod.yaml
Result:
The local cluster matches the GitRepo's targets (it's not a harvester cluster), so Fleet creates a Bundle for it. However, the local cluster doesn't have the env: procluster label, so no targetCustomization matches. Instead of skipping the deployment, Fleet still attempts to deploy with incomplete configuration, resulting in errors like:
ErrApplied(1) [Cluster fleet-local/local: template: app-10005/templates/service.yaml:1:14:
executing "app-10005/templates/service.yaml" at <.Values.service.enabled>:
nil pointer evaluating interface {}.enabled]
Root Cause Analysis
Fleet has a two-tier filtering mechanism:
-
GitRepo.spec.targets (Tier 1): Determines which clusters should receive the Bundle
- In this case: All non-harvester clusters (including
local)
-
fleet.yaml.targetCustomizations (Tier 2): Determines which configuration to use for each cluster
- In this case: Only clusters with
env: procluster label
The Problem:
When a cluster passes Tier 1 filtering (GitRepo targets) but has no matching targetCustomization in Tier 2, Fleet still attempts to deploy instead of gracefully skipping. This creates a mismatch between "this cluster should receive the Bundle" (Tier 1 ✅) and "this cluster has no configuration" (Tier 2 ❌).
Expected Behavior
When a cluster doesn't match any targetCustomizations in the application's fleet.yaml, Fleet should:
- NOT create a BundleDeployment for that cluster
- Gracefully skip the deployment without errors
- Log an informational message (optional) indicating the application was skipped due to no matching targetCustomization
Steps to Reproduce
- Create a GitRepo in
fleet-local namespace that monitors apps/*
- Create an application in
apps/2/10005 with fleet.yaml containing only targetCustomizations for downstream clusters (e.g., env: procluster)
- Ensure the local cluster does NOT have the
env: procluster label
- Observe that Fleet still attempts to deploy to the local cluster and fails
Impact
This behavior causes several issues:
- Confusing error messages: Users see deployment errors for clusters that shouldn't receive the application
- Workaround required: Users must either:
- Add dummy
targetCustomizations for every possible cluster (even if not intended)
- Create multiple GitRepos with narrow
paths filters
- Use complex
targets.clusterSelector in GitRepo
- Poor user experience: The error suggests a configuration problem when the configuration is actually correct
Current Workarounds
Workaround 1: Add targetCustomizations for all clusters
targetCustomizations:
- name: test
clusterSelector:
matchLabels:
env: prod # Matches local cluster
helm:
valuesFiles:
- values-test.yaml
- name: prod
clusterSelector:
matchLabels:
env: procluster # Matches downstream cluster
helm:
valuesFiles:
- values-prod.yaml
Pros: Works reliably
Cons: Forces deployment to clusters that may not need the application
Workaround 2: Use narrow GitRepo paths
# fleet-local GitRepo
paths:
- apps/1/* # Only system 1
# fleet-default GitRepo
paths:
- apps/2/* # Only system 2
Pros: Clean separation
Cons: Requires multiple GitRepos, more complex configuration
Proposed Solution
Implement a filtering mechanism that checks targetCustomizations before creating BundleDeployments:
GitRepo discovers application
↓
Parse fleet.yaml
↓
For each target cluster:
↓
Check if cluster matches any targetCustomization
↓
YES → Create BundleDeployment with matched config
NO → Skip (do not create BundleDeployment)
Environment
Additional Context
This issue is particularly problematic in multi-cluster environments where:
- A monorepo contains applications for different clusters
- Different applications target different cluster types (dev/staging/prod)
- GitRepo paths must be broad to monitor multiple applications
The current behavior forces users to tightly couple GitRepo configuration with application targeting, reducing flexibility and increasing maintenance overhead.
Related Issues
- Similar discussion: [link if you find any related issues]
Is this behavior intentional, or would the Fleet team be open to a PR that implements the proposed filtering logic?
Solution you'd like
No response
Alternatives you've considered
No response
Anything else?
No response
Is your feature request related to a problem?
Fleet should skip deployment when no targetCustomization matches the cluster
Problem Description
When a GitRepo monitors a path containing an application, but the application's
fleet.yamlcontainstargetCustomizationsthat don't match the current cluster, Fleet still attempts to deploy the application instead of gracefully skipping it. This results in deployment errors that should not occur.Current Behavior
GitRepo Configuration:
Application fleet.yaml:
Result:
The
localcluster matches the GitRepo'stargets(it's not a harvester cluster), so Fleet creates a Bundle for it. However, thelocalcluster doesn't have theenv: proclusterlabel, so notargetCustomizationmatches. Instead of skipping the deployment, Fleet still attempts to deploy with incomplete configuration, resulting in errors like:Root Cause Analysis
Fleet has a two-tier filtering mechanism:
GitRepo.spec.targets (Tier 1): Determines which clusters should receive the Bundle
local)fleet.yaml.targetCustomizations (Tier 2): Determines which configuration to use for each cluster
env: proclusterlabelThe Problem:
When a cluster passes Tier 1 filtering (GitRepo targets) but has no matching targetCustomization in Tier 2, Fleet still attempts to deploy instead of gracefully skipping. This creates a mismatch between "this cluster should receive the Bundle" (Tier 1 ✅) and "this cluster has no configuration" (Tier 2 ❌).
Expected Behavior
When a cluster doesn't match any
targetCustomizationsin the application'sfleet.yaml, Fleet should:Steps to Reproduce
fleet-localnamespace that monitorsapps/*apps/2/10005withfleet.yamlcontaining onlytargetCustomizationsfor downstream clusters (e.g.,env: procluster)env: proclusterlabelImpact
This behavior causes several issues:
targetCustomizationsfor every possible cluster (even if not intended)pathsfilterstargets.clusterSelectorin GitRepoCurrent Workarounds
Workaround 1: Add targetCustomizations for all clusters
Pros: Works reliably
Cons: Forces deployment to clusters that may not need the application
Workaround 2: Use narrow GitRepo paths
Pros: Clean separation
Cons: Requires multiple GitRepos, more complex configuration
Proposed Solution
Implement a filtering mechanism that checks
targetCustomizationsbefore creating BundleDeployments:Environment
Additional Context
This issue is particularly problematic in multi-cluster environments where:
The current behavior forces users to tightly couple GitRepo configuration with application targeting, reducing flexibility and increasing maintenance overhead.
Related Issues
Is this behavior intentional, or would the Fleet team be open to a PR that implements the proposed filtering logic?
Solution you'd like
No response
Alternatives you've considered
No response
Anything else?
No response