Install and verify a CustomResourceDefinition (CRD) before applying any Custom Resource (CR) that uses it. Then make sure the controller or operator is running before you expect reconciliation. Otherwise Kubernetes commonly returns no matches for kind, discovery errors, or accepts an object that never becomes healthy.
The dependable sequence is CRD → established and discoverable → controller ready → Custom Resource → reconciled status.
CRD versus Custom Resource
A CRD registers a new API type with the Kubernetes API server; a CR is an instance of that type. For example, this CRD defines the Application kind:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: applications.argoproj.io
This object is a Custom Resource using the registered type:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →#1 Best Overall
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
The API server cannot create the second object until it recognizes the group, version, and kind from the first. CRDs are cluster-scoped; the resulting CRs can be namespaced or cluster-scoped according to spec.scope. See Kubernetes CRD documentation.
Why “installed” is not the same as “ready”
Registration and application readiness are separate checks:
| Stage | What it proves | Typical check |
|---|---|---|
| CRD object exists | The definition was stored | kubectl get crd |
| CRD established and discoverable | The API endpoint is available | kubectl wait, then kubectl api-resources |
| Controller ready | Software can watch and reconcile the type | kubectl rollout status and controller health |
| CR healthy | The desired state was achieved | Resource status, events, and controller logs |
Kubernetes notes that discovery can lag CRD creation by several seconds, so wait for the Established condition rather than inserting a fixed sleep. A CR can be stored before its controller exists, but it normally will have no status updates, dependent resources, or finalizer processing. The operator pattern combines a Custom Resource with a custom controller; installing only the CRD does not install that logic. See Kubernetes custom resources and controllers.
Apply raw manifests in explicit stages
- Confirm the cluster.
kubectl config current-context kubectl cluster-info - Apply the definitions.
kubectl apply -f crds/ - Wait for registration.
kubectl wait --for=condition=Established crd/applications.argoproj.io --timeout=60sFor several CRDs, repeat the wait for each name:
for crd in
applications.argoproj.io
applicationsets.argoproj.io
appprojects.argoproj.io
do
kubectl wait --for=condition=Established "crd/${crd}" --timeout=60s
done
- Verify discovery.
kubectl api-resources | grep -i application kubectl api-versions | grep argoproj.io - Install the controller or operator and wait for it.
kubectl apply -f operator/ kubectl rollout status deployment/<controller-name> -n <controller-namespace> --timeout=5m - Apply Custom Resources.
kubectl apply -f custom-resources/ - Check reconciliation.
kubectl get <resource> -A kubectl describe <resource> <name> -n <namespace> kubectl get events -A --sort-by=.lastTimestamp
kubectl wait supports resource conditions and timeouts; it is more reliable than sleep 10. See kubectl wait reference.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Helm: use the crds/ convention deliberately
A chart that follows Helm’s convention places definitions in a top-level directory:
my-chart/
├── Chart.yaml
├── values.yaml
├── crds/
│ └── widgets.example.com.yaml
└── templates/
└── widget.yaml
During helm install, Helm installs CRDs in crds/ before other chart resources when those CRDs are not already present:
helm install my-release ./my-chart
--namespace example --create-namespace
That mechanism has important boundaries:
- Files in
crds/are not templated, and values cannot normally conditionally render them. - Existing CRDs are not automatically upgraded by Helm’s standard CRD handling.
- CRDs are not automatically deleted when a release is uninstalled.
helm install --dry-runcannot fully validate a chart whose CRs depend on CRDs absent from the cluster, because discovery does not know the type yet.--skip-crdsdisables installation and should be used only when another process owns the CRDs.
helm install my-release ./my-chart --skip-crds
Choose one owner—Helm, a dedicated CRD release, Argo CD, Flux, or cluster bootstrap—for each cluster-wide CRD. Do not let multiple tools mutate the same definition. Details are in Helm’s CRD best practices.
Helm upgrades and dry runs
Do not assume helm upgrade --install updates an existing CRD from crds/. A safer split is:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
kubectl apply -f crds/
helm upgrade --install my-release ./my-chart --skip-crds
Some charts expose their own CRD value. For example, the Argo chart documents chart-specific CRD settings; that option is not a generic Helm feature. Consult the chart’s versioned documentation, such as the Argo CD chart page.
For validation, establish the CRD first, render the chart, then use server-side dry run:
kubectl apply -f crds/
kubectl wait --for=condition=Established crd/widgets.example.com --timeout=60s
helm template my-release ./chart > rendered.yaml
kubectl apply --dry-run=server -f rendered.yaml
kubectl apply -f rendered.yaml
Argo CD: express dependency with sync waves
Argo CD orders resources by phase, wave, kind, and name. Lower waves run first, and negative waves are allowed. A practical layout is:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: widgets.example.com
annotations:
argocd.argoproj.io/sync-wave: "-2"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: widget-controller
namespace: widget-system
annotations:
argocd.argoproj.io/sync-wave: "-1"
---
apiVersion: example.com/v1
kind: Widget
metadata:
name: example-widget
annotations:
argocd.argoproj.io/sync-wave: "0"
Argo CD evaluates health as it advances. If the controller wave is unhealthy, later waves can remain blocked; a successful CRD wave alone does not prove that the application works. See Argo CD sync waves.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesWhen Argo CD renders a Helm source, it installs chart CRDs by default when needed. Set skipCrds: true only if a separate Argo CD application or platform bootstrap owns them:
spec:
source:
helm:
skipCrds: true
Keep ownership unambiguous, especially when using namespace-only Argo CD installations whose CRDs may be installed separately. See Argo CD Helm integration and Argo CD installation.
Flux: gate Helm releases with dependsOn
Flux Helm Controller can separate the CRD package from the controller package and make readiness explicit:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: example-crds
namespace: platform-system
spec:
interval: 10m
chart:
spec:
chart: example-crds
sourceRef:
kind: HelmRepository
name: example
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: example-controller
namespace: platform-system
spec:
interval: 10m
dependsOn:
- name: example-crds
chart:
spec:
chart: example-controller
sourceRef:
kind: HelmRepository
name: example
The dependent release waits until the referenced release is ready. Flux also supports CRD policies such as Skip, Create, and CreateReplace; the documented default creates missing CRDs without replacing existing ones. Avoid circular dependsOn graphs, which cannot become ready. See Flux HelmRelease documentation and Flux Helm API reference.
Best Value
Kustomize and other pipeline orchestrators
Kustomize transforms and renders manifests; it is not a universal dependency scheduler. Put CRDs in a separately applied base, then apply the operator and application bases. In CI/CD, Terraform, or Pulumi, model the same dependency graph explicitly and wait for establishment and controller rollout. A directory containing CRDs and CRs together may fail when a tool performs discovery or server-side validation before applying anything.
Safely handle existing CRDs and upgrades
Before changing an installed definition, inspect it:
kubectl get crd widgets.example.com -o yaml
kubectl describe crd widgets.example.com
Compare the API group, served and storage versions, scope, names and pluralization, OpenAPI schema, conversion strategy, printer columns, and webhook configuration. CRDs are persistent APIs, not disposable chart metadata. Kubernetes stores objects using the configured storage version; multi-version APIs may require conversion and data migration. Read the operator’s upgrade notes, back up representative CRs, apply vendor-provided CRD manifests, wait for Established, verify discovery and schema behavior, then upgrade the controller and validate statuses. If conversion webhooks are used, confirm their Service, certificates, and network path remain healthy. See Kubernetes CRD versioning.
Avoid kubectl replace --force on a live CRD unless the vendor explicitly requires it. Deleting a CRD can affect all of its Custom Resources across the cluster and may be destructive.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Quick Recap
Troubleshoot common failures
| Symptom | Likely causes | Checks |
|---|---|---|
no matches for kind |
Missing CRD, wrong group/version/kind, wrong context, or discovery delay | kubectl config current-context; kubectl get crd; kubectl api-resources | grep -i <kind>; kubectl api-versions | grep <group> |
| CRD exists but CR creation fails | Endpoint not established, wrong served version or plural, terminating CRD, stale discovery, unavailable admission webhook | kubectl get crd <name> -o yaml; kubectl get --raw /apis/<group>/<version>; inspect conditions and webhook events |
| CR accepted but does nothing | Controller missing or crash-looping, RBAC denial, namespace/watch-scope mismatch, missing dependency | kubectl get pods -n <operator-namespace>; kubectl logs deployment/<controller> -n <operator-namespace>; describe the CR and inspect events |
| Argo CD sync or comparison is blocked | Incorrect waves, conflicting CRD owner, skipCrds mismatch, unhealthy earlier wave |
Review annotations, application boundaries, health status, and ownership |
| Works in one environment only | CRD installed in a different cluster or context | kubectl config current-context; kubectl cluster-info |
Deployment checklist
- Correct kubeconfig context and cluster confirmed.
- CRD manifest applied by its single designated owner.
Establishedcondition is true.- API discovery lists the expected resource and version.
- Controller or operator is deployed, healthy, and authorized.
- Custom Resource is applied only after those checks.
- Resource status, events, and logs show reconciliation.
- CRD upgrade ownership, backups, served/storage versions, and conversion-webhook checks are documented.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




