본문 바로가기
Tech-BYOD

쿠버네티스 처음 본 사람의 표정: YAML은 왜 이렇게 생겼나

by simhead-peterkim 2026. 8. 4.

쿠버네티스 처음 본 사람의 표정: YAML은 왜 이렇게 생겼나

 

Introduction

쿠버네티스 튜토리얼을 처음 켜고 deployment.yaml 파일을 마주한 순간, 대다수 개발자의 표정은 하나로 통일됩니다. "도대체 점과 띄어쓰기는 왜 이렇게 많고, 괄호는 다 어디로 간 거지?" 분명 간단한 웹 애플리케이션 하나 띄우고 싶었을 뿐인데, 화면에는 apiVersion, kind, metadata, spec, selector, template, containers 같은 단어들이 줄지어 서 있습니다. 처음 보는 사람에게는 이것이 설정 파일인지, 주문서인지, 아니면 들여쓰기 수행 평가인지 헷갈릴 만합니다.

YAML은 겉보기에는 단순합니다. 중괄호도 적고, 따옴표도 적고, 사람이 읽기 쉬워 보입니다. 그런데 쿠버네티스 YAML은 막상 손으로 작성하려고 하면 갑자기 엄격해집니다. 탭 하나, 공백 두 칸, 리스트 하이픈 하나가 배포 성공과 실패를 가릅니다. 에러 메시지는 친절한 척하지만 정작 문제는 스무 줄 위의 들여쓰기일 때도 많습니다. 그래서 쿠버네티스를 처음 배우는 사람은 컨테이너 오케스트레이션보다 먼저 공백의 철학을 배우게 됩니다.

하지만 이 괴상하게 생긴 YAML 뒤에는 쿠버네티스가 인프라를 다루는 핵심 철학이 숨어 있습니다. 쿠버네티스는 사용자가 매번 "이 컨테이너를 지금 띄워라", "이 포트를 열어라", "죽었으니 다시 실행해라"라고 명령하기를 바라지 않습니다. 대신 사용자가 원하는 최종 상태를 문서로 선언하면, 쿠버네티스가 지속적으로 현재 상태를 관찰하고 그 상태에 맞추려고 움직입니다. 이 글에서는 쿠버네티스 YAML이 왜 이렇게 생겼는지, 처음 보는 사람이 어디서 헷갈리는지, 그리고 더 이상 YAML 때문에 밤을 새우지 않는 실전 방법을 함께 정리합니다.

내가 지금 프로그래밍을 하는 건가, 들여쓰기 예술을 하는 건가?

많은 개발자는 설정 파일이라고 하면 JSON, INI, TOML, HCL 같은 형식을 떠올립니다. JSON은 중괄호와 대괄호가 구조를 명확하게 보여 줍니다. Terraform에서 쓰는 HCL은 선언적이면서도 블록이 비교적 눈에 잘 들어옵니다. 그런데 YAML은 괄호 대신 공백으로 계층을 표현합니다. 처음에는 깔끔해 보이지만, 조금만 깊어지면 이 깔끔함이 묘하게 긴장감을 줍니다. 쿠버네티스에서는 이 긴장감이 특히 커집니다. 리소스 구조가 깊고, 필드 이름이 많고, 같은 단어가 여러 위치에서 반복되기 때문입니다.

예를 들어 단순한 Nginx 웹 서버 하나를 배포한다고 해도 실제로는 컨테이너 하나만 말하는 것이 아닙니다. 쿠버네티스에게는 "어떤 애플리케이션을 몇 개 띄울지", "어떤 Pod를 관리할지", "외부 또는 내부에서 어떤 방식으로 접근할지", "롤링 업데이트는 어떻게 할지" 같은 정보가 필요합니다. 그래서 Deployment 하나만으로도 YAML은 생각보다 길어집니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-web
  labels:
    app: my-web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-web
  template:
    metadata:
      labels:
        app: my-web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80

처음 보면 "웹 서버 하나 띄우는 데 왜 이렇게 많은 줄이 필요하지?"라는 생각이 자연스럽습니다. 특히 metadata가 두 번 나오고, spec도 두 번 나오고, labelsselector가 서로 비슷한 값을 반복하는 것처럼 보입니다. 그러나 이 반복은 실수가 아니라 쿠버네티스의 모델을 드러내는 구조입니다. Deployment 자체의 정보와, 그 Deployment가 만들 Pod 템플릿의 정보가 서로 다른 계층에 있기 때문입니다.

YAML의 가장 대표적인 함정은 들여쓰기입니다. JSON에서는 괄호가 닫히지 않으면 에디터가 금방 알려 줍니다. YAML에서는 구조가 공백에 의존하므로, 사람이 눈으로 보기에 비슷해도 파서는 완전히 다르게 해석할 수 있습니다. 특히 탭 문자는 YAML에서 일반적인 들여쓰기 용도로 허용되지 않습니다. 에디터가 탭을 공백처럼 보여 주면 더 위험합니다. 화면에는 정돈된 것처럼 보이지만, 실제 파일에는 탭과 스페이스가 섞여 있을 수 있습니다.

 

처음 겪는 증상 흔한 원인 실전 대응
yaml: line 12: did not find expected key 상위 필드와 하위 필드의 들여쓰기 레벨이 어긋남 문제 줄뿐 아니라 바로 위쪽 블록의 시작 위치를 함께 확인
mapping values are not allowed 콜론 뒤 공백 누락, 문자열 안 콜론 처리 실패 key: value 형식을 지키고 애매한 문자열은 따옴표 사용
적용은 됐는데 리소스가 연결되지 않음 레이블과 셀렉터 값 불일치 kubectl get pods --show-labels로 실제 라벨 확인
문법은 맞는데 의도와 다르게 동작 필드 위치가 잘못되어 다른 객체의 속성으로 들어감 kubectl explain과 스키마 검증 도구 사용

YAML 디버깅의 핵심은 "그 줄이 틀렸다"보다 "그 줄이 어느 부모 밑에 들어가야 하는가"를 보는 것입니다. 쿠버네티스 YAML은 문장보다 가계도에 가깝습니다.

쿠버네티스 YAML은 왜 하필 이렇게 생겼을까?

쿠버네티스 YAML을 이해하는 가장 빠른 방법은 "명령형"과 "선언형"의 차이를 붙잡는 것입니다. 명령형 방식은 컴퓨터에게 절차를 지시합니다. "파드(Pod)를 만들어라. 포트 80을 열어라. 컨테이너가 죽으면 다시 실행해라. 인스턴스를 3개로 늘려라." 이런 방식은 직관적입니다. 사람이 생각한 순서대로 명령을 내리기 때문입니다. 하지만 운영 환경에서는 이 방식이 금방 피곤해집니다. 서버가 죽고, 네트워크가 흔들리고, 배포 중 일부 컨테이너가 실패하고, 사람이 입력한 명령 순서가 환경마다 달라질 수 있습니다.

선언형 방식은 다르게 접근합니다. 사용자는 "내가 원하는 최종 상태는 이것이다"라고 문서로 표현합니다. 쿠버네티스는 그 문서를 읽고 현재 클러스터 상태와 비교합니다. 원하는 상태와 실제 상태가 다르면, 쿠버네티스가 스스로 차이를 줄이기 위해 작업합니다. 예를 들어 replicas: 3이라고 선언했는데 실제 파드가 2개뿐이면 하나를 더 만듭니다. 파드가 죽으면 다시 만듭니다. 노드가 사라지면 다른 노드에 새 파드를 배치하려고 시도합니다.

 

구분 명령형 접근 선언형 접근
생각의 단위 지금 실행할 명령 유지되어야 할 최종 상태
예시 kubectl run nginx Deployment YAML에 replicas, 이미지, 포트 선언
반복 실행 명령 순서와 현재 상태에 민감 같은 선언을 다시 적용해도 의도를 유지하기 쉬움
운영 장점 빠른 실험에 편함 GitOps, 리뷰, 롤백, 감사 추적에 유리

쿠버네티스 내부에서는 컨트롤러 루프가 이 선언형 모델을 계속 실행합니다. 사용자가 작성한 YAML은 API 서버에 저장되고, 컨트롤러는 spec에 적힌 원하는 상태와 status에 기록된 현재 상태를 비교합니다. 차이가 있으면 조정 작업을 수행합니다. 이 과정을 "reconciliation", 즉 조정이라고 부릅니다. 쿠버네티스가 강력한 이유는 한 번 명령하고 끝나는 도구가 아니라, 계속 관찰하고 복구하려는 시스템이라는 점입니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: desired-state-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: desired-state-demo
  template:
    metadata:
      labels:
        app: desired-state-demo
    spec:
      containers:
        - name: web
          image: nginx:1.27

위 YAML에서 사용자는 "Nginx 컨테이너를 지금 당장 세 번 실행해라"라고 절차를 명령한 것이 아닙니다. "이 애플리케이션은 항상 세 개의 복제본으로 존재해야 한다"라고 상태를 선언했습니다. 이 차이는 작아 보이지만 운영에서는 큽니다. 사람이 잠든 새벽에 파드 하나가 죽어도 쿠버네티스는 선언된 상태를 다시 맞추려고 움직입니다. 그래서 YAML은 단순 설정 파일이 아니라 클러스터와 맺는 계약서에 가깝습니다.

그렇다면 왜 JSON이 아니라 YAML일까요? 사실 쿠버네티스 API는 JSON 기반으로 동작합니다. YAML은 사용자 작성 형식으로 많이 쓰일 뿐이며, 내부적으로는 JSON과 호환되는 데이터 구조로 처리됩니다. YAML이 널리 쓰이는 이유는 사람이 읽고 쓰기에 상대적으로 편하고, 주석을 달 수 있으며, Git에 넣어 변경 사항을 리뷰하기 좋기 때문입니다. 특히 운영팀이 "이 배포에서 이미지 태그만 바뀌었는지", "리소스 제한이 추가되었는지", "서비스 포트가 변경되었는지"를 코드 리뷰처럼 확인할 수 있다는 점이 큽니다.

물론 YAML이 항상 아름답다는 뜻은 아닙니다. YAML은 간결함과 애매함 사이를 아슬아슬하게 걷습니다. 문자열처럼 보이는 값이 불리언으로 해석될 수 있고, 숫자처럼 보이는 값이 의도와 다르게 처리될 수도 있습니다. 그래서 쿠버네티스에서는 "YAML을 감으로 쓰는 습관"보다 "스키마와 도구로 검증하는 습관"이 훨씬 중요합니다.

YAML 파일의 4대 천왕 구조 한눈에 파악하기

쿠버네티스 Manifest를 처음 읽을 때는 모든 필드를 한 번에 이해하려고 하면 지칩니다. 대신 거의 모든 리소스에 등장하는 공통 뼈대 네 가지부터 보면 길이 보입니다. 그 네 가지는 apiVersion, kind, metadata, spec입니다. 이 네 줄만 알아도 낯선 YAML을 읽을 때 "지금 무엇을 만들고 있고, 이름은 무엇이며, 어떻게 동작하길 원하는가"를 빠르게 파악할 수 있습니다.

 

필드 역할 읽는 법
apiVersion 사용할 쿠버네티스 API 그룹과 버전 apps/v1이면 앱 관련 안정 API, v1이면 코어 API인 경우가 많음
kind 생성할 리소스 종류 Pod, Deployment, Service, Ingress 등 객체 타입 확인
metadata 이름, 네임스페이스, 라벨, 어노테이션 같은 식별 정보 사람과 쿠버네티스가 리소스를 찾고 연결하는 단서
spec 원하는 상태와 동작 방식 복제본 수, 컨테이너 이미지, 포트, 볼륨, 셀렉터 등 핵심 설정

이 네 가지 구조를 실제 예제로 보면 더 선명합니다. 아래 Serviceapp: my-web이라는 라벨을 가진 파드를 찾아서 80번 포트로 연결합니다. 여기서 중요한 부분은 metadata.labelsspec.selector가 같은 것이 아니라는 점입니다. metadata.labels는 Service 자신에게 붙는 이름표이고, spec.selector는 Service가 찾아야 할 Pod의 이름표 조건입니다.

apiVersion: v1
kind: Service
metadata:
  name: my-web-service
  labels:
    app: my-web
spec:
  type: ClusterIP
  selector:
    app: my-web
  ports:
    - name: http
      port: 80
      targetPort: 80

쿠버네티스에서 라벨과 셀렉터는 리소스를 이어 붙이는 접착제입니다. Service는 특정 Pod의 이름을 직접 기억하지 않습니다. Pod는 언제든 새로 만들어지고 삭제될 수 있으며, 이름도 바뀔 수 있습니다. 대신 Service는 "나는 app: my-web 라벨을 가진 Pod를 대상으로 삼겠다"라고 선언합니다. Deployment는 자신이 만드는 Pod 템플릿에 같은 라벨을 붙입니다. 그러면 Service가 해당 Pod들을 찾아 트래픽을 보냅니다. 이름으로 딱 고정하는 방식보다 훨씬 유연하지만, 처음 배우는 사람에게는 "왜 이름이 아니라 라벨로 연결하지?"라는 혼란을 줍니다.

Service가 Pod를 찾는 방식은 전화번호부가 아니라 조건 검색에 가깝습니다. "김철수에게 연결"이 아니라 "팀이 web이고 앱이 my-web인 대상에게 연결"이라고 이해하면 편합니다.

이 구조 때문에 라벨 오타는 쿠버네티스 초보자가 자주 만나는 조용한 실패입니다. YAML 문법은 맞고, 리소스도 생성되지만, Service 엔드포인트가 비어 있습니다. 이런 경우에는 애플리케이션 로그를 보기 전에 먼저 라벨을 확인해야 합니다.

kubectl get pods --show-labels
kubectl describe service my-web-service
kubectl get endpoints my-web-service

만약 kubectl get endpoints 결과가 비어 있다면, Service가 선택할 Pod를 찾지 못했다는 뜻입니다. 포트 문제처럼 보이지만 실제 원인은 selector와 Pod 라벨 불일치일 수 있습니다. 쿠버네티스를 처음 배울 때는 에러가 크게 터지지 않는 실패가 더 어렵습니다. YAML이 통과됐다는 사실은 "문법이 맞다"는 뜻이지 "설계 의도가 맞다"는 뜻은 아닙니다.

더 이상 YAML로 고통받지 않는 법

쿠버네티스 YAML을 잘 쓰는 사람은 모든 필드를 외운 사람이 아닙니다. 좋은 도구를 쓰고, 검증 가능한 흐름을 만들고, 반복되는 패턴을 템플릿화하는 사람입니다. 처음부터 수백 줄 YAML을 빈 파일에 손으로 쓰는 것은 추천하지 않습니다. 가능하면 쿠버네티스가 기본 구조를 만들어 주게 하고, 그 결과를 읽고 수정하는 방식으로 시작하는 편이 훨씬 안전합니다.

kubectl 드라이런으로 기본 템플릿 만들기

kubectl--dry-run=client -o yaml 옵션은 초보자와 숙련자 모두에게 유용합니다. 실제 클러스터에 리소스를 만들지 않고, 쿠버네티스 형식에 맞는 YAML을 출력해 줍니다. 이 출력물을 파일로 저장한 뒤 필요한 필드를 수정하면 맨땅에서 작성하는 것보다 실수가 줄어듭니다.

kubectl create deployment my-app --image=nginx --dry-run=client -o yaml > deployment.yaml
kubectl expose deployment my-app --port=80 --target-port=80 --dry-run=client -o yaml > service.yaml

생성한 파일은 바로 적용하기 전에 검증하는 습관을 들이는 것이 좋습니다. 클라이언트 측 문법 확인과 서버 측 스키마 확인은 서로 역할이 다릅니다. 클러스터 접근이 가능하다면 서버 측 드라이런이 더 실제 환경에 가깝습니다.

kubectl apply --dry-run=client -f deployment.yaml
kubectl apply --dry-run=server -f deployment.yaml
kubectl diff -f deployment.yaml

에디터 플러그인과 스키마 검증 사용하기

YAML은 눈으로만 검토하기에는 함정이 많습니다. VS Code라면 Kubernetes 확장과 YAML 확장을 함께 사용하는 것이 좋습니다. IntelliJ 계열 IDE도 Kubernetes 플러그인과 YAML 스키마 검증을 제공합니다. 핵심은 자동 완성과 빨간 밑줄을 적극적으로 믿는 것입니다. 필드 이름이 틀렸거나, 어떤 리소스에는 존재하지 않는 옵션을 넣었거나, 들여쓰기 때문에 필드 위치가 달라졌을 때 에디터가 먼저 알려 주면 디버깅 시간이 크게 줄어듭니다.

도구 효과 추천 사용 시점
VS Code Kubernetes Extension 리소스 자동 완성, 클러스터 탐색, Manifest 검증 로컬에서 YAML 작성과 간단한 클러스터 확인을 함께 할 때
YAML Schema Validator 필드 위치와 타입 오류를 빠르게 탐지 오타나 들여쓰기 오류를 줄이고 싶을 때
kubectl explain 리소스 필드의 의미를 터미널에서 확인 문서 검색 전에 특정 필드의 위치를 알고 싶을 때
K9s 또는 Lens 리소스 상태, 이벤트, 로그를 시각적으로 확인 YAML 적용 후 실제 클러스터 상태를 추적할 때
kubectl explain deployment.spec.template.spec.containers
kubectl explain service.spec.selector

Helm과 Kustomize로 반복을 줄이기

프로젝트가 커지면 YAML 파일이 늘어납니다. 개발 환경, 스테이징 환경, 운영 환경마다 이미지 태그, 복제본 수, 리소스 제한, Ingress 도메인, ConfigMap 값이 달라집니다. 이때 모든 환경의 YAML을 복사해서 조금씩 바꾸면 관리가 어려워집니다. 같은 수정이 여러 파일에 반복되고, 어느 환경만 누락되는 일이 생깁니다.

Helm은 YAML을 템플릿으로 만들고 값 파일로 차이를 주는 방식입니다. 패키지처럼 배포 단위를 관리할 수 있어 애플리케이션 배포에 널리 쓰입니다. 반면 Kustomize는 원본 YAML을 유지하면서 오버레이로 환경별 차이를 적용합니다. 쿠버네티스에 기본 통합되어 있어 kubectl apply -k로 사용할 수 있다는 장점이 있습니다.

 

접근 강점 주의점
순수 YAML 가장 명확하고 학습 초기에 구조 이해가 쉬움 환경이 늘면 중복과 복사 실수가 증가
Helm 템플릿, 값 분리, 차트 재사용에 강함 템플릿 로직이 과해지면 렌더링 결과를 추적하기 어려움
Kustomize 원본 YAML을 보존하고 환경별 오버레이 관리에 적합 복잡한 동적 템플릿에는 Helm보다 제한적
GUI/TUI 도구 상태 확인, 로그 탐색, 이벤트 추적이 빠름 선언 파일 자체를 대체하기보다 운영 관찰 도구로 쓰는 편이 안전

중요한 것은 어떤 도구를 쓰든 최종적으로 클러스터에 적용되는 YAML을 볼 수 있어야 한다는 점입니다. Helm을 쓴다면 helm template으로 렌더링 결과를 확인하고, Kustomize를 쓴다면 kubectl kustomize로 최종 Manifest를 확인해야 합니다. 템플릿 도구는 YAML을 없애는 마법이 아니라, YAML을 관리 가능한 단위로 나누는 도구입니다.

helm template my-release ./chart
kubectl kustomize overlays/prod
kubectl apply --dry-run=server -k overlays/prod

실전에서 덜 아프게 배우는 순서

쿠버네티스 YAML은 한 번에 모두 이해하려고 하면 부담스럽습니다. 그래서 학습 순서를 잘 잡는 것이 중요합니다. 처음부터 Ingress, HPA, NetworkPolicy, RBAC까지 모두 넣은 예제를 보면 구조가 아니라 혼란만 남습니다. 더 좋은 방법은 가장 작은 경로부터 시작하는 것입니다. 먼저 Pod와 Deployment의 관계를 이해하고, 그 다음 Service가 Pod를 어떻게 찾는지 확인하고, 마지막으로 Ingress나 Gateway가 외부 트래픽을 어떻게 연결하는지 확장하면 됩니다.

예를 들어 로컬 학습 환경에서는 다음 흐름이 좋습니다. 먼저 Deployment를 만들고 파드가 생성되는지 확인합니다. 그 다음 Service를 붙이고 클러스터 내부 접근을 확인합니다. 마지막으로 포트 포워딩이나 Ingress를 통해 외부 접근을 확인합니다. 각 단계에서 kubectl get, kubectl describe, kubectl logs를 사용하면 YAML과 실제 상태가 어떻게 연결되는지 몸으로 익힐 수 있습니다.

kubectl apply -f deployment.yaml
kubectl get deployments
kubectl get pods --show-labels
kubectl describe deployment my-app
kubectl logs -l app=my-app

운영 환경에서는 여기에 리소스 요청과 제한, 헬스 체크, 네임스페이스, 롤백 전략이 추가됩니다. 처음에는 선택 사항처럼 보이지만 실제 서비스에서는 중요합니다. readinessProbe가 없으면 준비되지 않은 파드로 트래픽이 갈 수 있고, resources가 없으면 클러스터 스케줄링과 장애 대응이 어려워질 수 있습니다. 쿠버네티스 YAML은 길어서 피곤한 것이 아니라, 운영에서 암묵적으로 처리하던 것들을 명시적으로 문서화하기 때문에 길어지는 경우가 많습니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: production-minded-web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: production-minded-web
  template:
    metadata:
      labels:
        app: production-minded-web
    spec:
      containers:
        - name: web
          image: nginx:1.27
          ports:
            - containerPort: 80
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 10
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 256Mi

이 예제는 처음 봤던 단순 Deployment보다 길지만, 각 줄에는 운영적 의미가 있습니다. replicas는 가용성을, readinessProbe는 트래픽 진입 시점을, resources는 클러스터 자원 사용의 예측 가능성을 다룹니다. 즉 YAML의 길이는 쿠버네티스가 귀찮아서 만든 장벽만은 아닙니다. 많은 경우 그것은 운영 규칙을 명시적으로 드러내는 비용입니다.

Frequently Asked Questions

쿠버네티스 YAML은 꼭 손으로 다 작성해야 하나요?

아닙니다. 처음에는 kubectl create ... --dry-run=client -o yaml로 기본 템플릿을 만들고 수정하는 방식을 추천합니다. 운영에서는 Helm, Kustomize, GitOps 도구를 함께 사용해 반복을 줄이는 경우가 많습니다.

YAML 문법은 맞는데 Service가 Pod에 연결되지 않는 이유는 무엇인가요?

가장 흔한 원인은 spec.selector와 Pod의 metadata.labels 불일치입니다. kubectl get pods --show-labelskubectl get endpoints 서비스명으로 실제 연결 대상을 확인해 보세요.

쿠버네티스는 왜 spec과 status를 나누나요?

spec은 사용자가 원하는 상태이고, status는 클러스터가 관찰한 현재 상태입니다. 컨트롤러는 이 둘을 계속 비교하면서 차이를 줄입니다. 이 구조 덕분에 쿠버네티스는 장애가 발생해도 원하는 상태로 돌아가려는 자동 복구 모델을 가질 수 있습니다.

Helm을 쓰면 YAML을 몰라도 되나요?

Helm은 YAML 작성을 줄여 주지만 YAML 이해를 완전히 대체하지는 않습니다. 문제가 생겼을 때는 결국 렌더링된 Manifest를 읽어야 합니다. 따라서 Helm을 쓰더라도 helm template 결과를 확인하는 습관이 필요합니다.

Key Takeaways

  • 쿠버네티스 YAML은 단순 설정 파일이 아니라 원하는 인프라 상태를 선언하는 문서입니다.
  • 들여쓰기 오류는 문법 문제처럼 보이지만 실제로는 객체 계층 문제인 경우가 많습니다.
  • apiVersion, kind, metadata, spec 네 가지를 먼저 읽으면 대부분의 Manifest 구조가 보입니다.
  • Service와 Pod의 연결은 이름이 아니라 라벨과 셀렉터로 이루어집니다.
  • 드라이런, 스키마 검증, kubectl explain, Helm, Kustomize를 사용하면 YAML 피로도를 크게 줄일 수 있습니다.

Troubleshooting / Common Gotchas

  • 탭 대신 스페이스를 사용하고, 에디터에서 탭 표시와 자동 변환을 켜 두세요.
  • 문제 줄만 보지 말고 상위 블록의 들여쓰기와 필드 위치를 함께 확인하세요.
  • 리소스는 생성됐는데 트래픽이 가지 않으면 먼저 라벨, 셀렉터, 엔드포인트를 확인하세요.
  • 템플릿 도구를 사용한 뒤에는 최종 렌더링된 YAML을 반드시 검토하세요.
  • 운영 배포 전에는 kubectl diff와 서버 측 드라이런으로 실제 변경 내용을 확인하세요.

Conclusion

쿠버네티스 YAML을 처음 본 사람의 표정이 굳어지는 것은 자연스러운 일입니다. 간단한 웹 서버 하나를 띄우려 했을 뿐인데 갑자기 들여쓰기, 라벨, 셀렉터, 컨트롤러 루프, desired state 같은 개념이 한꺼번에 등장하기 때문입니다. 하지만 이 구조를 조금만 뜯어보면 YAML은 쿠버네티스의 복잡함을 숨기는 장식이 아니라, 쿠버네티스가 운영을 자동화하는 방식을 드러내는 언어라는 점을 알 수 있습니다.

핵심은 모든 필드를 외우는 것이 아닙니다. 쿠버네티스가 선언형 시스템이라는 사실을 이해하고, specstatus의 관계를 떠올리며, 라벨과 셀렉터가 리소스를 연결한다는 원리를 잡는 것입니다. 그리고 실전에서는 드라이런으로 시작하고, 에디터 스키마 검증을 켜고, 적용 전후에 kubectl diff, describe, logs, endpoints를 확인하면 됩니다.

YAML은 처음에는 냉정한 들여쓰기 심판처럼 느껴지지만, 익숙해지면 인프라의 상태를 리뷰하고, 버전 관리하고, 재현 가능하게 만드는 공통 언어가 됩니다. 그러니 다음에 deployment.yaml을 열었을 때 괄호가 없다고 너무 서운해하지 않아도 됩니다. 그 공백들 사이에는 쿠버네티스가 클러스터를 계속 돌보고 복구하려는 꽤 단단한 철학이 들어 있습니다.

쿠버네티스 YAML 앞에서 당황한 개발자 일러스트