kubeconform -schema-location: Custom and CRD Schemas
kubeconform -schema-location sets a templated URL or directory where schemas are fetched, used to validate CRDs and to run without internet access.
Out of the box kubeconform pulls schemas from a public repo. -schema-location redirects it to your own mirror or to converted CRD schemas, which is required for air-gapped runners and custom resources.
What it does
-schema-location accepts default (the built-in upstream), a base URL, or a directory, and supports template variables like {{ .ResourceKind }}, {{ .ResourceAPIVersion }}, {{ .Group }}, and {{ .KubernetesVersion }}. You can pass it multiple times to chain locations, and it is how you teach kubeconform about CRDs.
Common usage
kubeconform \
-schema-location default \
-schema-location 'schemas/{{ .ResourceKind }}-{{ .ResourceAPIVersion }}.json' \
manifests/
# offline: only a local mirror
kubeconform -schema-location './crdschemas/{{ .ResourceKind }}.json' cr.yamlOptions
| Value | What it does |
|---|---|
| default | The built-in upstream schema source |
| <base-url-or-dir> | Custom location with template variables |
| {{ .ResourceKind }} | Template var for the kind, e.g. Deployment |
| {{ .ResourceAPIVersion }} | Template var for the version, e.g. v1 |
| {{ .KubernetesVersion }} | Template var for the target k8s version |
In CI
Generate CRD schemas with the openapi2jsonschema tooling, commit them, and point a second -schema-location at the directory so custom resources validate. Keep default first so core kinds still resolve.
Common errors in CI
could not find schema for <Kind> after adding a location usually means the template path does not match the generated filename; print one filename and align the template. A 404 against a custom URL means the mirror lacks that kind/version. With -ignore-missing-schemas these become skips rather than failures.
Using this in CI
A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods
# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info
# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes