Command Palette

Search for a command to run...

YAML 驗證器:為什麼有效的 YAML 仍然會破壞錯誤的事情

YAML 驗證器:為什麼有效的 YAML 仍然會破壞錯誤的事情

T
Toolz Team
|Jul 5, 2026|19 閱讀

編碼 合集的一部分

這裡咬人的行為是指定的,而不是偶然的: YAML 1.2 規範 定義如何將非引用標量解析為類型。

我曾經發布過一個部署,將服務固定到版本 1.1 當設定檔直白地說 1.10. 不是錯字。尋找並替換並不糟糕。我讀過四次的 YAML 檔案是這樣說的:

image_tag: 1.10

解析器將數字交給了我的部署腳本 1.1. 因為 1.10 isn't 是 YAML 的版本字串 - it's a 浮動字面量,浮點數 don't 保持尾隨零。十變成一分一。該文件是 100% 有效的 YAML。行話者很高興。 CI 是綠色的。錯誤的容器壞了。

That'這是沒有人告訴你的關於 YAML 驗證的事情: &引用;有效&引用;與&quot不同;正確。&引用; 僅回答是/否的語法檢查器正在回答簡單的問題。困難的問題 - 實際中斷的問題 - 是 我的 YAML 變成了什麼? 因為 YAML 不是 config 格式,所以 it'是一個採用 config 格式和#39; 的類型推斷引擎;它的衣服,它會對您的資料做出您從未要求它做出的決定。

yaml 驗證器 在 toolz。dev 上回答這兩個問題。它告訴您文件是否解析,然後向您顯示解析結果為 JSON - 您的工具將收到的實際資料結構。後半部分本來可以拯救我。 "image_tag": 1.1 在輸出窗格中不可能被誤讀。

TL;DR: 將您的 YAML 貼到 yaml 驗證器 並閱讀 JSON 輸出,不只是綠色複選標記。 That's 類型強制顯示的地方: 1.101.1, 0123123,未引用的值默默地變成數字、布林值或空值。它完全在瀏覽器中的 js-yaml (YAML 1.2) 上運行,因此 Kubernetes 的秘密和資料庫憑證永遠不會離開您的電腦。引用任何必須保留字串的內容。如果您需要將結果與 JSON 配置進行比較,則 json 格式化程式JSON 差異 從那裡接。


YAML 驗證器實際上檢查什麼?

兩件不同的事情,它'值得將它們分開,因為它們的失敗方式不同。

語法驗證 問:這個文字可以解析嗎?空格所屬選項卡、冒號後缺少的空格、正文為 't 縮排的區塊標量、未閉合的引號。這些是 大聲 失敗。你的解析器拋出,你的管道變紅,你在兩分鐘內修復它。煩人,不危險。

語義檢查 問:它是什麼解析的 進入?這就是安靜故障所在。該文件有效。管道是綠色的。這個值根本不是你以為你寫的東西。直到生產表現奇怪,然後沒有人發現,然後沒有人's 查看設定文件,因為設定檔是 "精細。&引用;

大多數線上 YAML 跳棋只執行第一個。 toolz。dev 驗證器執行第一個操作,然後遞給您第二個操作 - 解析的文件,呈現為 JSON,就在您的輸入旁邊。養成閱讀該窗格的習慣。 It'是&quot之間的區別;文件格式良好"和"文件就是我的意思。"

哪些 YAML 錯誤實際上會破壞建置?

這裡'這是真正出現的東西,根據我一生中每一次花費我多少錢來排名。低於我的每一種行為都會被驗證 js-yaml 4,這是 toolz。dev 驗證器運行的解析器,並且實現了 亞姆爾1.2 規格。

1. 選項卡。始終選項卡。

YAML 禁止使用選項卡字元進行縮排。不是&引用;勸阻和引用; - 禁止。規格明確,錯誤訊息直接令人耳目一新:

tab characters must not be used in indentation

這種情況不斷發生的原因是選項卡是不可見的。您的編輯器向您顯示一個對齊良好的文件;解析器看到一個控製字元。從來源修復它:將編輯器設定為插入空格,然後開啟 "渲染空白並引用;對於 YAML 檔案。每個層級有兩個空格,這是每個主要 YAML 生態系統所確定的約定。

2。 重複的按鍵

database:
  host: localhost
  port: 5432
  host: production-db.example.com

host 出現兩次。會發生什麼事?它完全取決於您的解析器,這是一個關於配置格式的可怕句子。

js-yaml 投擲: duplicated mapping key.好的。那'是你想要的行為,它'是 toolz。dev 驗證器將向您展示的內容。但 PyYAML--這就是 Ansible 和許多 Python 工具所坐的--默默地接受了 最後的 價值並繼續前進。沒有警告。您的資料庫主機現在是最後一個副本所說的任何內容,在一個長文件中,您合併得很糟糕,它可能距離您'的位置有三百行;正在尋找。

即使您的生產工具接受配置,這也是透過嚴格驗證器運行配置的最佳論點。驗證器 's 更嚴格 比你的運行時是一個發現錯誤的驗證器。

3。 類型強制-那是讓我著迷的

YAML 從未引用的標量推斷類型。它非常有信心,但你的意圖常常是錯誤的:

你寫了 你的意思是 YAML 1.2 為您提供
version: 1.10 字串"1.10" 漂浮物 1.1
pin: 0123 字串"0123" 整數 123
port: "8080" 數字8080 字串 "8080"
enabled: true 布爾 布爾 true - 正確的
value: 也許是空字串? null
value: ~ 一個波形符 null

那個 0123 行是 I'd 人身上的刺青。郵遞區號、PIN 碼、帳號、零填充 ID - 您出於某種原因寫下的每個前導零都會被吃掉。引用它們。

從未讓我失望過的規則: 如果該值是識別碼、版本、程式碼或任何您'從不進行算術運算的內容,請將其放入引號中。 連接埠和副本計數可以保持裸露。一切只是 看起來 數字應該是 "quoted".

4. 依賴版本的布林值(又稱挪威問題)

這確實臭名昭著,細節比迷因更重要。

亞姆爾 1.1,布林類型接受 yes, no, on, off, y, n,以及它們的資本化 truefalse. 所以 country: NO - 挪威's ISO 國家代碼 - 解析為布林值 假的. 在 亞姆爾1.2,這只是清理了這個 truefalse 是布林值; NO 只是字串 "NO".

這意味著相同的文件 在不同的工具中意味著不同的東西:

country: NO
feature_flag: on
  • js-yaml 4(YAML 1.2,以及此驗證器使用的內容): {"country": "NO", "feature_flag": "on"} - 字串。
  • 吡喃甲醛(YAML 1.1): {"country": False, "feature_flag": True} - 布爾。

相同的位元組。不同的數據。如果您的 CI 在 Node 服務消耗的配置上運行 Python 連結器,則有兩個解析器對您的檔案有不同意見,並且它們都沒有錯。

這也是 GitHub Actions&#39 的起源;最奇怪的怪癖: on: 每個工作流程開始時的關鍵是 a 布爾 對於 YAML 1.1 解析器,在 Python 中 lint 工作流程檔案的腳本會找到一個名為 的金鑰 True 代替 on. 引用("on":) 是合法的並且修復了它。

防守動作與之前相同: 引用它. country: "NO" 手段 "NO" 在曾經存在的每個解析器中。

5。 塊標量縮排

description: |
This is not indented

| (字面意思)和 > (折疊)區塊標量需要其內容相對於鍵縮排。未縮排的內容會立即結束區塊,解析器開始將您的散文讀取為 YAML 鍵,這會產生似乎與實際錯誤無關的錯誤訊息。

當您'在這裡時,值得了解咀嚼指標: | 保留一條尾隨換行符, |- 剝去它, |+ 保留所有這些。如果您'重新嵌入私鑰或腳本以及下游抱怨拖尾換行符的內容,這就是您的旋鈕。

6。 未引用的特殊字元

未引用值內的冒號空間結束該值並啟動一個新鍵。這會咬合錯誤訊息和 URL:

message: Error: file not found   # parse error
regex: [a-z]+                    # parsed as a LIST, not a string
time: "22:22"                    # quote it — in YAML 1.1 this was base-60!

[, {, #, &, *, !, |, >, %, @ 標量開始時都有意義。先引用,然後再提問。


如何在 Toolz。dev 上驗證 YAML?

  1. 打開 yaml 驗證器. 沒有帳戶,沒有上傳。
  2. 貼上您的文件。 Helm 值檔案、docker-compose、工作流程 - 無論如何'行為不端。
  3. 點擊驗證。 錯誤會隨著確切的情況而回來 行和列 來自解析器,加上解析器和#39;自己的原因字串((bad indentation of a mapping entry, duplicated mapping key,等等)。
  4. 讀取 JSON 輸出窗格。 這是人們跳過的步驟,它'是重要的。掃描它以查找您關心的價值觀。是 image_tag 字串還是數字?該連接埠被引用嗎?空值是否變為 null?
  5. 修復,重新驗證。 錯誤可能會相互掩蓋 - 解析器會在第一個解析器處停止並#39;t 恢復,因此修復一個解析器有時會顯示另外兩個。那'這很正常,並不是事情變得更糟的跡象。

一個已知的限制,明確指出

驗證器目前解析 a 單一 YAML 文件。 如果您貼上多文檔檔案 - 多個 Kubernetes 清單以分隔 --- 在一個文件中,這是一種極其常見的模式 - 它將報告:

expected a single document in the stream, but found more

That'解析器是正確的,而不是檔案被破壞。今天的解決方法是單獨驗證每個文件:將所有內容貼到上面 ---,檢查一下,然後貼上下一個區塊。多文檔支援出現在我的清單中,正是因為 Kubernetes 用戶立即點擊了該列表,並且 I'寧願告訴你差距,也不願讓你在事件中發現它。


YAML 與 JSON:我什麼時候該使用哪一個?

YAML 1.2 是 JSON 的嚴格超集 - 每個有效的 JSON 文件都是有效的 YAML,這就是為什麼驗證器可以向您提供 JSON 輸出。但這些格式具有相反的性質。

亞姆爾 傑森
結構定義 縮排(空白有效) 大括號和大括號(明確)
評論 是的(#)
類型推論 攻擊性 - 推斷數字、布林值、空值、日期 無 - 引號表示字串,始終
多文檔 是的(--- 分隔符號)
重複使用 錨 (&)、別名(*)、合併鍵(<<) 沒有
故障模式 無聲的誤解 大聲解析錯誤
最好在 人類編寫和編輯的文件 數據機交換

這種交易是真實的,而且是雙向的。 YAML&#39;可讀性和評論正是基礎設施配置存在的原因 - 沒有人願意在沒有評論的情況下維護 JSON 中的 400 行 Kubernetes 清單。 JSON&#39;完全缺乏聰明才智正是 API 使用它的原因: "1.10""1.10" 而且沒有什麼好討論的。

我的規則: YAML 用於人們編輯的文件,JSON 用於資料機器傳遞。 當 YAML 檔案由程式產生而不是由人鍵入時,&#39;s 氣味 - 機器產生的配置不會得到 YAML&#39;s 的好處及其所有風險。

如果你&#39;在兩者之間移動, JSON 到 YAML 轉換器 處理變換,並且 json 格式化程式 會收拾另一邊。

什麼是錨和別名?我應該使用它們嗎?

YAML 讓您定義一個區塊一次並重複使用它。錨與 &,參考 *,合併到地圖中 <<:

defaults: &defaults
  adapter: postgres
  host: localhost
  port: 5432

development:
  <<: *defaults
  database: myapp_dev

test:
  <<: *defaults
  database: myapp_test

兩者 developmenttest 適配器、主機和連接埠合併出來。它&#39;確實有用,js-yaml 處理它 - 我驗證了合併解析正確。

不過有兩個警告。

首先, 合併鍵是 YAML 1.1 擴充,不是 YAML 1.2 核心的一部分。支持是廣泛的,但不是普遍的,而且--吸引人的支持-- GitHub Actions 不支援它們。 工作流程檔案中的錨不會執行您想要的內容。在依靠此之前檢查您的消費者。

其次,錨點使下一個人更難閱讀文件,在配置中,下一個人通常是凌晨 2 點的您,我將它們用於真正重複的區塊,而不是為了聰明。

而我們&#39;則處於 YAML 的危險面:該格式支援某些解析器用來建構任意物件的自訂標籤。 Python&#39;s yaml.load() 眾所周知,這種方式是可以利用的,這就是原因 yaml.safe_load() 存在以及為什麼您應該始終在來自團隊外部的任何 YAML 上使用它。 js-yaml&#39;s load() 在 v4 中預設是安全的(它贏得了&#39;t 構造任意類型),這裡需要擔心的事情少了一件。

我該如何先停止編寫損壞的 YAML?

預防勝過驗證,其中大部分是編輯器配置:

  • 兩個空格,從不製表。 按文件類型設定它,以便您可以&#39;忘記。
  • 開啟空白渲染 對於 .yml/.yaml. 如果您可以看到選項卡,則您獲勝並#39;t 提交選項卡。
  • 安裝 YAML 語言伺服器。 針對 Kubernetes、GitHub Actions 和 docker-compose 模式的即時模式驗證會捕獲一整類錯誤,語法驗證可以&#39;t:使用拼字錯誤的金鑰進行有效的 YAML。
  • 有疑問時預設報價。 不必要的報價的成本為零。缺少一個的成本就是部署。
  • 在推動之前驗證1、CI 失敗後不行。貼上到瀏覽器標籤需要八秒鐘;失敗的管道需要八分鐘。
  • 對於 Kubernetes,分層檢查。 語法驗證捕獲結構; kubectl apply --dry-run=client 捕捉模式。他們發現了不同的錯誤,而你想要兩者。

這個習慣實際上改變了我的事情:當配置驅動的部署做了一些莫名其妙的事情時, 在查看其他內容之前先查看解析的輸出。 不是文件。解析後的輸出。該文件是一個關於您的意思的故事。解析後的輸出就是實際發生的情況。

那&#39;同樣的本能支配著我的一切 API調試工作流程 - 閱讀數據,而不是程式碼 - 它既適用於配置,也適用於回應。如果您想更廣泛地了解該工具箱中的其他內容,那麼 編碼工具指南 覆蓋它。


常見問題

為什麼我的 YAML 會驗證但仍然會破壞我的部署?

因為語法有效性和語意正確性是不同的。 YAML 從未引用的值推斷類型,因此 1.10 成為浮標 1.1, 0123 成為整數 123,空值變為 null - 全部在一個完全有效的文件中。讀取解析的 JSON 輸出,而不僅僅是通過/失敗結果,並引用必須保留字串的任何值。

為什麼 YAML 將我的版本號變成不同的號碼?

1.10 是 YAML 的浮點文字,浮點不保留尾隨零,因此它解析為 1.1。 必須引用任何版本、建置編號或零填充識別碼: version: "1.10". 這是最昂貴的 YAML 錯誤之一,因為檔案看起來正確且解析成功。

YAML 中的挪威問題是什麼?

在 YAML 1.1 中,這些值 no, NO, off, 和 yes 是布林值,所以挪威&#39;s 國家代碼 NO 解析為 false。 YAML 1.2 修復了這個 - 僅 truefalse 是布林值 - 但許多工具(特別是 Ansible 使用的 PyYAML)仍然實作 1.1。因此,同一個文件在不同的工具中可能意味著不同的東西。引用值(country: "NO")讓它到處都是一條繩子。

我可以使用選項卡在 YAML 中縮排嗎?

否。YAML 規範禁止縮排中的選項卡字符,解析器會拒絕它們,並出現諸如 &quot; 縮排中不得使用選項卡字符。&quot; 配置編輯器以插入 YAML 檔案的空格 - 每個層級有兩個空格是標準約定。

Toolz。dev YAML 驗證器是否支援多文件檔案?

目前沒有。它驗證一個文檔,因此包含多個 Kubernetes 的文件顯示為分隔 --- 退貨和報價;期望流中有一個文檔。&quot;分別驗證每個文檔作為解決方法。計劃提供多文檔支援。

YAML 中允許重複金鑰嗎?

該規範規定映射鍵必須是唯一的,但解析器在實踐中不同意。 js-yaml - 此驗證器使用 - 拋出 &quot;重複映射鍵&quot;錯誤。 PyYAML 靜默地保留最後一個值,這意味著重複項可以在沒有任何警告的情況下靜默地覆蓋您的配置。在運行時靜默接受之前,透過嚴格的驗證器運行您的配置會捕獲它。

在線上驗證 Kubernetes 的秘密和憑證安全嗎?

使用 toolz。dev 驗證器,是的 - 解析完全透過 JavaScript 在您的瀏覽器中進行,並且不會將任何內容傳輸到任何伺服器。您可以在驗證時開啟瀏覽器&#39;s Network 標籤並觀察是否提出請求,從而自行確認這一點。在將基礎架構配置貼上到任何線上工具之前,請將其套用相同的檢查。

。yml 和 。yaml 有什麼不同?

沒有任何功能 - 每個 YAML 解析器都認可這兩個擴充。官方建議是 .yaml; .yml 從三字元擴展時代倖存下來,並且仍然非常常見(docker Compose 和 GitHub Actions 都預設為它)。選擇一個並在專案中保持一致。

如何將 YAML 轉換為 JSON?

將 YAML 貼到驗證器中並讀取輸出窗格 - 它將解析的文件呈現為 JSON,即轉換。由於 YAML 1.2 是 JSON 的超集,因此每個有效的 YAML 文件都有一個 JSON 等效項,但首先應用類型推斷,因此不引用 1.10 到達as 1.10123 作為 123. 如果您需要將這些值保留為字串,請先引用它們。

如何根據模式驗證 YAML?

此驗證器檢查語法並顯示解析的結果,但它不會針對模式進行驗證 - 這是一個單獨的檢查,確認您的金鑰和值類型與 Kubernetes 或 GitHub Actions 等工具所期望的相符。對於模式驗證,請在編輯器中使用 YAML 語言伺服器,或模式感知 CLI,例如 kubeconform 對於庫伯內特斯或 kubectl apply --dry-run=client. 語法和模式驗證會捕獲不同的錯誤,因此同時執行這兩個錯誤。


Comments

0 comments

0/2000 characters

No comments yet. Be the first to share your thoughts!