單元 1 · YAML 是什麼

與 JSON/TOML 的差別、被誰使用、設計哲學

1.1 定義:YAML 是什麼

YAML(YAML Ain't Markup Language)是一門資料序列化格式(data serialization format):用縮排與少量符號描述資料結構,程式再用解析器把它讀成 dict / object / hash。全名是反覆式縮寫(recursive acronym)——「YAML 不是標記語言」,它刻意強調自己不描述版面,只描述資料的形狀

一句話:YAML = 「用打字就寫得出結構化資料」的格式。輸入是純文字,輸出是程式直接能用的資料結構。
對比HTMLJSONYAML
定位標記語言(版面)資料交換格式資料序列化格式
誰好讀機器/工程師機器
註解<!-- -->不支援# 原生支援
結構方式標籤括號縮排

1.2 YAML 與 JSON 的關係

YAML 與 JSON 描述的是同一種資料模型:對映(mapping)、序列(sequence)、純量(scalar)。兩者可以互相轉換——任何 JSON 都是一份合法的 YAML(JSON 是 YAML 1.2 的子集),反之絕大多數 YAML 也能轉成等價 JSON。

原始碼 · YAML SOURCE
server:
  host: localhost
  port: 8080
debug: true
渲染結果 · EQUIVALENT JSON
{"server": {"host": "localhost",
           "port": 8080},
 "debug": true}
記憶法:JSON 是「機器的語言」,YAML 是「人的語言」——兩者都能描述相同資料,差別在誰來寫。日常口語常說「把 YAML 轉成 JSON 驗證」,就是靠這個等價關係。

1.3 YAML vs JSON vs TOML

比較YAMLJSONTOML
主要賣點人最好讀機器最通用語法明確、不易出錯
語法風格縮排 + 符號大括號 / 方括號鍵值對 + 表格
註解支援 #不支援支援 #
多行字串原生 block / folded需跳脫 \n三引號
型別推斷自動(有陷阱)明確明確
典型用途設定檔、CI/CD、manifestAPI 傳輸、網頁資料套件設定(Cargo.toml)

1.4 被誰使用:生態地圖

場景代表怎麼用
CI/CDGitHub Actions / GitLab CI.github/workflows/*.yml 定義 pipeline
容器Docker Composecompose.yaml 描述多容器服務
叢集Kubernetes / HelmDeployment、Service 等 manifest
筆記與網站Jekyll / Hugo / ObsidianMarkdown 檔首 frontmatter 元資料
自動化Ansible / Airflow / Prefectplaybook、DAG 定義
API 描述OpenAPI / SwaggerAPI 規格(YAML 或 JSON)

1.5 設計哲學:為什麼 YAML 會贏

  1. 人好讀:縮排即結構,視覺上直接對應巢狀層級,比括號直覺。
  2. 原生註解:設定檔需要「為什麼這樣設」,JSON 辦不到。
  3. 低學習成本:核心概念只有 mapping 與 sequence 兩種容器。
  4. 多行字串:CI 步驟、指令碼可以直接嵌進設定,不需要跳脫地獄。
  5. 隨處可用:任何語言的解析器都有一堆,YAML 是生態事實標準。
常被忽略的點:YAML 的寬鬆(型別自動推斷、1.1/1.2 差異)正是陷阱來源——舒服歸舒服,被動容錯是雙面刃。單元 5 會完整拆解。

1.6 Worked Example:第一份設定檔

練習 · PRACTICE
app:
  name: 我的服務
  env: production
features:
  - login
  - billing
debug: false
驗收 · CHECKLIST

✅ 鍵值對冒號後都有空格
✅ 縮排一致(兩空格)
✅ 序列用 -
✅ 布林寫 true/false
✅ 存成 config.yml 並用 python3 -c "import yaml;print(yaml.safe_load(open('config.yml')))" 驗證

動手:開一個 test.yml,貼上左邊內容,用 Python / Node / 線上工具解析看看,再改成你自己的服務設定。

看完這單元你應該能說出:
  • 說出 YAML 全名的意思與「資料序列化格式」的定位。
  • 解釋 YAML 與 JSON 的關係(JSON 是 YAML 1.2 的子集)。
  • 舉例說明 YAML 被哪些場景使用(CI/CD、容器、K8s、frontmatter)。
  • 說出 YAML 設計哲學的三大優點(人好讀、可註解、縮排即結構)。

延伸閱讀


進階真實情境 Worked Example:Helm values 設定檔

在 Kubernetes 生態中,Helm chart 的 values.yaml 是最常見的 YAML 設定檔。以下是一份具備多層巢狀、flow/block 混用與註解的真實場景:

原始碼 · values.yaml
# Helm chart values
replicaCount: 2
image:
  repository: nginx
  tag: "1.27"            # 字串,避免浮點
  pullPolicy: IfNotPresent
service:
  type: LoadBalancer
  port: 80
resources:
  limits: {cpu: "500m", memory: "128Mi"}
  requests: {cpu: "250m", memory: "64Mi"}
解析結果 · PARSED
replicaCount: 2
image: {repository: "nginx",
        tag: "1.27",
        pullPolicy: "IfNotPresent"}
service: {type: "LoadBalancer",
          port: 80}
resources:
  limits: {cpu: "500m", memory: "128Mi"}
  requests: {cpu: "250m", memory: "64Mi"}

為什麼這樣設計而非替代方案:tag 加引號是為了避免 1.27 被推斷為浮點數;resources 用 flow style 是因為它是簡短的 key-value 對,一行看完比四行更清晰;pullPolicy 不加引號是 plain string 的最佳實踐——值不含特殊字元,多一對引號只會增加噪音。

深入原理擴充

Block Context vs Flow Context

YAML 有兩種呈現上下文(presentation context)block context(以縮排定義結構)與 flow context(以 { } / [ ] 定義結構)。關鍵規則:flow context 中的冒號後不一定要有空格(當值是明確的標量時),但在 block context 中一定要有空格。這就是為什麼 {cpu:"500m"} 在 flow 對映中合法,但 cpu:"500m" 在 block context 中會出錯。

大家以為是這樣但其實不是……

誤解:「YAML 只能描述設定檔」——事實上 YAML 是通用的資料序列化格式,可以用來描述任何結構化資料(API 回傳、測試 fixture、資料庫 schema migration、甚至遊戲關卡設計)。它的限制不在「能描述什麼」,而在「效能與安全性」——因此不適合大型 binary 資料或不可信來源。

診斷式疑難排解表

症狀可能原因解決方案
解析結果 key 消失冒號後沒空格,被當成純字串所有 key: value 確認冒號後有空格
值被轉成數字/布林未加引號,被自動推斷型別"value" 強制字串
編輯器看不出錯誤但解析爆炸Tab 與空格混用設定編輯器「Tab → 2 spaces」
結構整層錯位序列裡的對映對齊錯誤- key 對齊,後續鍵與 key 同縮排
frontmatter 讀不到檔首缺少 --- 或被 BOM 污染確認檔首是純 ---,無 UTF-8 BOM

進階挑戰題

  1. 跨單元挑戰:寫一份 YAML,要求包含:(a) 一個 flow 對映裡嵌套 block 序列、(b) 一個值同時使用 !!str 標籤與雙引號、(c) 一行包含 # 但不是註解。用 yaml.safe_load 印出型別驗證。
  2. 設計思維:你在設計一份 CI/CD 設定檔格式——哪些值應該是字串、哪些應該是數字?列舉 5 個例子並說明你的判斷依據(型別安全 vs 可讀性)。
  3. 比較分析:找一份真實的 GitHub Actions workflow,試著把它改寫成等價的 JSON,然後說明改寫過程中遇到哪些「YAML 有但 JSON 沒有」的特性(註解、多行字串、flow/block 混用)。

① 專案級端到端 Worked Example:設定檔驅動的微服務專案

把前 1–7 單元的概念放進一個完整專案:一個小型電商 API,所有設定都用 YAML 描述——應用設定、容器編排、CI pipeline 三層貫通。這就是 YAML 在真實世界的角色:整個專案的「膠水」

產出檔案樹

config-first-app/
├── app/
│   ├── config.yml          # 應用設定(本單元核心)
│   └── main.py             # 讀取 config.yml 的服務入口
├── deploy/
│   └── compose.yml         # Docker Compose 編排
└── .github/
    └── workflows/
        └── ci.yml          # GitHub Actions CI

關鍵檔案內容

app/config.yml
app:
  name: order-api
  env: ${APP_ENV:-dev}   # 環境變數注入,預設 dev
  port: 8080
features:
  - auth
  - cart
  - checkout
rate_limit:
  window: 60
  max_requests: 100
deploy/compose.yml
services:
  api:
    build: ../app
    ports: ["8080:8080"]
    environment:
      APP_ENV: production
  redis:
    image: redis:7-alpine
.github/workflows/ci.yml
name: CI
on: [push]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install pyyaml
      - run: python -c "import yaml;c=yaml.safe_load(open('app/config.yml'));assert c['app']['port']==8080"
驗證命令與輸出
$ python3 -c "import yaml;c=yaml.safe_load(open('app/config.yml'));print(c['app']['port'], c['features'])"
8080 ['auth', 'cart', 'checkout']

$ docker compose -f deploy/compose.yml config --quiet && echo "compose OK"
compose OK

$ actionlint .github/workflows/ci.yml && echo "workflow OK"
workflow OK

端到端流程:開發改 app/config.yml → push 觸發 CI → CI 先解析驗證 YAML 再跑測試 → 綠燈後用 compose 起整疊服務。任何一步的 YAML 壞掉,都會在 CI 階段被攔下,而不是等到上線才爆。

② 效能/品質/安全深度

效能:YAML 的大型檔案代價

YAML 是直譯器友善、解析器昂貴的格式。對比:

面向YAMLJSON
解析器實作複雜度高(縮排 + flow + 標籤 + 多文件)低(遞迴下降即可)
10 MB 設定檔解析時間數百 ms(PyYAML 量級)數十 ms(標準 json 模組)
記憶體峰值更高(保留節點與行號資訊)較低

實務結論:熱路徑(每次請求都讀)用 JSON;冷路徑(開機/部署時讀一次)用 YAML。大型 values.yaml 可拆成多檔或開啟快取,減少單次解析量。

品質:只有語法檢查不夠

YAML 的「寬鬆」讓品質問題藏在語法正確的檔案裡:型別誤判、缺少必填欄位、拼錯鍵名。解法是三層防線:yamllint(風格)→ JSON Schema(結構)→ 解析器 + assert(行為)。

安全:不可信 YAML 的處理原則

鐵律:對不可信來源的 YAML 一律用 safe_load(或各語言對應的 safe 變體),並加上檔案大小/深度上限。YAML 的標籤(!!python/object)與錨點展開是任意程式執行與 DoS 的入口——單元 6、8 會深入 Billion Laughs。

③ 站際比較對照表

面向yamlmarkdownjsongithubgitlab
單元定位資料序列化格式與設計哲學純文字標記與文件結構機器交換格式與嚴格語法平台工作流與協作習慣CI/CD pipeline 平台
開場切入點「人好讀的資料」「寫作與排版一體」「嚴謹的資料交換」「PR/issue 驅動開發」「pipeline 即程式碼」
第一單元教什麼定義、JSON 關係、生態地圖標題、段落、強調物件、陣列、型別repo、branch、PRproject、pipeline、runner
核心隱喻縮排即結構純文字即可表達結構括號即結構分散式版本控制整合式 DevSecOps
主要讀者後端 / DevOps / SRE文件寫作者 / 部落客前端 / API 工程師開源維護者 / 協作者企業 DevOps 團隊

④ 互動式檢核清單