Kubernetes Tools/Kubevirt

[KubeVirt Ep. 9] kubevirt에서 VM 관리하기 | 라이프사이클, 마이그레이션, HA

ygtoken 2025. 3. 21. 15:09
728x90

이 글에서는 KubeVirt 환경에서 가상 머신의 라이프사이클 관리, 라이브 마이그레이션, 고가용성(HA) 설정 등 운영 관리 측면에 초점을 맞춰 알아보겠습니다. Docker Desktop 환경에서의 VM 라이프사이클 관리부터 실제 프로덕션 환경에서 활용할 수 있는 스케줄링 및 로깅 기법까지 살펴봅니다.


📌 VM 라이프사이클 관리

KubeVirt는 기본적으로 VM의 전체 생명주기를 관리하는 기능을 제공합니다. 이는 VM의 생성부터 시작, 일시 중지, 중지, 재시작 및 삭제까지 포함합니다.

 

 

KubeVirt VM 라이프사이클 및 관리

 

✅ VM 상태(State) 이해하기

KubeVirt VM은 다음과 같은 주요 상태를 가질 수 있습니다:

  1. Running: VM이 실행 중인 상태
  2. Stopped: VM이 중지된 상태
  3. Paused: VM이 일시 중지된 상태
  4. Migrating: VM이 다른 노드로 마이그레이션 중인 상태
  5. Starting: VM이 시작 중인 상태
  6. Stopping: VM이 중지 중인 상태

다음 명령어로 현재 VM의 상태를 확인할 수 있습니다:

# VM 목록 및 상태 확인
kubectl get vm

# 상세 상태 확인 - VM의 모든 구성과 현재 상태를 YAML 형식으로 출력
kubectl get vm <vm-name> -o yaml

✅ 기본 VM 라이프사이클 명령어

VM을 제어하기 위한 기본 명령어를 살펴보겠습니다.

 

▶️ VM 시작/중지:

# VM 시작 - 중지된 VM을 실행 상태로 변경
kubectl virt start <vm-name>

# VM 중지 - 실행 중인 VM을 정상적으로 종료 (ACPI 신호 전송)
kubectl virt stop <vm-name>

# VM 재시작 - VM을 순차적으로 중지하고 다시 시작 (OS 재부팅과 유사)
kubectl virt restart <vm-name>

 

▶️ VM 일시 정지/재개:

# VM 일시 정지 - VM 실행을 일시 중단하지만 메모리 상태는 유지
kubectl virt pause <vm-name>

# VM 재개 - 일시 정지된 VM을 다시 실행 상태로 변경
kubectl virt unpause <vm-name>

이러한 명령어는 내부적으로 VirtualMachine 리소스의 spec.running 필드를 변경하거나 특별한 subresource API를 호출합니다.

✅ YAML 기반 VM 라이프사이클 관리

YAML을 통해 직접 VM의 상태를 관리할 수도 있습니다:

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: lifecycle-demo     # VM의 고유 이름
  labels:
    app: demo              # VM 식별 및 선택을 위한 라벨
spec:
  running: true           # VM의 실행 상태 제어 (true: 실행, false: 중지)
  template:
    metadata:
      labels:
        kubevirt.io/vm: lifecycle-demo   # virt-launcher Pod에 적용될 라벨
    spec:
      domain:
        devices:
          disks:
          - name: rootdisk               # 디스크 참조 이름 (volumes 섹션과 매칭)
            disk:
              bus: virtio                # 디스크 버스 타입 (virtio: 최적화된 가상화 드라이버)
          interfaces:
          - name: default                # 네트워크 인터페이스 이름 (networks 섹션과 매칭)
            masquerade: {}               # NAT 방식 네트워킹 사용
        resources:                       # VM에 할당할 리소스
          requests:                      # 최소 필요 리소스
            memory: 1Gi                  # 메모리 요청량
            cpu: 1                       # CPU 요청량
      networks:
      - name: default                    # 인터페이스와 매칭되는 네트워크 정의
        pod: {}                          # 기본 Pod 네트워크 사용
      volumes:
      - name: rootdisk                   # 디스크와 매칭되는 볼륨 정의
        containerDisk:                   # 컨테이너 이미지 형태의 디스크
          image: quay.io/kubevirt/ubuntu:22.04   # Ubuntu 22.04 이미지 사용

 

spec.running: true를 false로 변경하고 kubectl apply를 실행하면 VM이 중지됩니다:

# VM의 running 상태를 false로 패치하여 VM 중지
kubectl patch vm lifecycle-demo --type merge -p '{"spec":{"running":false}}'

📌 VM 템플릿 활용하기

대규모 환경에서는 표준화된 VM 템플릿을 사용하는 것이 중요합니다. KubeVirt는 VM 템플릿을 통해 일관된 VM 구성을 제공합니다.

✅ VirtualMachineTemplate 이해하기

VirtualMachineInstancePreset 또는 일반적인 K8s 방식으로 커스텀 리소스를 템플릿화할 수 있습니다.

 

▶️ VM 템플릿 예시:

apiVersion: kubevirt.io/v1
kind: VirtualMachineInstancePreset
metadata:
  name: small-vm                    # 템플릿 이름
spec:
  selector:
    matchLabels:
      size: small                   # 이 라벨을 가진 VM에 프리셋 적용
  domain:
    resources:
      requests:                     # 리소스 요청 설정
        memory: 2Gi                 # 기본 메모리 설정 - 2GB
        cpu: 2                      # 기본 CPU 설정 - 2 코어
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: template-demo               # VM 이름
  labels:
    size: small                     # 위 템플릿과 매칭되는 라벨 (중요!)
spec:
  running: false                    # 초기 상태는 중지 상태
  template:
    metadata:
      labels:
        kubevirt.io/vm: template-demo
        size: small                 # 템플릿 선택자와 매칭되는 라벨 포함 (중요!)
    spec:
      domain:
        devices:
          disks:
          - name: rootdisk          # 디스크 참조 이름
            disk:
              bus: virtio           # 디스크 버스 타입
      volumes:
      - name: rootdisk              # 볼륨 정의
        containerDisk:
          image: quay.io/kubevirt/ubuntu:22.04   # Ubuntu 22.04 이미지

이 방식으로 small, medium, large와 같은 사전 정의된 크기 템플릿을 만들고 VM에 적용할 수 있습니다.

✅ Common Templates 활용하기

KubeVirt 커뮤니티는 다양한 운영체제에 대한 표준 템플릿 모음인 "Common Templates"를 제공합니다.

# Common Templates 설치 - 다양한 OS 유형별 표준 템플릿 제공
kubectl apply -f https://github.com/kubevirt/common-templates/releases/download/v0.15.0/common-templates.yaml

# 사용 가능한 템플릿 확인 - 기본적으로 openshift 네임스페이스에 설치됨
kubectl get templates -n openshift

Common Templates는 주로 OpenShift 환경을 위해 설계되었지만, 일반 Kubernetes에서도 응용할 수 있습니다.


📌 Live Migration 이해하기

KubeVirt는 VM을 한 노드에서 다른 노드로 다운타임 없이 이동하는 Live Migration 기능을 제공합니다. Docker Desktop 환경에서는 노드가 하나뿐이므로 실제 마이그레이션을 테스트할 수는 없지만, 개념과 기본 설정을 살펴보겠습니다.

✅ Live Migration 개념

Live Migration은 다음과 같은 상황에서 유용합니다:

  1. 노드 유지보수: 노드 업그레이드/패치 시 VM을 다른 노드로 이동
  2. 부하 분산: 과부하된 노드에서 VM을 다른 노드로 이동
  3. 장애 복구: 문제가 있는 노드에서 정상 노드로 VM 이동

✅ Migration 설정

실제 클러스터 환경에서 Live Migration을 활성화하려면 다음과 같은 구성이 필요합니다:

  1. Feature Gate 활성화:
apiVersion: v1
kind: ConfigMap
metadata:
  name: kubevirt-config           # KubeVirt 구성용 ConfigMap
  namespace: kubevirt             # kubevirt 네임스페이스에 생성
  labels:
    kubevirt.io: ""               # KubeVirt 컴포넌트가 인식하는 라벨
data:
  feature-gates: "LiveMigration"  # Live Migration 기능 활성화 설정
  migrations: |                   # 마이그레이션 관련 세부 설정
    parallelMigrationsPerCluster: 5       # 클러스터 전체 동시 마이그레이션 수 제한
    parallelOutboundMigrationsPerNode: 2  # 노드별 아웃바운드 마이그레이션 수 제한
    bandwidthPerMigration: 64Mi           # 마이그레이션당 대역폭 제한 (64MiB/s)
    completionTimeoutPerGiB: 800          # 1GiB당 타임아웃 시간(초)
    progressTimeout: 150                  # 진행 확인 타임아웃 시간(초)
  1. VM에서 마이그레이션 허용:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: migratable-vm             # VM 이름
spec:
  running: true                   # 실행 상태로 시작
  template:
    spec:
      domain:
        devices: # ...
        # Live Migration을 위한 메모리 설정
        memory:
          guest: 1Gi              # VM에 할당할 메모리 크기
      # 그 외 필요한 설정들...

✅ Migration 명령어

멀티노드 환경에서 마이그레이션을 시작하려면:

# VM 마이그레이션 시작 - VM을 다른 적합한 노드로 마이그레이션
kubectl virt migrate <vm-name>

# 마이그레이션 상태 확인 - VirtualMachineInstanceMigration 리소스 조회
kubectl get vmim   # VirtualMachineInstanceMigration의 약어

# 마이그레이션 취소 - 진행 중인 마이그레이션 중단
kubectl delete vmim <migration-name>

📌 VM 스케줄링 및 Affinity 관리

KubeVirt VM을 특정 노드에 스케줄링하거나 여러 노드에 분산하는 방법을 알아보겠습니다.

✅ 노드 선택기(NodeSelector) 설정

특정 노드에 VM을 배치하려면 NodeSelector를 사용할 수 있습니다:

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: node-selector-demo       # VM 이름
spec:
  template:
    spec:
      nodeSelector:               # 특정 노드에 VM을 스케줄링하기 위한 설정
        kubernetes.io/hostname: worker-node-01  # 특정 노드 이름으로 배치
      domain:
        # VM 도메인 설정...

✅ Affinity 및 Anti-Affinity 설정

노드 Affinity를 사용하여 VM 배치를 더 세밀하게 제어할 수 있습니다:

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: affinity-demo            # VM 이름
spec:
  template:
    spec:
      affinity:
        nodeAffinity:            # 노드 어피니티 설정
          requiredDuringSchedulingIgnoredDuringExecution:  # 반드시 만족해야 함
            nodeSelectorTerms:
            - matchExpressions:
              - key: node-role.kubernetes.io/compute      # 노드 라벨
                operator: In                              # 조건 연산자
                values:
                - "true"                                  # 매칭될 값
        # Pod Anti-Affinity 예시 (같은 애플리케이션의 VM들이 서로 다른 노드에 배치되도록)
        podAntiAffinity:         # Pod 간 분산 배치 설정
          preferredDuringSchedulingIgnoredDuringExecution:  # 가능하면 만족
          - weight: 100                                   # 우선순위 가중치 (1-100)
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app                                # Pod 라벨
                  operator: In
                  values:
                  - web-server                            # 특정 앱 라벨 값
              topologyKey: kubernetes.io/hostname         # 분산 기준 (호스트 단위)
      domain:
        # VM 도메인 설정...

이 설정은 node-role.kubernetes.io/compute=true 라벨이 있는 노드에 VM을 배치하며, 가능하면 app=web-server 라벨이 있는 다른 VM과 같은 노드에 배치하지 않습니다.

✅ Descheduler 활용

장기 실행 중인 클러스터에서는 Kubernetes Descheduler를 통해 VM의 재배치를 자동화할 수 있습니다:

# Descheduler 설치 (Helm 사용) - VM 자동 재분배를 위한 도구
helm repo add descheduler https://kubernetes-sigs.github.io/descheduler/
helm install descheduler descheduler/descheduler --namespace kube-system

 

Descheduler 정책 예시:

apiVersion: descheduler.k8s.io/v1alpha1
kind: DeschedulerPolicy
metadata:
  name: kubevirt-policy            # 정책 이름
  namespace: kube-system           # 시스템 네임스페이스
spec:
  strategies:
    RemoveDuplicates:              # 중복 pod 제거 전략
      enabled: true                # 활성화 여부
    LowNodeUtilization:            # 노드 자원 활용도 균형화 전략
      enabled: true
      params:
        nodeResourceUtilizationThresholds:
          thresholds:              # 저활용 노드 기준 (이하)
            cpu: 20                # CPU 사용률 20% 이하
            memory: 20             # 메모리 사용률 20% 이하
            pods: 20               # Pod 사용률 20% 이하
          targetThresholds:        # 목표 활용도 (이하)
            cpu: 70                # CPU 목표 사용률 70% 이하
            memory: 70             # 메모리 목표 사용률 70% 이하
            pods: 70               # Pod 목표 사용률 70% 이하

📌 VM의 HA(High Availability) 구성

KubeVirt에서 VM의 고가용성을 구성하는 방법을 알아보겠습니다.

✅ LiveMigration을 통한 기본 HA

LiveMigration은 유지보수 또는 계획된 다운타임 시 고가용성을 제공합니다. 노드 장애 시 자동 복구를 위해서는 추가 설정이 필요합니다.

✅ 런타임 클래스 및 우선순위 설정

VM의 재시작 및 복구 우선순위를 설정할 수 있습니다:

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: high-priority-vm           # 우선순위가 높은 VM 이름
spec:
  template:
    spec:
      priorityClassName: high-priority  # 우선순위 클래스 지정 (높은 우선순위)
      terminationGracePeriodSeconds: 30 # 종료 전 유예 시간(초)
      domain:
        # VM 도메인 설정...

 

사전에 PriorityClass를 정의해야 합니다:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority              # 우선순위 클래스 이름
value: 1000000                     # 우선순위 값 (높을수록 우선순위 높음)
globalDefault: false               # 기본 클래스 여부
description: "This priority class is used for high-priority VMs"  # 설명

✅ 자동 노드 재부팅 방지

중요한 VM의 경우 노드 재부팅을 방지하는 Pod Disruption Budget을 설정할 수 있습니다:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: vm-pdb                     # PDB 이름
spec:
  minAvailable: 1                  # 항상 최소 1개 인스턴스 유지 (중단 제한)
  selector:                        # 대상 Pod 선택
    matchLabels:
      kubevirt.io/vm: high-priority-vm  # 특정 VM에 대한 Pod 선택

📌 로그 및 이벤트 확인 방법

KubeVirt VM 관리 시 로그와 이벤트를 확인하는 방법을 알아보겠습니다.

✅ VM 로그 확인

VM 로그는 virt-launcher Pod를 통해 확인할 수 있습니다:

# VM의 Pod 이름 찾기 - VM을 호스팅하는 virt-launcher Pod 조회
kubectl get pods -l kubevirt.io/vm=<vm-name>

# VM Pod 로그 확인 - compute 컨테이너의 로그 확인 (VM 실행 관련 로그)
kubectl logs <vm-pod-name> -c compute

# VM 직접 콘솔 접속 - VM의 직접 콘솔에 연결 (시리얼 콘솔)
kubectl virt console <vm-name>

✅ VM 이벤트 확인

Kubernetes 이벤트를 통해 VM 상태 변경을 추적할 수 있습니다:

# VM 관련 이벤트 확인 - 특정 VM과 관련된 모든 이벤트 조회
kubectl get events --field-selector involvedObject.name=<vm-name>

# 모든 KubeVirt 이벤트 확인 - kubevirt 관련 모든 이벤트 필터링
kubectl get events | grep kubevirt

✅ KubeVirt 컴포넌트 로그 확인

KubeVirt 컴포넌트 자체의 로그도 문제 해결에 유용합니다:

# virt-controller 로그 - VM 라이프사이클 관리 컴포넌트 로그
kubectl logs -n kubevirt -l kubevirt.io=virt-controller

# virt-api 로그 - KubeVirt API 서버 로그
kubectl logs -n kubevirt -l kubevirt.io=virt-api

# virt-handler 로그 - 각 노드에서 실행되는 VM 관리 에이전트 로그
kubectl logs -n kubevirt -l kubevirt.io=virt-handler

📌 예약 스케줄링 설정

KubeVirt VM의 예약 실행 및 중지를 설정하는 방법을 알아보겠습니다.

✅ CronJob을 활용한 VM 자동화

Kubernetes CronJob을 사용하여 VM의 정기적인 시작/중지를 자동화할 수 있습니다:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: start-vm-weekdays          # CronJob 이름 - 평일 VM 시작
spec:
  schedule: "0 8 * * 1-5"          # cron 스케줄 표현식 (평일 오전 8시)
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: vm-operator  # 권한을 가진 서비스 계정
          containers:
          - name: kubectl                 # kubectl 명령어 실행용 컨테이너
            image: bitnami/kubectl:latest # kubectl 이미지
            command:                      # VM 시작 명령어
            - /bin/sh
            - -c
            - "kubectl virt start scheduled-vm"
          restartPolicy: OnFailure        # 실패 시 재시작 정책
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: stop-vm-weekdays           # CronJob 이름 - 평일 VM 중지
spec:
  schedule: "0 18 * * 1-5"         # cron 스케줄 표현식 (평일 오후 6시)
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: vm-operator  # 권한을 가진 서비스 계정
          containers:
          - name: kubectl
            image: bitnami/kubectl:latest
            command:                      # VM 중지 명령어
            - /bin/sh
            - -c
            - "kubectl virt stop scheduled-vm"
          restartPolicy: OnFailure

 

이를 위해서는 VM을 시작/중지할 수 있는 권한을 가진 서비스 계정이 필요합니다:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: vm-operator               # 서비스 계정 이름
  namespace: default              # 네임스페이스
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: vm-operator               # 역할 이름
  namespace: default              # 네임스페이스
rules:
- apiGroups: ["kubevirt.io"]      # KubeVirt API 그룹
  resources: ["virtualmachines", "virtualmachines/status"]  # 접근 가능 리소스
  verbs: ["get", "list", "update", "patch"]                 # 허용 작업
- apiGroups: ["subresources.kubevirt.io"]                   # 서브리소스 API 그룹
  resources: ["virtualmachines/start", "virtualmachines/stop"]  # VM 시작/중지 서브리소스
  verbs: ["update"]                                         # 허용 작업
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: vm-operator               # 역할 바인딩 이름
  namespace: default              # 네임스페이스
subjects:
- kind: ServiceAccount            # 바인딩 대상 종류
  name: vm-operator               # 서비스 계정 이름
roleRef:
  kind: Role                      # 참조할 역할 종류
  name: vm-operator               # 역할 이름
  apiGroup: rbac.authorization.k8s.io

✅ 자동 스냅샷 설정

CDI(Containerized Data Importer)를 사용하여 VM 디스크의 정기적인 스냅샷을 생성할 수 있습니다:

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: vm-disk-snapshot          # 스냅샷 이름
spec:
  volumeSnapshotClassName: csi-hostpath-snapclass  # 스냅샷 클래스 (CSI 드라이버 지원 필요)
  source:
    persistentVolumeClaimName: vm-disk-pvc         # 대상 PVC 이름

CronJob을 사용하여 이 스냅샷을 정기적으로 생성할 수 있습니다.

Summary

이번 글에서는 KubeVirt에서 VM을 효과적으로 관리하는 방법에 대해 알아보았습니다. 핵심 내용을 요약하면:

  1. VM 라이프사이클 관리는 kubectl virt 명령어나 spec.running 필드를 통해 가능
  2. VM 템플릿을 활용하여 일관된 VM 구성 유지 가능
  3. Live Migration을 통해 다운타임 없이 VM을 다른 노드로 이동 가능
  4. NodeSelector와, Affinity 설정을 통해 VM 배치 최적화 가능
  5. PriorityClass, PDB 등을 활용한 VM의 HA 구성 가능
  6. 로그와 이벤트를 통해 VM 상태 모니터링 가능
  7. CronJob을 활용한 VM 예약 스케줄링 설정 가능
728x90