序列(陣列)、巢狀、複雜結構、錨點預告
YAML 的資料只有兩種容器:對映 mapping(鍵值組,即 dict / object)與 序列 sequence(有序清單,即 list / array)。其他一切都是「值」。掌握這兩種容器的組合,就掌握 YAML 的 90%。
用 - (橫槓 + 空格)表示清單項,同一層的 - 對齊。
fruits: - apple - banana - cherry
{"fruits": ["apple",
"banana",
"cherry"]}
對映的值可以是另一個序列。
server: ports: - 80 - 443 tls: true
清單的每個元素可以是一組鍵值——這是設定檔最常見的形狀(服務清單、容器清單)。關鍵在對齊:- 與第一個鍵同層,後續鍵值與第一個鍵同縮排。
services: - name: web port: 8080 - name: db port: 5432
{"services": [
{"name": "web", "port": 8080},
{"name": "db", "port": 5432}]}
port 縮排到 - 底下(和 name 不同層),結果變成「對映裡包一個序列」,結構整個錯位。Kubernetes 的 containers 正是這個形狀——單元 7 會再驗證一次。三種結構可以任意組合到任意深度——這是 YAML 描述複雜系統的方式。
pipeline: - name: build steps: - checkout - test env: DEBUG: false
{"pipeline": [{
"name": "build",
"steps": ["checkout","test"],
"env": {"DEBUG": false}}]}
想要「一行寫完」時,用 JSON 風格:序列 [ ]、對映 { }。
aliases: [prod, production] limits: {cpu: "1.5", mem: "512Mi"}
{"aliases": ["prod","production"],
"limits": {"cpu": "1.5",
"mem": "512Mi"}}
jobs: - name: lint commands: - npm run lint - name: deploy when: main env: {URL: https://example.com}
① jobs 是序列
② 每個 job 是對映(序列裡的對映)
③ commands 是巢狀序列
④ env 用 flow 對映
👉 試著把它改寫成「純 block style」,再驗證兩者解析結果相同
練習:設計一個「學生清單」設定:每個學生有姓名、年級與選課序列(至少三個),用序列裡的對映寫出,再用 JSON 對照驗證。
DevOps 中常見「序列裡有深層巢狀對映、對映裡又包序列」的結構。以下是一份含多層混用的真實場景:
clusters: - name: prod-us node_pools: - name: general autoscaling: min: 3 max: 10 labels: [web, api] - name: gpu taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule - name: staging-eu node_pools: - name: general autoscaling: {min: 1, max: 5}
clusters (sequence)
├─ {name: "prod-us", node_pools:
│ ├─ {name: "general",
│ │ autoscaling: {min:3, max:10},
│ │ labels: ["web","api"]}
│ └─ {name: "gpu",
│ taints: [{key:"nvidia.com/gpu",
value:"true",
effect:"NoSchedule"}]}}
└─ {name: "staging-eu", node_pools:
└─ {name: "general",
autoscaling: {min:1, max:5}}}
為什麼這樣設計而非替代方案:labels 用 flow 序列 [web, api] 是因為它短而扁平;taints 用 block 序列是因為每個元素有三個鍵值對,block 更清晰。autoscaling 在 staging 用 flow 是因為只有兩欄——同一份設定檔中根據內容複雜度選擇最適合的風格是 YAML 的最佳實踐。
YAML 規範中,flow style 的對映中,冒號後的空格是可選的(例如 {a:1} 合法),但block style 中冒號後一定要有空格(a: 1)。這就是為什麼很多從 flow 風格複製到 block 風格的值會突然報錯——漏加了空格。
- 的位置」——其實 - 後面的第一個鍵與 - 同列(或下一行同縮排),但後續的鍵只需要與第一個鍵同縮排,不需要與 - 對齊。對齊 - 只是風格建議,不是語法要求。| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
sequence entries are not allowed here | 序列與對映混用時縮排錯位 | - key 的 - 與上層容器對齊 |
expected ',' or '}' | flow 對映中漏了逗號或鍵值間缺少分隔 | 檢查 {a: 1, b: 2} 格式 |
| 解析結果層級與預期不同 | 多層巢狀時某處少了一級縮排 | 用 yq '.' 印出完整結構比對 |
mapping keys must be unique | 同層出現重複鍵 | 搜尋並合併或移除重複鍵 |
| 序列元素「跳」到上層 | - 的縮排比上層少 | 確保 - 縮排 ≥ 父容器的縮排 + 1 |
yaml.safe_load 解析並觀察結果如何變化。畫出正確 vs 錯誤的結構樹。K8s 是「序列與巢狀」的極致考場——containers(序列裡的對映)、env(對映裡包序列)、strategy(多層巢狀)。配合 Kustomize overlay 做多環境管理:
k8s-app/ ├── base/ │ ├── namespace.yaml # 命名空間 │ ├── deployment.yaml # 深層巢狀主檔 │ ├── service.yaml # 服務暴露 │ └── kustomization.yaml # 組合 base 資源 └── overlays/ ├── dev/ │ └── kustomization.yaml └── prod/ └── kustomization.yaml # 覆寫 replicas / 資源
apiVersion: apps/v1 kind: Deployment metadata: name: api spec: replicas: 1 selector: matchLabels: {app: api} template: metadata: labels: {app: api} spec: containers: - name: api image: myapi:1.0 ports: - containerPort: 8080 env: - name: LOG_LEVEL value: info resources: limits: {cpu: "100m", memory: "128Mi"}
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ../../base patches: - target: {kind: Deployment, name: api} patch: |- - op: replace path: /spec/replicas value: 5
$ kustomize build overlays/prod | kubectl apply --dry-run=client -f - -o name deployment.apps/api namespace/api service/api $ kustomize build overlays/prod | kubectl apply --server-side --dry-run=server -f - && echo VALID deployment.apps/api configured (server dry run) VALID $ kubeconform -strict -summary <(kustomize build overlays/prod) Result: PASS
① containers = 序列,每個元素是對映(name/image/ports/env)
② ports = 序列裡的對映,containerPort 與 - 對齊
③ env = 序列裡的對映,再往下一層
④ 最內層 resources 用 flow,讓深度控制在 5 層內
⑤ Kustomize patch 用 |- 寫 YAML-in-YAML(JSON Patch)
端到端流程:base/ 放標準資源 → overlays/prod 覆寫 replicas: 5 → kustomize build 產生最終 manifest → kubectl apply --dry-run=server 在 API server 驗證。整個管線的每一步都在處理「序列與巢狀」的正確性。
K8s Deployment 的 spec.template.spec.containers[].env[].valueFrom 可達 6–7 層縮排,這是 YAML 可讀性的極限。品質策略:
kubeconform / kubeval + 官方 JSON Schema 驗證欄位(攔截拼錯的欄位名)。解析器對巢狀深度有實作上限(PyYAML 預設 ~1000 層,超過拋 maximum recursion depth exceeded)。實務上沒人會寫到 100 層,但「程式產生的 YAML」可能踩到——生成器要設定合理上限並在輸出前驗證。
securityContext、serviceAccountName、hostNetwork 都在深層。用 kube-linter / checkov 掃 manifest,別只靠肉眼讀深度巢狀。Pod 安全標準(PSS)是官方的強制分層。| 面向 | yaml | markdown | json | github | gitlab |
|---|---|---|---|---|---|
| 序列(清單) | - item 縮排式 | - item / 1. item | ["a","b"] | task checklist(- [ ]) | job list 以 YAML 序列表達 |
| 巢狀深度 | 縮排決定,最高可上百層 | 標題層級(#/##/###) | 括號遞迴,理論無上限 | 目錄樹(檔案系統) | group / subgroup 階層 |
| 最易錯形狀 | 「序列裡的對映」對齊 | 巢狀列表縮排 | 逗號遺漏 | 檔案路徑結構 | pipeline stage 依賴 |
| 驗證方式 | yamllint / schema / dry-run | Markdown lint / 渲染預覽 | JSON Schema / linter | workflow 語法檢查 | pipeline lint / dry-run |
yaml.safe_load 驗證結構與預期相符。containers / env 深層巢狀,並指出每一層的容器類型。kustomize build + kubectl apply --dry-run=server 驗證一份 K8s 專案。