UPTools UPTools
开发 主笔:工具匠

YAML 九成报错都是缩进:CI/CD 配置避坑清单

上周组里一个新人把 GitHub Actions 工作流推上去,CI 直接红了一片。本地 act 跑得好好的,到他这儿的 runner 死活认不出来。我让他把 .github/workflows/deploy.yml 发我,肉眼看过去一切正常。直到我把光标挪到 steps: 那一行往后,才看见下面 - name: Check out 前面的空格少了一个。就一个。

YAML 不靠括号也不靠分号,层级完全靠缩进表达。这设计读起来舒服,写起来坑多。配置文件解析失败,原因九成不在业务逻辑,在缩进和类型转换。下面这四个是我这些年排过最多的。

第一个坑:用了 Tab 缩进

YAML 规范明确禁止 Tab 做缩进,只能用空格。但绝大多数编辑器按一下 Tab 键默认插入制表符,于是你在 VS Code 里敲得飞起,提交后 CI 解析直接挂。

# 错:services 下面用了 Tab
services:
	web:
		image: nginx
# 对:全部用空格
services:
  web:
    image: nginx

预防办法是在编辑器里开启「Tab 转空格」。VS Code 设置项 editor.insertSpaces: trueeditor.tabSize: 2,Sublime、JetBrains 系列都有同样的选项。团队里最好把这条写进 .editorconfig,仓库根目录一份,所有人 clone 下来就对:

[*.{yml,yaml}]
indent_style = space
indent_size = 2

第二个坑:同级元素缩进不一致

这个坑最阴。同一个列表或同一层 map,差一个空格就报错,肉眼还看不出来。

# 错:第二个 service 少缩进了一个空格
services:
  api:
    image: my-api
   worker:          # 这行少了一个空格
     image: my-worker
# 对:同级元素对齐
services:
  api:
    image: my-api
  worker:
    image: my-worker

上次排查过一起 GitLab CI 故障,buildtest 两个 job,一个缩进 2 空格、一个缩进 3 空格。本地 GitLab Runner 没报错(解析器宽容度高一点),推到托管版直接报 mapping values are not allowed here。一通 diff 比对才发现差了一个空格。从那以后我团队立的规矩:YAML 必须过格式化工具,CI 里挂一道校验。

Kubernetes 的 manifest 也一样。spec.containers 下面每个容器对齐,ports 下面每个端口对齐,差一空格 kubectl apply 就失败。

第三个坑:冒号后没有空格

这条是新手坑,但踩过的都知道有多浪费时间。

# 错:冒号后紧贴 value
image:nginx:1.25
# 对:冒号后面留一个空格
image: nginx:1.25

YAML 里 key: value 是固定语法,冒号后面必须有一个空格。没空格会被当成一个整体字符串。注意值里如果本身带冒号(比如镜像 tag nginx:1.25),那个冒号后面要不要空格取决于它是不是「key: value」结构里的那个冒号。不确定的时候,整个值加引号最稳:image: "nginx:1.25"

第四个坑:yes/no/on/off 被解析成布尔

这条不是缩进问题,但跟配置文件排错高度相关,必须单独说。

YAML 1.1 规范规定了一组布尔值的别名:yesnoonofftruefalse(大小写不敏感)。你以为写的是字符串,解析器拿到的却是布尔。Docker Compose、GitHub Actions、Kubernetes(API server 用 YAML 1.1 时代的解析器)里都能复现。

典型踩坑:Kubernetes 里 ConfigMap 想存一个 PostgreSQL 的参数 sslmode: no,apply 进去发现值变成了 false,应用拿到的不是 nofalse,连不上数据库还查不出来原因。

# 错:no 被解析成布尔 false
config:
  sslmode: no
  enable_feature: yes
  region: on
# 对:加引号明确为字符串
config:
  sslmode: "no"
  enable_feature: "yes"
  region: "on"

同样的还有数字。version: 123 会被解析成整数 123,如果你需要字符串 "123",加引号。版本号、以 0 开头的编号(比如 012 可能被当成八进制)尤其要注意。还有 null~ 都会被解析成空值。

排查这类问题的办法:把 YAML 转成 JSON 看一眼,类型一目了然。

实操:用工具替你做眼力活

排查 YAML 问题时与其肉眼对空格,不如直接丢进 UPTools YAML 格式化工具。它能把错乱的缩进重新对齐,顺带做语法校验,第一次出错的行号会标出来;还能一键把 YAML 转成 JSON,yes/no 被转成 true/false 的瞬间你就知道踩了隐式类型的坑。所有解析在浏览器本地完成,配置文件不外传。

另外建议在 CI 里加一道 yamllintprettier --parser yaml,提交时就拦掉绝大多数缩进和格式问题,不用等流水线红了才回头查。

三句话总结

YAML 禁 Tab,编辑器开「Tab 转空格」,仓库里放一份 .editorconfig。同级元素缩进必须一致,冒号后必须留空格,过不去的坎先丢进格式化工具看行号。yes/no/on/off/123 会被隐式转成布尔或数字,含这类值时一律加引号,转 JSON 看类型是最快的验证方式。

相关文章