가이드
YAML 1.1과 1.2
가장 비싼 대가를 치른 YAML 버그의 중심에는 국가 코드가 있습니다.
작성 yamltojsonfree · 게시일 · 수정일
Norway 문제란
YAML 1.1에서 따옴표 없는 y, yes, on, n, no, off는 불리언입니다 — 대문자든 소문자든 첫 글자만 대문자든. 그래서 노르웨이(NO)가 포함된 국가 코드 목록은 조용히 false가 됩니다. 아무 오류도 나지 않습니다. 문서는 파싱되고, 배포는 성공하며, 어딘가 하류에서 "불리언은 딕셔너리 키가 될 수 없고 문자열 비교에도 맞지 않는다"는 이유로 목록에서 나라 하나가 사라집니다.
2009년에 발표된 YAML 1.2는 이를 없앴습니다. 불리언은 true와 false뿐이고, 저 여섯 단어는 일반 문자열입니다. YAML 1.1의 다른 암시적 변환도 버렸습니다 — 022는 더 이상 18을 뜻하는 8진수가 아니고, 12:30은 더 이상 750을 뜻하는 60진수가 아닙니다.
문제는 15년이 넘게 지난 지금도 두 버전이 널리 쓰인다는 것입니다. 같은 파일이 여는 도구에 따라 두 가지 다른 의미를 가질 수 있습니다 — 바로 그래서 이 사이트의 YAML → JSON 변환기는 기본적으로 YAML 1.2를 사용하고, 1.1에서 다르게 읽힐 문서 내 모든 값을 표시합니다.
의미가 바뀌는 모든 값
같은 원본을 명세의 각 버전으로 읽은 결과.
| YAML 원본 | YAML 1.2 해석 | YAML 1.1 해석 | 안전한 형태 |
|---|---|---|---|
| country: NO | "NO" | false | country: "NO" |
| enabled: yes | "yes" | true | enabled: true |
| debug: off | "off" | false | debug: false |
| mode: 022 | 22 | 18 | mode: "022" |
| start: 12:30 | "12:30" | 750 | start: "12:30" |
| version: 1.10 | 1.1 | 1.1 | version: "1.10" |
마지막 줄에 주목하세요. 1.10은 숫자로 파싱되기 때문에 두 버전 모두에서 끝의 0을 잃습니다. 버전 문자열은 항상 따옴표로 감싸야 합니다.
어떤 파서가 어떤 버전을 읽는가
YAML 버전을 직접 고르는 일은 거의 없습니다 — 사용하는 도구가 의존하는 라이브러리에서 물려받습니다. 생태계는 대략 다음과 같이 나뉩니다:
| 파서 | 버전 | 비고 |
|---|---|---|
| PyYAML (Python) | YAML 1.1 | Ansible을 포함한 대부분의 Python 도구의 기본값. |
| ruamel.yaml (Python) | YAML 1.2 | 유지 관리되는 PyYAML의 후속. 옵션으로 1.1 가능. |
| js-yaml v5 (JavaScript) | YAML 1.2 | 이 사이트가 사용하는 엔진. 이전 버전은 1.1을 읽었음. |
| go-yaml / sigs.k8s.io (Go) | 대부분 1.2 | Kubernetes가 사용. 호환성을 위해 일부 1.1 동작 유지. |
| SnakeYAML (Java) | YAML 1.1 | Spring Boot 설정 로딩의 기본값. |
| libyaml (C bindings) | YAML 1.1 | PyYAML을 포함한 많은 언어 바인딩의 기반. |
실무적인 결과: 이 표의 한쪽에서 작성되고 다른 쪽에서 읽히는 파일은 값이 조용히 바뀔 수 있습니다. YAML을 Python으로 생성하고 Kubernetes가 소비한다면 — 아주 흔한 파이프라인입니다 — 버전 경계를 넘는 것입니다. 코드 수준의 자세한 내용은 코드로 YAML을 JSON으로 변환하기 가이드에 있습니다.
두 버전 모두에서 안전한 YAML 작성법
세 가지 습관이 이런 종류의 버그를 통째로 없앱니다. 다른 것으로 오해될 수 있는 모든 문자열을 따옴표로 감싸세요 — 국가 코드, 버전 번호, 앞에 0이 붙는 값, 콜론이 들어간 모든 것. 불리언은 true와 false로만 쓰고 yes, on이나 그 유사어는 절대 쓰지 마세요. 그리고 파일이 도구 사이를 오가기 전에 버전에 따라 달라지는 값을 보고하는 변환기나 검증기를 거치게 하세요 — YAML을 명시적인 JSON으로 보는 것이 의도하지 않은 타입을 잡아내는 가장 빠른 방법입니다.
참고 자료
- YAML 1.1 명세(2005) — 위에서 설명한 불리언, 8진수, 60진수 형식
- YAML 1.2.2 명세 — 불리언을 true와 false로 제한하는 core 스키마
- YAML 1.1 불리언 타입 — YAML 1.1이 불리언으로 읽는 단어의 전체 목록
- PyYAML 문서 — Python에서의 YAML 1.1 동작
- ruamel.yaml 문서 — 기본은 YAML 1.2, 옵션으로 1.1
- js-yaml — 이 사이트에서 사용하는 YAML 1.2 엔진
- sigs.k8s.io/yaml — Kubernetes가 사용하는 Go 라이브러리