咬这里的行为是指定的,而不是偶然的: YAML 1.2 规范 定义如何将未引用的标量解析为类型。
我曾经发送过一个将服务固定为版本的部署 1.1 config文件明明说的时候 1.10、不是错字、不是不好找换, 读了四遍的YAML文件是这样说的:
image_tag: 1.10
解析器将数字交给我的部署脚本 1.1。因为 1.10 is't YAML 的版本字符串 - it's a 浮动字面、和浮don't保持尾随零十变一分一文件100%有效YAML, 转轴快乐, CI绿色, 出错容器。
That's 没有人告诉你的关于YAML验证的事情: "有效"与"不一样正确。" 只回答是/否的语法检查器是回答简单的问题,难题 - 实际上破坏部署的问题 - 是 我的 YAML 变成了什么? YAML因为不是配置格式,它's一个类型推理引擎,穿着配置格式's衣服,它对你的数据做出你从未要求它做出的决定。
的 YAML 验证器 on toolz。dev 回答了两个问题,它告诉你文档是否解析,然后它会向你显示解析后的结果为 JSON - 你的工具将收到的实际数据结构,那下半部分是本来可以拯救我的。 "image_tag": 1.1 在输出窗格中不可能被误读。
TL;博士: 将您的 YAML 粘贴到 YAML 验证器 并阅读 JSON 输出的, 不仅仅是绿色复选标记。那个's其中类型强制显示自己:
1.10→1.1、0123→123的,未引用的值默默地变成数字,布尔值或空值,它完全在浏览器中运行在js-yaml(yaml 1.2)上,因此Kubernetes的秘密和数据库凭据永远不会离开你的机器,引用任何必须保持字符串的内容,如果您需要将结果与JSON配置进行比较,则 json格式化程序 並 JSON 迪夫 从那里接。
YAML 验证器实际检查什么?
2种不同的东西,而它'值得将它们分开,因为它们以不同的方式失败。
语法验证 asks: 这篇文字到底能不能解析?空格所属的选项卡,冒号后缺少的空格,体为't缩进的块标量,未封闭的引号,这些是 大声 failures。你的解析器抛出,你的管道变红,你在两分钟内修复。烦人,不危险。
语义检查 问:它解析了什么 进入?这里是安静的失败所居住的地方文档有效管道绿色值根本不是你以为你写的直到生产行为怪异才发现,到那时没有人's看着配置文件,因为配置文件是"fine。"
YAML大多数在线检查器只做第一个。toolz。dev验证器做第一个,然后递给你第二个 - 解析的文档,渲染为JSON,就在你的输入旁边。养成阅读该窗格的习惯。it's之间的区别"文件格式良好"和"文件的意思是我的意思。"
哪些 YAML 错误实际上会破坏构建?
Here's真正显现出来的东西,按我每人付出了多少生命的代价来排名我验证的下面每一个行为 js-yaml 4它是 toolz。dev 验证器运行的解析器,实现 山药 1.2 规格。
1。选项卡。总是选项卡。
YAML禁止缩进的选项卡字符。不是"劝阻"-禁止。规格显式, 错误信息令人耳目一新直接:
tab characters must not be used in indentation
1直发生这个原因就是标签是隐形的,你的编辑器给你看一个对齐不错的文件;解析器看到一个控制字符,在源头修复:设置你的编辑器插入空格,打开"渲染空格"对于YAML文件每个级别两个空格,这是每个主要YAML生态系统都已经确定的约定。
2、重复键
database:
host: localhost
port: 5432
host: production-db.example.com
host 2次出现。会发生什么?完全取决于你的解析器,写一个config格式,这句话很恐怖。
js-yaml 投掷: duplicated mapping key。好。你想要的行为和它's工具z。dev验证器将向你展示的东西。但是PyYAML - 这就是Ansible和很多Python工具所采用的 - 默默地采用 最后 value并继续前进。没有警告。你的数据库主机现在是最后一个重复所说的任何内容, 在一个长文件中, 你合并得很糟糕, 可能距离你're看的地方三百行。
即使您的生产工具接受配置,这也是通过严格验证器运行配置的最佳论据。验证器's 更严格 than 你的运行时是一个查找错误的验证器。
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: ~ |
a蒂尔德 | null |
那个 0123 row是人身上纹身的那个i'd邮编,pin,帐号,零填充id- 你写的每一个前导零都有理由被吃掉,引用它们。
从来没有让我失望的规则: 如果该值是标识符、版本、代码或任何您'd 从不进行算术,请将其放入引号中。 端口和复制品很重要,可以保持光秃秃的状态。一切都是简单的 看起来 数字应该是 "quoted"。
4。依赖于版本的布尔值(又名挪威问题)
这确实是臭名昭著的,细节比模因更重要。
在 山药 1.1中, 布尔类型接受 yes、 no、 on、 off、 y、 n及其资本化,此外 true 並 false.所以 country: NO - 挪威's ISO 国家代码 - 解析为布尔值 假.在 山药 1.2只是,它清理了这个 true 並 false 是布尔人; NO 是只是字符串 "NO"。
这意味着相同的文件 在不同的工具中意味着不同的东西:
country: NO
feature_flag: on
- js-yaml 4(YAML 1.2, 以及此验证器使用的内容):
{"country": "NO", "feature_flag": "on"}- 字符串。 - PYYAML (YAML 1.1):
{"country": False, "feature_flag": True}- 布尔人。
相同的字节。不同的数据。如果您的 CI 在 Node 服务消耗的配置上运行 Python 字节,则有两个解析器对您的文件存在分歧,并且它们都不会出错。
这也是 GitHub Actions' 的由来。最奇怪的怪癖: on: 每个工作流程开始的键是 a 布尔 yaml 1.1解析器,因此在Python中列出工作流文件的脚本会找到一个调用 True 代替 on.引用("on":的()是合法的,并修复了它。
的防守动作和之前一样: 引用它。 country: "NO" 手段 "NO" 在曾经存在的每个解析器中。
5。块标量缩进
description: |
This is not indented
的 | (字面意思)和 > (折叠)的块标量需要它们相对于键缩进的内容,未缩进的内容立即结束块,解析器开始将你的散文读为YAML键,这会产生似乎与实际错误无关的错误消息。
值得一提的是,当你'在这里: | 保留一条尾随换行符, |- 剥掉它, |+ keep住全部,如果你're嵌入私钥或脚本下游有事吐槽尾随换行符,这就是你的旋钮。
6、未引用的特殊字符
A colon-space 在一个未引用的值内结束值并启动一个新的密钥, 这咬在错误消息和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?
- 打开 YAML 验证器。 没有帐户,没有上传。
- 粘贴您的文档。 Helm 重视文件、docker 组合、工作流程 - 无论如何'的不当行为。
- 击验证。 错误又回来了 行和列 from 解析器,加上解析器'自己的原因字符串(
bad indentation of a mapping entry、duplicated mapping key的(等等)。 - 读取 JSON 输出窗格。 这是人们跳过的步骤,重要的是's。扫描它以了解您关心的价值观。是
image_tag字符串还是数字?那个端口是否被引用?空值是否变成了null嗎? - 修复、重新验证。 Errors可以互相掩盖-解析器停在第一个它可以't恢复,所以修复一个有时会显示两个更多。那's正常,不是标志事情正在变得更糟。
一个已知的限制,明确指出
验证器当前解析a 单一 YAML 文档。如果你粘贴一个多文档文件 - 几个 Kubernetes 清单,由 隔开 --- 在一个文件中,这是一个极其常见的模式 - 它将报告:
expected a single document in the stream, but found more
That's解析器正确,而不是文件被破坏,今天的解决方法是分别验证每个文档:粘贴上面的所有内容 ---、检查一下,然后粘贴下一块多文档支持就在我的列表中,正是因为 Kubernetes 用户立即点击了此内容,而 I'宁愿告诉你差距,也不愿让你在事件中期发现它。
YAML vs JSON:我什么时候应该使用哪个?
YAML 1.2 是 JSON 的严格超集 - 每个有效的 JSON 文档都是有效的 YAML,这就是为什么验证器可以交给你 JSON 输出的原因。但格式具有相反的个性。
| 山药 | JSON | |
|---|---|---|
| 定义的结构 | 缩进(空白显着) | 括号和括号(明确) |
| 评论 | 是(x),在(x)中,在(x)中,在(x)中,在(x)中,在(x)中,在(x)中#) |
否 |
| 类型推断 | 攻击性 - 推断数字、布尔值、空值、日期 | 没有 - 引号总是表示字符串 |
| 多文档 | 是(x),在(x)中,在(x)中,在(x)中,在(x)中,在(x)中,在(x)中--- 分(隔) |
否 |
| 再利用 | 锚(&),别名(*),合并键(<<) |
没有 |
| 故障模式 | 无声的误解 | 解析错误大声 |
| 最好的 | 人类编写和编辑文件 | 数据机交换 |
交易是真实的,是双向的 YAML's 可读性和评论正是基础设施配置生活在那里的原因 - 没有人想在 JSON 中保持 400 行的 Kubernetes 清单,而没有评论 JSON's 完全缺乏聪明才智正是 API 使用它的原因: "1.10" 於 "1.10" 而且没有什么可讨论的。
我的规则: YAML 适用于人员编辑的文件,JSON 适用于数据机通过。 当 YAML 文件由程序生成而不是由人键入时,嗅觉生成配置不会获得 YAML' 的好处及其所有风险。
如果你're在两者之间移动,the JSON 到 YAML 转换器 处理转换,并且 json格式化程序 会收拾另一边。
什么是锚和别名,我应该使用它们吗?
YAML 让你定义一次区块,并重用。锚与 &,参考 *,合并成地图与 <<:
defaults: &defaults
adapter: postgres
host: localhost
port: 5432
development:
<<: *defaults
database: myapp_dev
test:
<<: *defaults
database: myapp_test
两者 development 並 test out with 适配器,主机,端口合并到。it's 真正有用,并且 js-yaml 处理它 - 我验证合并解析正确。
不过,有两个警告。
首先, 合并密钥是 YAML 1.1 扩展的,不是YAML 1.2核心的一部分,支持是广泛的,但不是普遍的,而且- 抓住人的- GitHub 操作不支持它们。 Workflow文件中的锚不会做你想做的事,在你依靠这个之前检查你的消费者。
其次,锚使下一个人的文件更难读取,在配置中,下一个人通常是凌晨 2 点的您。我将它们用于真正重复的块,而不是用于聪明。
While we're 在YAML危险的一面:格式支持一些解析器用来构造任意对象的自定义标签。Python's yaml.load() 以这种方式被利用而闻名,这就是原因 yaml.safe_load() 存在以及为什么您应该始终在来自团队外部的任何 YAML 上使用它。 js-yaml's load() v4中默认是安全的(赢了't构造任意类型),这里少担心一件事。
我如何停止首先写破损的 YAML?
Prevention 击败验证, 其中大部分是编辑器配置:
- 两个空格,从不选项卡。 按文件类型设置,以便您可以't 忘记。
- 打开空白渲染 为
.yml/.yaml。如果可以看到选项卡,则获胜't提交选项卡。 - 安装 YAML 语言服务器。 Kubernetes、GitHub 操作和 docker-compose 模式的实时模式验证会捕获语法验证可以't:使用拼错键的有效 YAML 的整类错误。
- 存在疑问时默认引用。 1个不必要的报价成本为零,少一个的成本就是部署。
- 在推送之前验证CI 失败后,而不是。粘贴到浏览器选项卡需要八秒;失败的管道需要八分钟。
- 对于 Kubernetes,分层检查。 语法验证捕获结构;
kubectl apply --dry-run=clientcatchschema。他们发现了不同的错误,你想要两者。
而真正改变我事情的习惯:当配置驱动的部署做一些莫名其妙的事情时, 在查看其他任何内容之前,请先查看解析的输出。 Not the file。解析出来的输出。文件是一个关于你意思的故事。解析出来的输出就是实际发生的事情。
That's相同的本能,支配着我的一切 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 是布尔人,所以挪威's国家代码 NO 解析为 false。YAML 1.2 修复了这个问题 - 仅 true 並 false 是布尔值- 但许多工具(特别是Ansible使用的PyYAML)仍然实现了1.1。因此,同一个文件在不同的工具中可以表示不同的值(引用)country: "NO"()使它成为无处不在的字符串。
我可以在 YAML 中使用选项卡进行缩进吗?
No。YAML规范禁止缩进中的选项卡字符,解析器拒绝它们,并出现"这样的错误,缩进中不得使用选项卡字符。"配置您的编辑器为YAML文件插入空格-每级两个空格是标准约定。
Toolz。dev YAML Validator 支持多文档文件吗?
Not current。它验证单个文档,因此包含多个 Kubernetes 的文件由 隔开 --- returns "期望流中的单个文档。"单独验证每个文档作为解决方法。计划多文档支持。
YAML 中是否允许使用重复的密钥?
规范规定映射键必须是唯一的,但解析器在实践中不同意。 js-yaml(此验证器使用它)会抛出 " 重复的映射键 " 错误。PyYAML 默默地保留最后一个值,这意味着重复项可以在完全没有警告的情况下悄悄覆盖您的配置。通过严格的验证器运行您的配置会在运行时默默接受之前捕获它。
在线验证 Kubernetes 秘密和凭据安全吗?
Toolz。dev验证器,是的 - 解析完全在您的浏览器中通过JavaScript发生,并且没有任何东西传输到任何服务器,您可以通过打开浏览器's网络选项卡来自行确认这一点,同时验证并观察没有请求在将基础设施配置粘贴到任何在线工具之前将相同的检查应用到其中。
.yml 和.yaml 有什么区别?
Nothing 函数式 - 两个扩展都被每个 YAML 解析器所识别,官方推荐的是 .yaml; .yml 3个字符扩展的时代中生存下来,并且仍然极为普遍(docker Compose和GitHub Actions都默认是它)。选择一个并在项目中保持一致。
如何将 YAML 转换为 JSON?
YAML粘贴到验证器中,读取输出窗格- 它将解析的文档渲染为JSON,也就是转换,因为YAML 1.2是JSON的超集,所以每个有效的YAML文档都有一个JSON等价,但是首先应用类型推断,所以没有引用 1.10 到达时为 1.1 並 0123 as 123。如果您需要将这些值保留为字符串,请首先引用它们。
如何根据模式验证 YAML?
This validator 检查语法并显示解析的结果,但它不会针对模式进行验证 - 这是一个单独的检查,确认您的密钥和值类型与 Kubernetes 或 GitHub Actions 等工具所期望的模式验证,请在编辑器中使用 YAML 语言服务器,或模式感知 CLI,例如 kubeconform 对于 Kubernetes 或 kubectl apply --dry-run=client。语法和模式验证捕获不同的错误,因此两者都运行。



