alltools.one
YAML
2025-06-19
7 min
alltools.one Team
YAMLAnchorsAliasesDRYConfiguration

YAML 錨點與別名:DRY 設定模式

在 YAML 檔案的多個區段中重複相同的設定違反了 DRY(Don't Repeat Yourself)原則,並造成維護上的困擾。YAML 錨點與別名透過讓你定義一次值並多次引用來解決這個問題。

基本語法

錨點&):標記一個值以供重複使用 別名*):引用一個已標記的錨點值

# 定義錨點
defaults: &default_settings
  timeout: 30
  retries: 3
  log_level: info

# 使用別名引用
development:
  <<: *default_settings
  log_level: debug

production:
  <<: *default_settings
  retries: 5

<< 合併鍵會將引用錨點中的所有鍵值對合併進來。合併之後定義的屬性會覆寫錨點中的值。

解析後的結果:

development:
  timeout: 30
  retries: 3
  log_level: debug  # 已覆寫

production:
  timeout: 30
  retries: 5        # 已覆寫
  log_level: info

錨點類型

純量錨點

重複使用單一值:

max_connections: &max_conn 100

database:
  pool_size: *max_conn
cache:
  pool_size: *max_conn

序列錨點

重複使用整個列表:

common_ports: &ports
  - 80
  - 443

web_server:
  ports: *ports
load_balancer:
  ports: *ports

映射錨點

重複使用整個物件(最常見的模式):

logging: &log_config
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

services:
  api:
    logging: *log_config
  worker:
    logging: *log_config

合併鍵(<<

合併鍵有特定的行為規則:

  1. 它會複製引用映射中的所有鍵值對
  2. 明確設定的鍵優先於合併的鍵
  3. 多重合併按順序處理(衝突時先到先得)
# 多重合併
base: &base
  a: 1
  b: 2

extra: &extra
  b: 3
  c: 4

combined:
  <<: [*base, *extra]
  # 結果:a=1, b=2(base 優先), c=4

實際應用範例

Docker Compose

x-common: &common
  restart: unless-stopped
  networks:
    - app-network
  logging:
    driver: json-file
    options:
      max-size: "10m"

services:
  api:
    <<: *common
    image: myapp/api:latest
    ports:
      - "8080:8080"
    environment:
      DATABASE_URL: postgres://db:5432/myapp

  worker:
    <<: *common
    image: myapp/worker:latest
    environment:
      QUEUE_URL: redis://cache:6379

  scheduler:
    <<: *common
    image: myapp/scheduler:latest

Docker Compose 使用 x- 前綴慣例來定義用於存放錨點的擴充欄位。更多模式請參閱我們的 YAML 與 Docker Compose 指南。

GitHub Actions

jobs:
  test:
    runs-on: ubuntu-latest
    env: &common_env
      NODE_VERSION: '20'
      CI: true
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
      - run: npm test

  build:
    runs-on: ubuntu-latest
    needs: test
    env:
      <<: *common_env
      BUILD_TARGET: production
    steps:
      - uses: actions/checkout@v4
      - run: npm run build

Kubernetes

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: app
          resources: &resources
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
        - name: sidecar
          resources: *resources  # 相同的資源限制

限制與注意事項

1. 無法跨檔案引用

錨點僅在單一 YAML 檔案內有效。你無法引用在另一個檔案中定義的錨點。若需要跨檔案重複使用,請使用模板工具如 Helm、Jsonnet 或 Kustomize。

2. 序列無法部分覆寫

你無法合併並部分覆寫列表——只能整個取代:

base_ports: &ports
  - 80
  - 443

service:
  ports: *ports  # 你得到的就是 [80, 443]
  # 無法透過合併將 port 8080 加入此列表

替代方案:另外定義一個擴充的列表。

3. 順序很重要

錨點必須在被引用之前定義:

# 錯誤——別名在錨點之前
service:
  settings: *defaults

defaults: &defaults
  timeout: 30

# 正確——錨點在別名之前
defaults: &defaults
  timeout: 30

service:
  settings: *defaults

4. 並非所有工具都支援合併鍵

<< 合併鍵不是 YAML 核心規範的一部分——它是一個型別特定的擴充。大多數主流 YAML 解析器都支援它,但某些嚴格的解析器可能不支援。

使用我們的 YAML 驗證器來驗證你的 YAML 錨點使用方式。

常見問題

錨點在轉換 YAML 為 JSON 時會保留嗎?

不會。當 YAML 被解析時,錨點和別名會被解析為它們的實際值。產生的 JSON 會將值展開內聯。這意味著轉換為 JSON 再轉回來會失去 DRY 結構。錨點只存在於 YAML 原始格式中。

可以在複雜的巢狀覆寫中使用錨點嗎?

合併鍵(<<)只執行淺層合併——它複製錨點映射中的頂層鍵。巢狀物件會被整個替換,而非深度合併。若需要深度合併行為,你需要使用工具特定的方案(Helm 的 merge 函式、自訂 YAML 處理器)。

相關資源

Published on 2025-06-19
YAML Anchors and Aliases: DRY Configuration Patterns | alltools.one