iT邦幫忙

2021 iThome 鐵人賽

DAY 18
0
Software Development

系統與服務雜談系列 第 18

設定檔格式 YAML

YAML

YAML的誕生不算太晚, 1.0在2004就出了, 雖然晚了JSON 5年(1999年), 但算是蠻迅速就被開發者們給接受了
相較於INI, YAML所支持的層級, 資料類型可就豐富了,
支持的結構也從來到3種(Mapping、Collection、Scalars)
它主檔的口號如下

YAML Ain't Markup Language
YAML is a human friendly data serialization
language for all programming languages.

第一句YAML Ain't Markup Language就是YAML全名了
就是希望全程式語言都能用, 對人類好閱讀跟設計.

YAML有幾個特徵

  • 使用Indent表示層級關係(越靠左的, 越上層)
    • 其實Tab不支持, 但IDE會幫忙轉成對應的Space
    • indent的space數量其實不重要, 但第一個定義出來的層級元素, 之後相同層級的元素,都需要左對齊
parent:
  son1: 1 #2個space
  son2:   #因為想要同層級, 所以同上是2個space
   grandson: 3 #4個space
   sonofgrandson: #因為想要同層級, 所以同上是4個space
       grandgrandson: 4 #隨意個space, 反正比4多

轉成對應的JSON

{
  "parent": {
    "son1": 1,
    "son2": {
      "grandson": 3,
      "sonofgrandson": {
        "grandgrandson": 4
      }
    }
  }
}
  • Case sensitive, 大小寫不同視為不同變數
    A: 1
    a: 1
    
  • # 註解, 後面整行都是註解, 隨時都能加入註解
  • JSON的super set
  • String未必要用'"包起來, 除非有必要
  • 可以型態轉型!!, 但我其實自己不懂這有什麼實際用途
  • 可以有多分Document
    • ---為開始, ...為document的結束
    • 可以多個Document, 就相同於JSON的file, 但yaml可以在一隻檔案內, 透過---...來撰寫
    • 每個Document之間彼此獨立
---
# 1nd document
ithome: 12th
...

--- 
# 2nd document
ithome: 13th
...

YAML的基本資料節點

  • Scarlar
    • String
    • Boolean
    • Integer
    • Float
    • Null
    • Timestamp (Canonical、ISO8601、Date)
ithome:
  strings:
  - Hi eveny iron man
  year: 2021
  finished: False
  beginDate: 2021-09-01
  nullType:

轉成對應的JSON

{
  "ithome": {
    "strings": [
      "Hi eveny iron man"
    ],
    "year": 2021,
    "finished": false,
    "beginDate": "2021-09-01T00:00:00.000Z",
    "nullType": null
  }
}
  • Collections
    • -[]表示
ithome:
    years:
    - 2021
    - 2020
    - 2019
    terms: [13th, 12th, 11th]

轉成對應的JSON

{
  "ithome": {
    "years": [
      2021,
      2020
    ],
    "terms": [
      "13th",
      "12th"
    ]
  }
}
  • Mapping/Dictionary/Object
    • key: value
    • 支持Nested Mapping, 如上面所描述, 用indent表示層級關係
      上面展示的例子都是Mapping了

String類型的幾種多行寫法與indicators:
|>
先看sample

preserved: |
  65 Home Runs
  0.278 Batting Average
    Mark McGwire's
      year was crippled

folded: >
  Your long
  string here.
  
  Second string here.
  
  
  Last string here.

轉成對應的JSON

{ preserved: '65 Home Runs\n0.278 Batting Average\n  Mark McGwire\'s\n    year was crippled\n',
 folded: 'Sammy Sosa completed another fine season with great stats.\n\n  63 Home Runs\n  0.288 Batting Average\n\nWhat a year!\n' }

|只要碰到yaml換行就是換行, 然後之後其他行是對齊第一行的indent, 但若是自己多打的額外indent則會被保留, 像是 Mark McGwire's跟第一行相比多縮進的兩個space, 就會被保留.

>換行方式比較特別, 要遇到空白行, 會把前一句的\n給修剪掉, 並且在最後輸出一個\n
可以看到第一個\n出現在Second前面, 因為第一個here後面有一個\n(這個被移除), 然後接一個空白行\n.
第二句最後轉出json是\n\n, 第二個here後面的\n一樣被移除, 接兩個空白行\n\n, 就輸出這兩個了

|>搭配+或是-
+就是最後多加個\n
-反之就是最後把最後的\n刪除

preserved: |
  12th
  13th

preservedPlu: |+
  12th
  13th
  
preservedMinus: |-
  12th
  13th
{ preserved: '12th\n13th\n',
  preservedPlu: '12th\n13th\n\n',
  preservedMinus: '12th\n13th' }

Anchor錨點& 與 Alias引用*

當Yaml文件中, 有多處的重複內容時, 可以透過Anchor與Alias來快速引用相同的內容.
在字串類型上的應用, 當對同一個Anchor名稱定義內容時, 能做覆寫

ithome: &anchor |
  11th
  12th
  
reuseFirst: *anchor

override: &anchor | 
  12th
  13th
  
reuseSecond: *anchor
{ ithome: '11th\n12th\n',
  reuseFirst: '11th\n12th\n',
  override: '12th\n13th\n',
  reuseSecond: '12th\n13th\n' }

陣列元素的重複引用

---
hr:
- Mark McGwire
# Following node labeled SS
- &SS Sammy Sosa
rbi:
- *SS # Subsequent occurrence
- Ken Griffey
{ hr: [ 'Mark McGwire', 'Sammy Sosa' ],
  rbi: [ 'Sammy Sosa', 'Ken Griffey' ] }

於mapping類型的應用
這裡會看到<<這個符號, 這是用來merge mapping的key
當如果需要修改原本的key, 或者新增key,
就需要<<來merge, 如果只是純引用, 則不必

defaults: &defaults
  year:  2021
  terms: 13th
  name: iT邦幫忙

development:
  *defaults

newFeature:
  <<: *defaults
  name: iT邦個忙
{ defaults: { year: 2021, terms: '13th', name: 'iT邦幫忙' },
  development: { year: 2021, terms: '13th', name: 'iT邦幫忙' },
  newFeature: { year: 2021, terms: '13th', name: 'iT邦個忙' } }

現在最常見到YAML的應用場景
大概就是Docker-Compose文件與K8S文件
範例來源DoockerCompose

version: "3.9"
x-volumes:
  &default-volume #  Anchor宣告
  driver: foobar-storage

services:
  web:
    image: myapp/web:latest
    volumes: ["vol1", "vol2", "vol3"]
volumes:
  vol1: *default-volume #  引用Anchor
  vol2:
    << : *default-volume # 引用Anchor並Merge keys
    name: volume02
  vol3:
    << : *default-volume # 引用Anchor並Merge keys
    driver: default
    name: volume-local
{ version: '3.9',
  'x-volumes': { driver: 'foobar-storage' },
  services: 
   { web: 
      { image: 'myapp/web:latest',
        volumes: [ 'vol1', 'vol2', 'vol3' ] } },
  volumes: 
   { vol1: { driver: 'foobar-storage' },
     vol2: { driver: 'foobar-storage', name: 'volume02' },
     vol3: { driver: 'default', name: 'volume-local' } } }

本日小結

YAML具有多種Type的表示, 也能透過Anchor達到內容覆用.
但其實蠻複雜的XD, 目前在WebService的傳輸協議上, 可見度很低, 幾乎還是JSON居多.
但作為像Docker-compose或k8s這種需要多組服務的設定時,
確實比起上一篇的ini, 更能表現出複雜設定時的便利性

ps. YAML 1.2.2 於2021/10/1號剛好釋出了

參考資料

YAML org


上一篇
設定檔格式INI + Service的管理工具Systemd簡介
下一篇
多容器編排與管理 Docker Compose簡介
系列文
系統與服務雜談33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言