학습 내용

9-1. 쿠버네티스 Label

Label이란? Node를 포함하여 Pod, Deployment 등 모든 리소스에 할당 가능한 key-value 쌍. 리소스의 특성을 분류하고, selector를 이용해 선택하는 데 사용한다.

metadata:
  labels:
    rel: stable
    name: mainui
    environment: dev

selector 활용:

selector:
  matchLabels:
    key: value
  matchExpressions:
    - {key: name, operator: In, values: [mainui]}
    - {key: rel, operator: NotIn, values: ["beta", "canary"]}

명령어:

kubectl get pods --selector rel=beta            # 특정 라벨 필터링
kubectl get pods --show-labels                  # 라벨과 함께 조회
kubectl label pod <pod-name> rel=stable         # 라벨 추가
kubectl label pod <pod-name> rel=beta --overwrite  # 라벨 변경

9-2. 쿠버네티스 Node Label

필요성: 워커노드의 스펙이 다를 때(GPU, SSD 등), 그 특성을 label로 설정하고 Pod를 특정 노드에 배치

kubectl label nodes node1.example.com gpu=true disk=ssd

nodeSelector 를 사용하면 해당 조건을 만족하는 노드에만 Pod가 배치됨. 조건에 맞는 노드가 없을 경우 Pod는 Pending 상태로 유지된다.

9-3. 쿠버네티스 Annotation

Label과 동일하게 key-value 형태이지만, 목적이 다르다:

  • 쿠버네티스에게 특정 정보를 전달할 용도 (예: kubernetes.io/change-cause로 롤링업데이트 히스토리 기록)
  • 운영 환경에서 관리용 메타정보 기록 (빌더, 빌드일자, 이미지 레지스트리 등)

Label은 리소스 선택(selector) 에 사용하고, Annotation은 부가 정보 기록에 사용한다.

9-4. 카나리 배포 (Label 활용 예시)

배포 방식 비교:

  • 블루/그린 업데이트: old(블루)를 new(그린)로 한 번에 전환
  • 롤링 업데이트: 점진적으로 교체
  • 카나리 배포: 기존 버전을 유지하면서 일부만 신규 버전으로 올려 모니터링 (예: 기존 80%, 신규 20%)

Label을 이용한 카나리 배포 원리:

  • stable Deployment: app: mainui, version: stable → replicas: 2
  • canary Deployment: app: mainui, version: canary → replicas: 1
  • Service의 selector는 app: mainui 만 지정 → stable과 canary Pod 모두에 트래픽 분배

실습 예제 (GitHub 237summit)

Label 없는 Pod — pod1.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
spec:
  containers:
  - name: nginx
    image: nginx:1.14
    ports:
    - containerPort: 80

Label이 있는 Pod — pod2.yaml

apiVersion: v1
kind: Pod
metadata:
  name: label-pod-demo
  labels:
    name: mainui
    rel: stable
spec:
  containers:
  - name: nginx
    image: nginx:1.14
    ports:
    - containerPort: 80

NodeSelector — nodeselector.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector
spec:
  nodeSelector:
    gpu: "true"
    disk: ssd
  containers:
  - name: nginx
    image: nginx:1.14
    ports:
    - containerPort: 80

Annotation — annotation.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-annotation
  annotations:
    builder: "seongmi Lee ([email protected])"
    buildDate: "20210502"
    imageRegistry: https://hub.docker.com/
spec:
  containers:
  - name: nginx
    image: nginx:1.14
    ports:
    - containerPort: 80

카나리 배포 — Stable Deployment (mainui-stable.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mainui-stable
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mainui
      version: stable
  template:
    metadata:
      labels:
        app: mainui
        version: stable
    spec:
      containers:
      - name: mainui
        image: nginx:1.14
        ports:
        - containerPort: 80

카나리 배포 — Canary Deployment (mainui-canary.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mainui-canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mainui
      version: canary
  template:
    metadata:
      labels:
        app: mainui
        version: canary
    spec:
      containers:
      - name: mainui
        image: nginx:1.15
        ports:
        - containerPort: 80

카나리 배포 — Service (mainui-service.yaml)

apiVersion: v1
kind: Service
metadata:
  name: mainui-svc
spec:
  selector:
    app: mainui        # version 라벨 없이 app만 지정 → stable + canary 모두 포함
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080

롤링업데이트 Deployment — deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  annotations:
    kubernetes.io/change-cause: version 1.15
spec:
  progressDeadlineSeconds: 600
  revisionHistoryLimit: 10
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  replicas: 3
  selector:
    matchLabels:
      app: webui
  template:
    metadata:
      labels:
        app: webui
    spec:
      containers:
      - name: web
        image: nginx:1.15
        ports:
        - containerPort: 80

핵심 정리

  • Label = 리소스 분류 + selector 선택용. key-value 쌍으로 모든 리소스에 할당 가능.
  • Annotation = 부가 정보 기록용. selector로 선택 불가. 운영 메타정보나 쿠버네티스 내부 기능(change-cause 등)에 활용.
  • Node Label + nodeSelector 로 특정 스펙의 노드에 Pod를 지정 배치할 수 있음.
  • 카나리 배포: Service selector를 공통 라벨(app: mainui)로 설정하고, stable/canary Deployment의 replicas 비율로 트래픽 분배를 제어.

체크리스트

  • Label과 Annotation의 차이를 설명할 수 있는가?
  • nodeSelector로 Pod를 특정 노드에 배치하는 YAML을 작성할 수 있는가?
  • 카나리 배포에서 Service selector 설계 원리를 이해했는가?
  • matchExpressions의 In, NotIn, Exists, DoesNotExist 연산자를 구분할 수 있는가?

참고 링크