Prerequisites: kubernetes
A Kubernetes manifest is a serialized Kubernetes object. YAML is only the notation used to write it. The useful mental model is not “YAML makes infrastructure” but “this document tells the Kubernetes API which object should exist and what state that object should hold.” The API validates it, stores it, and controllers act on it.
The Devata Overview dashboard begins with this shape:
apiVersion: v1
kind: ConfigMap
metadata:
name: grafana-dashboard-devata-overview
namespace: monitoring
labels:
grafana_dashboard: "1"
annotations:
grafana_folder: /tmp/dashboards/Devata
data:
devata-overview.json: |-
{
"title": "Devata Overview"
}Reading the document from the outside in
| Field | Question it answers | Devata answer |
|---|---|---|
apiVersion | Which API schema understands this object? | Core Kubernetes API, version v1 |
kind | What type of object is this? | ConfigMap |
metadata.name | What is its stable identity? | grafana-dashboard-devata-overview |
metadata.namespace | Which namespace owns it? | monitoring |
metadata.labels | Which machines or controllers should select it? | The Grafana dashboard sidecar |
metadata.annotations | What extra instruction travels with it? | The destination folder path |
data | What non-secret configuration does it carry? | A key whose value is dashboard JSON |
Not every Kubernetes object has a spec. Workload objects such as Deployments do because they describe a controller-managed desired state. A ConfigMap stores keys under data or binaryData, so the dashboard manifest correctly has no spec.
YAML details that matter here
Indentation expresses nesting. grafana_dashboard belongs to labels because it is indented beneath it. Moving it one level left would change the object, not merely its appearance.
"1" is quoted because Kubernetes label values are strings. Without the quotes a YAML parser may interpret 1 as a number, which does not match the API schema for labels.
|- starts a literal block scalar. It means “treat the following indented lines as one string, preserve their line breaks, and remove the final newline.” The JSON is therefore not a second Kubernetes object. To the ConfigMap it is one long string stored under the key devata-overview.json. Later, the sidecar turns that key into a file with the same name.
Labels and annotations are both metadata, but they carry different contracts here:
- the label is a selector:
grafana_dashboard=1makes the object discoverable; - the annotation is an instruction:
grafana_foldertells the sidecar where to write it.
That distinction is why changing either field can leave the ConfigMap healthy in Kubernetes while making the dashboard disappear from Grafana.
Validate before reconciliation
From the lab repository:
kubectl apply --dry-run=server \
-f kubernetes/infra/observability/kps/resources/devata-overview-dashboard.yaml
kubectl diff \
-f kubernetes/infra/observability/kps/resources/devata-overview-dashboard.yamlThe server-side dry run checks the document against the live API without storing it. kubectl diff compares the file with the live object. In this homelab the normal deployment path is still Git and application, not a manual kubectl apply; these commands are preflight tools.
Official reference: Kubernetes objects.