Logo Codebaker
EN
Blog/DevOps

KYAML in Kubernetes 1.37: guida per chi inizia e per chi è in produzione da anni

16 Settembre 2026 · di Luca Vitali

A cura del team DevOps di Codebaker

Con Kubernetes 1.37 “Garhwal”, rilasciato il 26 agosto 2026, KYAML è diventato Stable. È una delle novità più citate della release e anche una delle più fraintese: la si sente descrivere come “il nuovo formato che sostituisce YAML”, e non lo è.

Abbiamo diviso l'articolo in due parti.

Le due parti sono indipendenti: chi ha già esperienza può saltare direttamente alla seconda.

Parte 1: Primi passi con KYAML

Cos'è un manifest Kubernetes

In Kubernetes non si dice al cluster cosa fare passo per passo. Si descrive lo stato desiderato: “voglio tre copie di questa applicazione, raggiungibili su questa porta, con questa quantità di memoria”. Questa descrizione è un manifest, un file di testo che si invia al cluster con un comando come:

kubectl apply -f mia-applicazione.yaml

Da quel momento Kubernetes lavora di continuo per far coincidere la realtà con quanto scritto nel file.

Il formato storicamente usato per questi file è YAML, un linguaggio pensato per essere leggibile da una persona. Ecco un manifest minimo che crea un Pod, cioè l'unità più piccola che Kubernetes esegue:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: demo
spec:
  containers:
    - name: nginx
      image: nginx:1.20

Le regole di base sono tre:

Dove YAML ti tradisce

YAML è comodo, ma lascia molta libertà. Chi inizia con Kubernetes finisce quasi sempre per inciampare negli stessi tre problemi.

Problema 1: due spazi di troppo cambiano il significato

Nel YAML tradizionale la struttura dipende solo dagli spazi. Guarda questo esempio:

spec:
  containers:
    - name: app
      image: registry.example.com/app:1.4
  resources:
    limits:
      memory: 512Mi

Volevamo limitare la memoria del container, ma resources è indentato allo stesso livello di containers e quindi finisce dentro spec, non dentro il container. Il file è sintatticamente corretto: nessun errore di “formato sbagliato”. Il limite di memoria, semplicemente, non viene applicato dove pensavi. In questo caso fortunato kubectl segnalerà un campo sconosciuto; in altri casi l'errore passa del tutto inosservato.

Problema 2: il testo che diventa altro

In YAML le virgolette attorno ai testi sono facoltative. Il parser prova a indovinare il tipo del valore, e a volte sbaglia rispetto alle tue intenzioni:

country: NO        # letto come "falso", non come il codice della Norvegia
feature: on        # letto come "vero"
version: 1.20      # letto come il numero 1.2: lo zero finale sparisce

Il primo caso è talmente famoso da avere un nome: il “Norway problem”.

Problema 3: JSON non è la via di fuga

Kubernetes accetta anche JSON, che non ha nessuno di questi problemi. Però JSON non ammette commenti, pretende le virgolette su ogni chiave e va in errore se lasci una virgola dopo l'ultimo elemento. Per file che devi scrivere e leggere a mano è scomodo.

KYAML: YAML con regole più severe

KYAML (Kubernetes YAML) non è un nuovo linguaggio. È YAML scritto seguendo sempre le stesse regole:

  1. gli oggetti stanno sempre tra parentesi graffe { };
  2. le liste stanno sempre tra parentesi quadre [ ];
  3. i valori di testo stanno sempre tra virgolette doppie " ";
  4. ogni elemento termina con una virgola, anche l'ultimo;
  5. il file inizia con ---, un marcatore standard di YAML che indica l'inizio di un documento.

Lo stesso Pod di prima, in KYAML:

---
{
  apiVersion: "v1",
  kind: "Pod",
  metadata: {
    name: "my-pod",
    labels: {
      app: "demo",
    },
  },
  spec: {
    containers: [{
      name: "nginx",
      image: "nginx:1.20",
    }],
  },
}

Cosa cambia in pratica:

Se ti sembra JSON, hai ragione: è molto simile. Del resto, tecnicamente, un file JSON è già YAML valido. KYAML sta a metà strada: più rigoroso del YAML classico, più comodo di JSON.

Le domande che ci fanno più spesso

Devo rinominare i file in .kyaml?

No. I file restano .yaml. Non esiste un'estensione dedicata.

Devo convertire i miei manifest esistenti?

No. KYAML è YAML, e il YAML tradizionale continua a funzionare esattamente come prima. Il progetto Kubernetes non ha piani per renderlo il formato predefinito.

Il cluster deve essere aggiornato alla 1.37 per leggere KYAML?

No. KYAML riguarda solo il lato client. Qualsiasi versione di kubectl e qualsiasi cluster leggono un file KYAML, perché è YAML valido. Serve una versione recente di kubectl solo per generare KYAML.

Allora cosa è cambiato con la 1.37?

Il comando kubectl ... -o kyaml è ora stabile e sempre disponibile, senza impostazioni particolari.

I primi comandi da provare

Vedere una risorsa esistente in KYAML:

kubectl get deployment my-app -o kyaml

Generare lo scheletro di un nuovo Deployment senza toccare il cluster, direttamente in KYAML, e salvarlo su file:

kubectl create deployment web --image=nginx:1.27 --replicas=2 \
  --dry-run=client -o kyaml > web.yaml

Applicarlo:

kubectl apply -f web.yaml

Se preferisci vedere sempre KYAML quando usi kubectl get, puoi impostarlo come preferenza personale:

kubectl kuberc set --section defaults --command get --option output=kyaml

La preferenza vale solo per il tuo computer: non tocca il cluster né i colleghi.

In sintesi per chi inizia

YAML tradizionaleKYAML
Cosa definisce la strutturaGli spaziLe parentesi {} e []
Virgolette sui testiFacoltativeObbligatorie
Rischio che NO diventi “falso”No
Commenti
Estensione del file.yaml.yaml
Funziona con qualsiasi kubectl

Il nostro consiglio: impara a leggere entrambi. Quasi tutta la documentazione e gli esempi online sono in YAML tradizionale, ma usare -o kyaml quando esplori un cluster ti abitua a vedere la struttura in modo esplicito ed evita una classe intera di errori.

Parte 2: Approfondimento per chi è in produzione

Questa parte dà per scontata la familiarità con kubectl, Helm, Kustomize e flussi GitOps. L'obiettivo è capire come KYAML è costruito, dove aiuta davvero e dove può creare attrito.

Inquadramento: cosa è e cosa non è

KYAML è definito dalla KEP-5295 (SIG CLI, autori Tim Hockin e Benjamin Elder), con milestone Alpha in 1.34, Beta in 1.35 e Stable in 1.37. Alcuni punti della KEP vanno tenuti presenti:

Evoluzione del gate

VersioneStatoComportamento
1.34Alpha-o kyaml disponibile solo con KUBECTL_KYAML=true
1.35BetaAbilitato di default, disattivabile con KUBECTL_KYAML=false
1.36Betakubectl kuberc esce dal prefisso alpha
1.37StableVariabile d'ambiente rimossa, -o kyaml sempre disponibile

Se avete script che esportano KUBECTL_KYAML, con client 1.37 la variabile è semplicemente ignorata e potete eliminarla.

Perché YAML è ambiguo proprio nell'ecosistema Kubernetes

La libreria usata da Kubernetes è sigs.k8s.io/yaml, che dalla 1.33 include fork di go-yaml v2 e v3. Il percorso di decodifica di un manifest è, semplificando:

YAML  ──(sigs.k8s.io/yaml)──▶  JSON  ──(decoder strict)──▶  oggetto Go tipizzato

La risoluzione implicita dei tipi segue le regole storiche di YAML 1.1. La KEP elenca esplicitamente i casi più insidiosi:

Valore non quotatoInterpretato come
NO, no, N, YES, yes, Y, On, Offbooleano
_42, _4_2_numero
11:00numero in base 60
1.20float 1.2
0755intero ottale

Quando l'errore è rumoroso e quando è silenzioso

Sui campi tipizzati delle API core, la coercizione di solito fallisce in modo esplicito, perché il decoder strict rifiuta un booleano dove si aspetta una stringa:

env:
  - name: PORT
    value: 8080

Questo produce un errore del tipo cannot unmarshal number into Go struct field EnvVar...value of type string. Fastidioso, ma visibile. Lo stesso accade con label e annotation, che sono map[string]string.

Il problema diventa silenzioso in tre situazioni tipiche:

  1. values di Helm. country: NO in values.yaml diventa false prima ancora che il template venga renderizzato. Se il template fa {{ .Values.country | quote }} il manifest finale conterrà "false", perfettamente valido e perfettamente sbagliato;
  2. CRD con schema permissivo. Campi con x-kubernetes-preserve-unknown-fields: true o tipi object generici accettano qualsiasi tipo senza protestare;
  3. payload annidati in stringhe. Configurazioni applicative incluse in una ConfigMap e poi parsate dall'applicazione con un parser YAML diverso, con regole diverse.

Il caso IntOrString

KYAML quota le stringhe, non tutto. I campi IntOrString come targetPort restano semanticamente diversi a seconda del tipo:

ports: [{
  port: 80,
  targetPort: 8080,     # porta numerica
}, {
  port: 443,
  targetPort: "https",  # porta nominata del container
}],

Scrivere targetPort: "8080" non è equivalente a targetPort: 8080: la stringa viene trattata come nome di porta e fallisce la validazione. KYAML rende il tipo esplicito, ma non vi dispensa dal conoscerlo.

Le Quantity

Le resource.Quantity si serializzano sempre come stringa. Anche se scrivete cpu: 1, l'output KYAML di un oggetto letto dal cluster sarà cpu: "1". Non è una differenza semantica e non va “corretta”.

La pipeline di rendering

Per garantire la massima fedeltà a JSON, KYAML non serializza direttamente gli oggetti Go:

oggetto Go ──▶ JSON ──▶ AST (go-yaml v3) ──▶ KYAML

Il passaggio intermedio da JSON ha conseguenze precise.

I tag json governano tutto. omitempty, omitzero, rinomine dei campi: tutto è rispettato perché passa dal marshaller JSON. I tag yaml sono ignorati, come già avviene con -o yaml. I tipi che implementano json.Marshaler vengono resi tramite quello; MarshalYAML() non viene usato.

Le chiavi delle mappe devono essere stringhe. YAML ammette chiavi composte (liste, mappe) o non stringa; JSON no. Un YAML con chiavi di questo tipo non è convertibile in KYAML e la conversione fallisce. In altre parole: ogni KYAML è YAML, ma non ogni YAML può diventare KYAML.

Le chiavi delle mappe sono ordinate, e l'ordine dei campi delle struct non è garantito. kubectl converte tutto in unstructured internamente e perde l'ordine di dichiarazione. Chi confronta output testuali deve tenerne conto.

Anchor, alias e tag vengono appiattiti. Anchor e alias vengono materializzati, i tag espliciti (!!str, !!int) e globali (%TAG) possono essere semplificati, a condizione che l'oggetto risultante sia identico. Se usate anchor per deduplicare blocchi in file scritti a mano, la conversione li espande.

Puntatori e interfacce sono resi come null o come il valore effettivo. Tipi non gestiti producono un errore esplicito invece di un output ambiguo.

Regole di formattazione nel dettaglio

Scalari

Chiavi

Le chiavi non sono quotate, salvo quando non sono “ovviamente stringhe” o coincidono con parole ambigue come no. Le chiavi di label con prefisso (app.kubernetes.io/name) rientrano nei casi gestiti. La KEP non garantisce uniformità: nello stesso oggetto possono convivere chiavi quotate e non quotate.

labels: {
  app: "hostnames",
  "kubernetes.io/service-name": "hostnames",
  pod-template-hash: "77b655d8d",
},

Virgole e parentesi

L'intestazione ---

Serve a distinguere KYAML da un JSON malformato, dato che entrambi iniziano con {. Secondo la KEP, i client dalla 1.33 in poi gestiscono KYAML anche senza intestazione; le versioni precedenti ne hanno bisogno. Se avete ambienti con kubectl datati in pipeline, non togliete l'intestazione.

Documenti multipli

Un multi-documento KYAML è un normale multi-documento YAML: più blocchi { ... } separati da ---.

Stringhe multilinea

Il flow style di YAML non ammette i blocchi letterali | e >. KYAML usa quindi stringhe tra doppi apici con flow folding (backslash a fine riga, che elimina il ritorno a capo e gli spazi iniziali della riga successiva), \n espliciti per i veri a capo e \ per preservare gli spazi iniziali.

Una ConfigMap in YAML tradizionale:

data:
  nginx.conf: |
    server {
      listen 80;
      location / {
        return 200 'ok';
      }
    }

Lo stesso contenuto nella resa KYAML:

data: {
  "nginx.conf": "\
     server {\n\
    \  listen 80;\n\
    \  location / {\n\
    \    return 200 'ok';\n\
    \  }\n\
     }\n\
    ",
},

Qualche osservazione:

Commenti: il punto debole

KYAML ammette commenti, ma la loro conservazione durante la conversione dipende da go-yaml, che ha limiti noti nella gestione dei commenti. La KEP lo dichiara apertamente:

Conseguenza pratica: prima di convertire un repository, isolate i file con commenti significativi (spiegazioni di tuning, workaround, riferimenti a ticket) e verificateli a mano dopo la conversione.

Stabilità dell'output

La KEP garantisce idempotenza a parità di versione: l'output del formatter, ripassato allo stesso formatter, non cambia. Non garantisce stabilità byte per byte tra versioni diverse: la resa potrà essere affinata in futuro.

Implicazioni:

KYAML e Helm

Qui KYAML dà il vantaggio più concreto, ma con un'avvertenza importante.

Il vantaggio: niente più nindent

In block style, iniettare un blocco richiede di gestire l'indentazione dal template:

spec:
  template:
    spec:
      containers:
        - name: app
          resources:
            {{- toYaml .Values.resources | nindent 12 }}

Poiché JSON è YAML flow valido, in un template KYAML si può iniettare direttamente l'output di toJson, senza preoccuparsi degli spazi:

spec: {
  template: {
    spec: {
      containers: [{
        name: "app",
        image: {{ printf "%s:%s" .Values.image.repository .Values.image.tag | toJson }},
        resources: {{ toJson .Values.resources }},
      }],
    },
  },
},

Due dettagli:

env: [
{{- range $k, $v := .Values.env }}
  { name: {{ $k | toJson }}, value: {{ $v | toJson }} },
{{- end }}
],

L'avvertenza: non mescolate gli stili

La KEP lo dice esplicitamente: patchare testualmente KYAML con frammenti block style, come succede in un chart che include helper esistenti, non funziona in modo affidabile. Un chart va scritto interamente in uno stile o nell'altro. Includere helper di terze parti che emettono block style dentro un template KYAML è la ricetta per errori di parsing difficili da leggere.

E ricordate che KYAML non protegge i values: il Norway problem colpisce values.yaml prima del rendering. Se il chart accetta stringhe ambigue, quotatele nei values o validatele con values.schema.json.

KYAML e Kustomize

kustomize build e kubectl kustomize producono block style. Kustomize legge senza problemi base e patch in KYAML, ma l'output resta tradizionale. Se volete l'output finale in KYAML, ad esempio per archiviare i manifest renderizzati, serve un passaggio di formattazione successivo in pipeline.

Attenzione anche alle patch strategic merge o JSON 6902 scritte a mano: sono YAML e funzionano in qualsiasi stile, ma è bene mantenere uno stile coerente con la base per non confondere chi le rivede.

KYAML e GitOps

Argo CD e Flux confrontano oggetti, non testo: lo stato desiderato viene parsato prima del confronto con lo stato live. Convertire un manifest da block style a KYAML non genera drift né sincronizzazioni, purché l'oggetto risultante sia identico.

Genera però un diff Git enorme. Buone pratiche:

  1. fate la conversione in un commit dedicato, senza modifiche funzionali;
  2. aggiungete l'hash di quel commit a .git-blame-ignore-revs, così git blame continua a puntare alle modifiche reali;
  3. verificate l'equivalenza prima del merge.

Verificare l'equivalenza

Offline, confrontando la forma parsata con yq (v4), con chiavi ordinate:

diff \
  <(git show HEAD~1:deploy/app.yaml | yq -o=json 'sort_keys(..)') \
  <(yq -o=json 'sort_keys(..)' deploy/app.yaml)

Online, contro il cluster, con kubectl diff, che deve restituire output vuoto:

kubectl diff -f deploy/

Il secondo controllo è più forte perché tiene conto anche di defaulting e validazione server-side.

Esportare risorse dal cluster

kubectl get -o kyaml restituisce l'oggetto live, con status, uid, resourceVersion, creationTimestamp e i campi popolati dai default. I managedFields sono nascosti per impostazione predefinita. Prima di versionare un oggetto esportato, rimuovete i campi runtime, a mano o con un plugin come kubectl-neat, e poi riformattate.

Per creare scheletri puliti, il percorso migliore resta --dry-run=client:

kubectl create service clusterip api --tcp=80:8080 \
  --dry-run=client -o kyaml

Tooling di conversione

yamlfmt di sigs.k8s.io/yaml

È il tool del progetto Kubernetes, usato anche nel verifier CI del repository kubernetes/kubernetes:

go install sigs.k8s.io/yaml/yamlfmt@latest

Accetta un file o una directory e scrive su stdout, quindi l'output va rediretto. La KEP prevede flag per scegliere tra stile “convenzionale” e KYAML, così che ogni file possa essere verificato rispetto allo stile previsto; consultate --help della versione installata per la sintassi esatta.

google/yamlfmt

Dalla versione 0.21.0 include un formatter dedicato a KYAML. È la scelta più comoda per pre-commit hook e controlli in CI, perché supporta già la modalità di verifica senza scrittura e la configurazione per percorso.

yq

Legge KYAML senza problemi, essendo YAML. Utile per tornare al block style quando serve (yq -P), per interrogare i file e per i confronti di equivalenza visti sopra.

Editor e schema

Il language server YAML degli editor più diffusi lavora sul documento parsato, quindi validazione tramite JSON Schema e autocompletamento continuano a funzionare anche sui file KYAML.

Compatibilità e version skew

ScenarioEsito
File KYAML applicato con qualsiasi kubectlFunziona (è YAML)
File KYAML senza --- con kubectl precedente alla 1.33Rischio di errata identificazione come JSON
-o kyaml con client 1.34 senza KUBECTL_KYAML=trueFormato non disponibile
-o kyaml con client 1.35 o 1.36Disponibile, disattivabile via variabile
-o kyaml con client 1.37Sempre disponibile
Output KYAML confrontato byte per byte tra versioni diverseNon garantito

La KEP raccomanda di non usare -o kyaml nelle automazioni finché tutti i client coinvolti non sono aggiornati. Con la 1.37 GA il vincolo si riduce a verificare la versione del kubectl presente nelle immagini dei runner CI.

Limiti da mettere in conto

Strategia di adozione consigliata

Il nostro consiglio, per team che gestiscono più cluster e più repository:

  1. 1

    Output prima di input. Adottate subito -o kyaml in script e automazioni che leggono l'output di kubectl: è il caso d'uso a rischio zero e beneficio immediato.

  2. 2

    Nuovi repository e nuovi chart in KYAML, con formatter in modalità verifica nei pre-commit hook e in CI, versione del formatter fissata.

  3. 3

    Repository esistenti: solo se c'è un motivo. Template Helm fragili sull'indentazione o storico di incidenti da coercizione giustificano la conversione. Altrimenti il costo in diff e revisione supera il beneficio.

  4. 4

    Eccezioni esplicite. ConfigMap con file lunghi, manifest di terze parti vendorizzati e chart upstream restano in block style. Documentatelo nel README del repository, così nessuno li “corregge”.

  5. 5

    Validazione indipendente dal formato, sempre: schema, dry-run server-side e policy.

KYAML non rende YAML obsoleto. Toglie di mezzo una categoria di errori che con Kubernetes non avremmo mai dovuto avere, senza chiedere di buttare via nulla di quello che già funziona. Adottarlo con giudizio, partendo da dove rende di più, è la scelta più sensata.

Luca Vitali

Riferimenti

Vuoi un cluster Kubernetes gestito come si deve?

Progettiamo e gestiamo infrastrutture Kubernetes su cloud europeo e on-premise, con manifest puliti, GitOps, osservabilità e backup. Se vuoi parlarne con chi lo fa ogni giorno, scrivici.

Scopri Kubernetes & Docker