YAML 驗證工具
在你的瀏覽器中解析,不會傳送到任何地方,因為 manifest 常帶有密鑰、registry 與內部主機名稱。重複的鍵與以 Tab 縮排會被視為錯誤而非默默接受,多份文件的串流則會轉成 JSON 陣列。
您輸入的內容不會被儲存、記錄或分享。
貼上 YAML 即可檢查語法並轉成 JSON,切換方向也能把 JSON 轉回 YAML。錯誤會指出確切的行與列。所有解析都在瀏覽器中完成,因此含有密鑰的 manifest 不會被上傳。
使用方式
- 將 YAML 貼進輸入欄位。
- 看下方的結果:有效,或是錯誤原因與所在的行、列。
- 複製 JSON,或切換到「JSON 轉 YAML」做反向轉換。
為什麼 YAML 比看起來難
YAML 的魅力在於簡單的文件幾乎不需要語法。代價是解析器必須推斷很多事情,而大多數 YAML 問題,都來自它推斷出的結果和你的本意不同。
縮排就是結構,而且必須使用空格。Tab 從來都不合法,所以設定成插入 Tab 的編輯器,會產生看起來毫無問題的錯誤。縮排也是相對的而非固定寬度,所以一個區塊縮排四格、它的兄弟縮排兩格,這是真正的錯誤,而不只是風格不一致。
此外,同樣的資料可以有好幾種寫法:區塊樣式與流式樣式、有引號與沒引號的純量、三種寫 null 的方式。這些平常都無所謂,直到某個值剛好落在它們之間的縫隙,那時就非常要緊了。
隱式型別的陷阱
沒有引號的純量是依照外觀來決定型別的,而這些外觀和人們當作字串寫的東西有所重疊。
版本號是經典案例。沒有引號的 1.10 是浮點數,而浮點數沒有尾端的零,於是變成 1.1,你鎖定的相依套件版本就悄悄指向別處。開頭有零的值則有反方向的同樣問題:在 YAML 1.2 中 0755 是數字 755,而不是八進位的檔案權限,必須寫成 0o755。電話號碼、帳號、ID 這類長串數字會失去開頭的零,超過十六位數還會失去精度。
最有名的是布林值。YAML 1.1 把 yes、no、on、off、y、n 都當作布林值,這就是「挪威問題」的由來:包含 NO(挪威)的國家清單,會變成包含 false 的清單。YAML 1.2 core 將布林值縮減為只有 true 和 false,本工具也遵循此規範;但實際上仍有許多軟體使用 1.1 解析器,例如 Ruby 的 Psych 與舊版 PyYAML。所以安全的習慣是:凡是想當字串的值,都加上引號。
另外值得知道:null 可以寫成 null、~,或什麼都不寫,所以值為空的鍵是 null,而不是空字串。在 YAML 1.1 中,22:22 會被解析成六十進位數字,而不是時間。
多行字串
兩種區塊純量指示符幾乎涵蓋所有情況,而選錯是設定檔壞掉的常見原因。
直線符號(|)會完全保留你寫的換行。Shell 腳本、憑證、內嵌的設定檔,或任何行結構有意義的內容,都應該用它。大於符號(>)則會摺疊:單一換行變成空格,空行變成換行,適合想在原始檔中換行、但值本身不換行的長段文字。
兩者都可以加上控制結尾換行的截斷指示符。不加時保留一個換行,減號(-)刪除全部,加號(+)全部保留。當結尾換行會讓接收端出錯時(例如權杖、金鑰、命令參數)就用減號;需要完整保留空白時則用加號。
內容相對於鍵縮排,而這段縮排會從值中移除。縮排比其他行更深的行會保留多出來的空格,這讓嵌在設定清單裡的腳本也能維持自己的結構。
錨點、別名與合併鍵
錨點用 & 標記一個節點,別名用 * 參照它,讓文件可以重複使用前面定義過的值。在 CI 設定或 compose 檔案中,這能消除幾乎相同的工作或服務之間的重複,也是選擇 YAML 而非 JSON 的少數真正好理由之一。
寫成 <<: *base 的合併鍵更進一步,會把錨點對應表的鍵併入目前的對應表,讓你只覆寫其中幾個。要注意這不屬於 YAML 1.2 core,而是另一份規格;多數解析器有實作,但也有少數沒有,所以並非處處安全。
轉換成 JSON 時,這些必然全部消失。別名會在轉換前展開成實際的值,所以被參照三次的錨點會變成三份資料副本,而不是三個參照。註解也會消失,因為 JSON 沒有註解。因此把大量使用錨點的設定轉成 JSON 再轉回來,得到的文件意義相同但長得多;就可讀性而言,這是一條單行道。
引號:什麼時候要用,該用哪一種
沒有加引號的純量會依照它的外觀被判定型別,所以加引號就是你在說「這是文字」。單引號裡的內容完全照字面解讀,唯一的例外是連續兩個單引號代表一個撇號;它不處理任何逸出序列,因此 'C:\path\to' 就是那串字元本身。雙引號會處理逸出序列,所以 \n 會變成換行,而要表示一個反斜線字元本身就得寫兩個。
能避開大部分麻煩的原則是:預設用單引號,只有需要逸出序列時才用雙引號,並且把任何可能被讀成別種型別的東西都加上引號。這涵蓋了版本號、整串都是數字的值、以零開頭的值,以及 yes、no、on、off 這幾個字。
有幾個字元只要出現在值裡就強制需要引號:後面跟著空白的冒號、前面有空白的井號,以及開頭的 &、*、!、%、@ 或反引號。以大括號或方括號開頭的值會被當成流式樣式的開始,所以像 {{ .Values.name }} 這樣的 Jinja 或 Helm 樣板一定要加引號,否則剖析器會把它讀成巢狀的對應。
讓 Kubernetes 與 CI 檔案出錯的那幾個地雷
第一個是清單項目的縮排。某個鍵底下的序列,可以縮排,也可以和鍵對齊,兩種都合法,但同一個序列裡的各個項目必須彼此一致。當一份檔案經過好幾個人編輯而混用了兩種寫法,產生的錯誤所指出的行號往往和真正的問題差得很遠。
第二個是多文件檔案。三個連字號用來分隔文件,只讀取第一份的工具會默默忽略分隔線之後的所有內容——這就是為什麼一份 Kubernetes manifest 只套用了 Deployment 卻沒有套用 Service。kubectl 能處理多份文件;但許多使用語言預設載入函式的指令碼做不到,得改用 load-all 那個版本。
第三個是空值。冒號後面什麼都沒寫的鍵,其值是 null,不是空字串,也不是空的對應,所以一段被註解掉卻留著鍵名的設定,在使用端期待一個物件的位置上得到的會是 null。在所有建構於 YAML 之上的樣板系統中,null 和空字串的行為都不一樣。
用結構描述驗證 YAML
剖析器告訴你的是這份檔案語法正確。結構描述告訴你的是內容說得通,而對任何牽涉到營運的東西來說,後者才是更有用的檢查。由於 YAML 對應到與 JSON 相同的資料模型,JSON Schema 可以直接套用在它上面,這正是大多數編輯器在 Kubernetes manifest 或 GitHub Actions 檔案裡提供自動完成與即時錯誤提示所依靠的機制。
在流程中,專用的驗證工具比通用結構描述走得更遠:kubeconform 會依目標版本的 Kubernetes API 結構描述檢查 manifest,yamllint 會強制風格一致並揪出縮排與重複鍵的問題,而大多數 CI 系統也都能讓你在推送前於本機驗證自己的設定檔。
重複鍵值得單獨提出來講。大多數剖析器會接受它並保留最後一個,默默丟掉前面的——所以在一份很長的檔案裡設定了兩次的值,看起來就像被忽略了。Linter 會標示出來,語言的執行環境通常不會。
在 YAML 之上套樣板,為什麼會這麼痛
Helm、Ansible 和大多數 CI 系統都用樣板產生 YAML,也就是用一套文字樣板語言去產出一種對空白敏感的格式。結果完全可以預料:插進去的值縮排錯了、多行字串把一個區塊壓平了、某個條件式刪掉一行之後留下一個懸空的鍵。
有兩個習慣能減輕痛苦。第一,先算繪再套用——執行 helm template 或等效的 dry run——並且把輸出當成 YAML 來讀,而不是去相信樣板。第二,使用工具本身提供的縮排輔助函式,例如 Helm 的 nindent,而不是在樣板裡用手數空格。
更根本的替代做法,是從資料而不是從文字產生 YAML:用一種真正的程式語言建構出資料結構再序列化,讓縮排變成序列化器要煩惱的事。CDK8s、Pulumi,以及 CUE 和 Dhall 這類設定語言存在的意義正是如此,這種做法可以整類地消滅一種失敗模式。
機密、註解,以及轉換之後還留下什麼
YAML 設定檔是機密資訊最常流進版本庫的地方,通常是某個人本來打算在提交前刪掉的值。要讓它們不進來是工作流程上的決定——改用環境變數、機密管理服務,或用 SOPS、sealed secrets 之類的加密檔案——而且值得掃描版本庫一次,看看裡面已經有些什麼,同時記得只要曾經提交過,歷史紀錄就會一直留著。
註解是另一個值得保護的東西。對許多設定檔來說,註解是它們僅有的文件,而註解無法在轉成 JSON 之後倖存,也撐不過一支載入檔案再重新序列化的程式跑一趟。能夠就地編輯 YAML 又保留註解的工具是存在的——Python 的 ruamel.yaml,以及用於命令列編輯的 yq——要用指令碼去改一份由人維護的檔案,選它們才對。
錨點也是一樣。轉成 JSON 時,每個別名都會被展開成一份副本,所以圍繞共用區塊建構起來的設定會變得長很多,而且當初讓它易於維護的那個結構也不見了。對機器來說意思完全相同,對下一個要編輯它的人來說就差多了。
常見問題
- 把 Kubernetes manifest 貼在這裡安全嗎?
- 安全。解析器在你的瀏覽器中執行,文件不會被送到任何地方,這正是這個工具存在、而不是叫你去用伺服器端工具的理由。Manifest 經常帶有 image registry、內部主機名稱與 base64 密鑰,這些都不會離開你的電腦,既不會給本站,也不會給 AI 助理。
- 為什麼版本號從 1.10 變成了 1.1?
- 因為沒有加引號的 1.10 是浮點數,而浮點數沒有結尾的零。這是實務上最常見的 YAML 陷阱,本工具不會替你掩蓋它:把值寫成 "1.10" 就會保持字串。任何看起來像數字但其實不是的值都一樣,例如組建編號、電話號碼,以及開頭有零的識別碼。
- NO 還會變成 false 嗎?也就是所謂的挪威問題。
- 不會了。那是 YAML 1.1 的行為,當時 NO、yes、on、off 全都是布林值。本工具遵循 YAML 1.2 core,這些會保持字串。開頭的零也變了:0755 現在是十進位的 755,不是八進位;若你要表示檔案權限,請寫 0o755。
- 多份文件的檔案會怎麼處理?
- 以 --- 分隔的串流會轉成 JSON 陣列,一份文件一個元素,這是用 JSON 表示多個根文件唯一誠實的方式。若結尾的 --- 後面沒有內容,會被忽略而不是變成 null 元素,因為幾乎每個 manifest 產生器都會輸出一個。
- 為什麼編輯器可以,但這裡不接受重複的鍵?
- 因為接受它的工具並沒有在驗證。YAML 禁止重複的 mapping 鍵,但許多解析器會默默只留下最後一個,於是第一個值毫無警告地消失,而那正是你來這裡想找出的錯誤。拒絕 Tab 縮排也是同樣的理由:YAML 從來就不允許 Tab。
- 轉成 JSON 會遺失什麼嗎?
- 註解與錨點一定會遺失,因為 JSON 兩者都沒有。錨點與別名會在轉換前解析成實際的值,所以 &base 與 *base 會變成同一份資料的兩份副本。反方向轉換時,重複的值會完整寫出而不會用別名,長字串也不會被折行。
最後更新:
請提供操作步驟、預期結果及實際結果。請移除機密與個人資料。
