GitHub Actions/Docker Compose/Kubernetes/frontmatter
放在 .github/workflows/*.yml,定義 CI/CD。你現在看的這個教學站就是它部署的。三層結構:on(何時觸發)→ jobs(跑什麼)→ steps(每個 job 的步驟)。
name: CI on: push: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm test
on: 在 YAML 1.1 裡 on 會被當布林——GitHub Actions 特別容許它作為鍵名。這也再次印證單元 5 的提醒:你自己寫設定檔時,避免用 on 當鍵。定義多容器服務。<< 合併鍵常用來共用設定(單元 6),ports 是「序列裡的對映」的應用。
services: web: build: . ports: - "8080:80" environment: NODE_ENV: production db: image: postgres:16 volumes: - db-data:/var/lib/postgresql/data volumes: db-data: {}
注意 ports / volumes 都是序列;environment 是對映;volumes.db-data: {} 是空對映(留 {} 比留空更明確)。
K8s 資源描述也是 YAML。基本結構:apiVersion、kind、metadata、spec。
apiVersion: apps/v1 kind: Deployment metadata: name: web spec: replicas: 3 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: web image: nginx:1.27
這是單元 4 的「序列裡的對映」深度應用:containers 底下是序列,每個元素是對映,image 要跟 name 對齊。
Markdown 檔案頂端的 --- 區塊,用 YAML 描述文件屬性。這是「文件分隔符」最日常的用途(單元 2)。
--- title: YAML 筆記 tags: - yaml - 教學 date: 2026-08-15 draft: false ---
| 工具 | 用 YAML 做什麼 |
|---|---|
| GitLab CI | .gitlab-ci.yml 定義 pipeline |
| Ansible | playbook 描述部署任務 |
| Prefect / Airflow | 資料管線 DAG 定義 |
| Helm | K8s 套件模板(含 Go template 語法) |
| OpenAPI / Swagger | API 描述(YAML 或 JSON) |
apiVersion: apps/v1 kind: Deployment metadata: name: api spec: replicas: 2 template: spec: containers: - name: api image: myapi:1.2 env: - name: LOG_LEVEL value: info
① 頂層四欄位
② replicas 整數
③ containers = 序列裡的對映
④ env = 序列裡含兩鍵的對映
👉 用單元 4 的「對齊」眼光檢查:name / image / env 三鍵同層
練習:找一個 GitHub repo 的 .github/workflows/,讀懂它的 on / jobs / steps;再用 compose 的語法為一個服務寫一份含環境變數與 ports 的片段。
Matrix 策略是 GitHub Actions 中最複雜的 YAML 結構之一——序列裡包對映、對映裡包序列、flow 與 block 混用:
name: Matrix CI on: push: {branches: [main]} pull_request: {branches: [main]} jobs: test: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest] node: [18, 20, 22] exclude: - {os: macos-latest, node: 18} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: {node-version: "${{ matrix.node }}"} - run: npm test
① on 的值是 flow 對映——push: {branches: [main]}
② matrix 含兩個序列(os × node = 6 組合)
③ exclude 是序列裡的 flow 對映
④ ${{ }} 是 GitHub expression,非 YAML 語法
⑤ with 用 flow 對映包單個值——簡潔
為什麼這樣設計而非替代方案:on 用 flow 對映而非 block 是因為每個 trigger 只有一行參數,flow 佔行數更少。exclude 用 flow 對映 {os:..., node:...} 是因為每個排除規則只有兩個欄位——如果改用 block 寫,反而多出 4 行縮排。GitHub Actions 社群的慣例是「簡單用 flow、複雜用 block」。
| 工具 | YAML 版本 | 特殊方言 | 注意事項 |
|---|---|---|---|
| GitHub Actions | 1.1(部分) | on: 允許當鍵名;${{ }} expression | 避免自己用 on / off 當鍵 |
| Docker Compose | 1.1 | x- 延伸節點;<< 合併鍵 | x- 前綴的節點被忽略 |
| Kubernetes | 1.2(推薦) | 多文件 ---;型別標籤 !! | kubectl 預設用 1.2+ 解析器 |
| Ansible | 1.1 | !vault 等自訂標籤 | Ansible 用 PyYAML(1.1) |
| Helm | Go YAML 3(1.2) | Go template {{ }} 嵌在 YAML 裡 | template 語法與 YAML 衝突需注意 |
on: 是特例處理,不是通用 YAML 行為。Ansible 仍基於 PyYAML(1.1),所以 yes 仍是布林。一份 YAML 在 A 工具正常不代表在 B 工具也正常。| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
GitHub Actions on 報解析錯誤 | 非 GitHub 的 YAML 解析器把 on 當布林鍵 | 本地測試用 GitHub 的解析器,或加引號 |
Docker Compose 忽略 x- 節點中的設定 | 這是預期行為——x- 節點只當錨點來源 | 確保 x- 節點的值被 <<:*alias 引用 |
K8s kubectl apply 報 unknown field | apiVersion/kind 指錯版本 | 確認 apiVersion 與 K8s 版本相符 |
| Helm template 產生意外輸出 | Go template {{ }} 與 YAML flow 對映衝突 | 用 \{{ }} 轉義或 rawYaml helper |
| Ansible playbook 讀不到變數 | PyYAML 1.1 把 yes 當布林,變數名被改 | 變數名避免 yes/no/on/off |
compose.yaml 中的 x- 延伸節點改寫成 Ansible inventory 可用的格式。哪些概念可以直接搬?哪些需要重新設計?matrix、exclude、include 的 GitHub Actions workflow,然後把所有 GitHub expression(${{ }})替換成實際值,觀察純 YAML 的結構。yes 布林)與 1.2 的特性(010 字串),然後用不同解析器(PyYAML、ruamel.yaml、Go yaml.v3)解析,比較結果差異。一個產品同時用 GitHub Actions(公開 repo CI)與 GitLab CI(私有部署 pipeline)跑兩條管線,共享同一份 Docker Compose——這是「同一份 YAML 面對不同生態方言」的真實場景:
dual-ci-app/ ├── .github/workflows/ │ └── ci.yml # GitHub Actions(matrix + 快取) ├── .gitlab-ci.yml # GitLab CI(stages + include) ├── docker-compose.yml # 兩邊測試共用 └── Makefile # 統一指令入口
name: CI on: push: {branches: [main]} pull_request: {branches: [main]} jobs: test: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest] node: [18, 20] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: {node-version: "${{ matrix.node }}"} - run: make test
stages: [test, deploy] include: - project: infra/ci-templates file: /node-tests.yml test: stage: test image: node:20 script: - npm ci - make test parallel: 2 rules: - if: $CI_COMMIT_BRANCH == "main" deploy: stage: deploy image: docker:27 script: - docker compose -f docker-compose.yml up -d
$ actionlint .github/workflows/ci.yml && echo "gh OK"
gh OK
$ curl -X POST --header "PRIVATE-TOKEN: $CI_TOKEN" \
"$GITLAB_URL/api/v4/projects/1/ci/lint" \
--data-urlencode "content=$(cat .gitlab-ci.yml)"
{"status":"valid","errors":[]}
$ docker compose -f docker-compose.yml config --quiet && echo "compose OK"
compose OK
① GitHub 用 on / jobs / steps;GitLab 用 stages / script / rules
② GitHub matrix 用 flow 序列;GitLab parallel: 2 更簡單
③ GitLab include 參考共用 template(reusable)
④ 兩邊都引用同一份 docker-compose.yml
⑤ 驗證工具完全不同:actionlint vs GitLab CI Lint API
關鍵洞察:同一個 CI 意圖(測、建、佈署)在兩個平台用不同 YAML 方言描述——語法關鍵字、觸發方式、變數語法全部不同。這就是「YAML 是方言的世界」,一份 YAML 換平台就是翻譯工程。
| 語法 | GitHub Actions | GitLab CI |
|---|---|---|
| 觸發 | on:(特例鍵名) | rules: / only/except(舊式) |
| 變數 | ${{ }} expression | $VAR / ${VAR} |
| 共用 | reusable workflow / composite | include + extends |
| 環境 | env: 層級眾多 | variables 層級眾多 |
移植時最容易漏:GitHub 的 env 是「對映」而 GitLab 的 variables 也是對映——但表達式與預設值語法完全不同,直接複製貼上必爆。
大型 monorepo 的 workflow 檔會拖慢每次 CI 的「排程前解析」。GitHub 有 workflow 快取與 paths 過濾;GitLab 有 rules:changes。用這些機制讓無關檔案變更不觸發整條 pipeline——這才是「YAML 效能」在生態系的真正意義。
${{ }} 若插值進 run:,可能被 github.event.issue.title 這類不可信輸入注入(CVE 等級的已知風險)。規則:不要把未處理的 event 資料插進 script;secret 只透過 env 注入,不寫進 YAML;CI 日誌永不 echo secret。| 面向 | yaml | markdown | json | github | gitlab |
|---|---|---|---|---|---|
| 平台主力格式 | 設定檔 / manifest | 文件 / README / wiki | API 交換 / 設定 | workflow(YAML) | pipeline(YAML) |
| 觸發機制 | 無(資料格式) | 無 | 無 | on: 事件 | rules / schedule |
| CI 結構 | 無(被描述) | 無 | 無 | jobs → steps | stages → jobs |
| 變數/secret | ${VAR}(執行期注入) | frontmatter 變數 | 無 | env / secrets | variables / CI/CD variables |
| 驗證工具 | yamllint / schema | markdownlint | JSON Schema | actionlint | GitLab CI Lint API |
| 安全性關注 | safe_load / Billion Laughs | XSS(渲染時) | prototype pollution | expression 注入 / secret 外洩 | runner 隔離 / secret 外洩 |
on / jobs / steps 三層結構。stages / script / rules 結構,並說明與 GitHub 的差異。.gitlab-ci.yml。${{ }} 事件資料插進 run:,防住 expression 注入。