ทำความเข้าใจ YAML
YAML (YAML Ain't Markup Language) คือรูปแบบการจัดเก็บข้อมูลที่ออกแบบมาให้อ่านง่ายสำหรับมนุษย์ ใช้อย่างแพร่หลายในไฟล์ Config, CI/CD pipelines, Infrastructure as Code และ Kubernetes manifests
YAML คืออะไร?
YAML เป็น Superset ของ JSON หมายความว่าไฟล์ JSON ทุกไฟล์ถือเป็น YAML ที่ถูกต้องด้วย แต่ YAML มี syntax ที่กระชับและอ่านง่ายกว่า เหมาะสำหรับไฟล์ที่มนุษย์ต้องแก้ไขบ่อย
เหตุผลที่ YAML ได้รับความนิยม
- อ่านง่าย — ไม่มีวงเล็บหรือ quote มากเกินไป
- รองรับ Comment — ใส่
#เพื่อเขียน comment ได้ - ยืดหยุ่น — รองรับ multiline string และโครงสร้างซับซ้อน
- มาตรฐาน DevOps — ใช้ใน Docker Compose, Kubernetes, Ansible, GitHub Actions
โครงสร้างและชนิดข้อมูล
YAML ใช้ การย่อหน้า (indentation) ด้วย space (ไม่ใช่ tab) เพื่อแสดงโครงสร้าง
ชนิดข้อมูลพื้นฐาน
# String
name: "Alice"
message: Hello World # ไม่ต้องใส่ quote ก็ได้
# Number
age: 30
price: 9.99
negative: -5
# Boolean
isActive: true
isDeleted: false
# Null
address: null
nickname: ~ # ~ ก็หมายถึง null
# Date
createdAt: 2024-06-15
Object (Mapping)
user:
name: Alice
email: [email protected]
age: 25
profile:
avatar: https://example.com/avatar.png
bio: "นักพัฒนาซอฟต์แวร์"
Array (Sequence)
# Block style
fruits:
- apple
- banana
- cherry
# Flow style (เหมือน JSON)
fruits: [apple, banana, cherry]
# Array of objects
users:
- name: Alice
age: 25
- name: Bob
age: 30
Multiline String
# Literal block (|) — เก็บ newline ไว้
description: |
บรรทัดแรก
บรรทัดสอง
บรรทัดสาม
# Folded block (>) — แปลง newline เป็น space
summary: >
บรรทัดนี้จะถูก
รวมเป็นบรรทัดเดียว
โดยอัตโนมัติ
ตัวอย่างการใช้งานจริง
Docker Compose
# docker-compose.yml
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
db:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: your_secure_password_here
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
GitHub Actions
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
Kubernetes Deployment
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:1.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: production
การใช้งานใน Python
import yaml
# อ่านไฟล์ YAML
with open("config.yaml", "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
print(config["database"]["host"])
# เขียนไฟล์ YAML
data = {
"app": "my-service",
"version": "1.0.0",
"features": ["auth", "api", "dashboard"]
}
with open("output.yaml", "w", encoding="utf-8") as f:
yaml.dump(data, f, allow_unicode=True, default_flow_style=False)
# Parse YAML string
yaml_string = """
name: Alice
tags:
- python
- developer
"""
parsed = yaml.safe_load(yaml_string)
print(parsed["name"]) # Alice
หมายเหตุ: ใช้
yaml.safe_load()เสมอ (ไม่ใช่yaml.load()) เพื่อป้องกันช่องโหว่ด้านความปลอดภัย
การใช้งานใน JavaScript/Node.js
import { parse, stringify } from 'yaml'; // หรือใช้ js-yaml
// Parse YAML string
const yamlString = `
name: Alice
age: 25
tags:
- developer
- designer
`;
const data = parse(yamlString);
console.log(data.name); // Alice
console.log(data.tags); // ['developer', 'designer']
// แปลง object เป็น YAML string
const obj = { name: 'Bob', active: true, scores: [10, 20, 30] };
const yaml = stringify(obj);
console.log(yaml);
// name: Bob
// active: true
// scores:
// - 10
// - 20
// - 30
การใช้งานใน Go
package main
import (
"fmt"
"gopkg.in/yaml.v3"
)
type Config struct {
Name string `yaml:"name"`
Port int `yaml:"port"`
Features []string `yaml:"features"`
}
func main() {
// Parse YAML
yamlStr := `
name: my-app
port: 8080
features:
- auth
- logging
`
var config Config
yaml.Unmarshal([]byte(yamlStr), &config)
fmt.Println(config.Name) // my-app
fmt.Println(config.Port) // 8080
// Marshal to YAML
out, _ := yaml.Marshal(config)
fmt.Println(string(out))
}
YAML Anchors และ Aliases
Anchors (&) และ Aliases (*) ช่วยลดการเขียนซ้ำ
# กำหนด anchor
defaults: &defaults
timeout: 30
retries: 3
logLevel: info
# ใช้ alias
production:
<<: *defaults # Merge key — รับค่าจาก defaults
logLevel: warn # Override เฉพาะที่ต้องการ
staging:
<<: *defaults
timeout: 60
กฎที่ควรระวัง
Indentation ต้องใช้ Space ไม่ใช่ Tab
# ✅ ถูกต้อง (space)
parent:
child: value
# ❌ ผิด (tab)
parent:
child: value
String ที่มีอักขระพิเศษต้องใส่ Quote
# ✅ ใส่ quote ป้องกันการตีความผิด
version: "1.0" # ไม่ใส่จะกลายเป็น number
active: "true" # ไม่ใส่จะกลายเป็น boolean
colon: "key: value" # มี : ต้องใส่ quote
ตัวเลขพิเศษ
# ค่าเหล่านี้ถูก parse เป็นชนิดที่ไม่ใช่ string
infinity: .inf
not-a-number: .nan
octal: 0o17 # 15 ในฐาน 8
hex: 0xFF # 255 ในฐาน 16
เปรียบเทียบ YAML กับ JSON
# YAML — อ่านง่ายกว่า รองรับ comment
name: Alice # ชื่อผู้ใช้
age: 25
tags:
- developer
- designer
// JSON — เหมาะกับ API และการส่งข้อมูล
{
"name": "Alice",
"age": 25,
"tags": ["developer", "designer"]
}
| คุณสมบัติ | YAML | JSON |
|---|---|---|
| Comment | ✅ รองรับ | ❌ ไม่รองรับ |
| Multiline string | ✅ ง่าย | ❌ ต้องใช้ \n |
| การอ่าน | ✅ ง่ายกว่า | ปานกลาง |
| Parse ง่าย | ปานกลาง | ✅ ง่ายกว่า |
| ใช้กับ API | ❌ ไม่นิยม | ✅ มาตรฐาน |
| ใช้กับ Config | ✅ มาตรฐาน | ปานกลาง |
แนวทางปฏิบัติที่ดี
- ใช้ 2 spaces สำหรับการย่อหน้า (มาตรฐานที่นิยมที่สุด)
- ใส่ quote string ที่คลุมเครือ — โดยเฉพาะ
true,false,null,yes,no - ตรวจสอบด้วย linter — ใช้
yamllintเพื่อหาข้อผิดพลาด - ระวัง trailing space — อาจทำให้ parse ผิดพลาด
- ใช้
safe_loadใน Python — ไม่ใช้load()เพื่อความปลอดภัย
เครื่องมือที่เกี่ยวข้อง
- JWT Decoder — JWT ใช้ JSON ซึ่งเป็น Subset ของ YAML
- Base64 Encoder — ข้อมูลใน YAML มักถูก Base64 encode
- URL Encoder/Decoder — เข้ารหัสข้อมูลสำหรับใช้ใน URL