07 · OpenStack on Kubernetes — 컨트롤 플레인은 파드로, VM은 여전히 베어메탈의 KVM으로
OpenStack on Kubernetes에서 Kubernetes가 배포하는 대상은 VM을 관리하는 OpenStack 서비스입니다. OpenStack-Helm에서는 API·scheduler·conductor와 MariaDB·RabbitMQ가 파드로 실행되고, VM은 컴퓨트 노드의 libvirt와 QEMU/KVM이 실행합니다. VM 하나를 호스트의 QEMU 프로세스 하나에 대응시킨 설명은 libvirt 문서를 바탕으로 한 이 글의 정리입니다.
이 구성이 모두 같은 배포 방식을 뜻하지는 않습니다. OpenStack-Helm은 컴퓨트 노드의 nova-compute와 libvirt도 파드로 배포합니다. RHOSO(Red Hat OpenStack Services on OpenShift)는 업스트림 문서 기준으로 컨트롤 플레인만 Kubernetes에 두고 컴퓨트 노드는 별도로 관리합니다. RHOSO 제품 문서 본문은 확인하지 못했습니다.
조사 기준일은 2026-10-05이며 Nova 문서는 latest(34.1.0.dev22), OpenStack-Helm 소스는 GitHub 미러의 master를 읽었습니다. ✓는 원문 직접 확인, Ⓥ는 벤더·프로젝트 주장, Ⓑ는 벤치마크 수치, ≈는 눈대중·역산, Σ는 여러 사실을 이은 종합 추론, ?는 미확인입니다. 각 절의 접힌 표에 출처와 세부 조건을 두었으며, 소스에서 읽은 설계 의도와 실제 동작을 시험한 결과를 구분합니다. KubeVirt 자체의 구성은 04 KubeVirt에서 다룹니다.
1. 무엇이 파드가 되고 무엇이 호스트에 남는가
OpenStack-Helm은 VM 관리 서비스를 파드로 배포하지만 VM 자체를 Kubernetes 객체로 만들지는 않습니다. 컴퓨트 노드에서 하이퍼바이저를 조작하는 nova-compute와 QEMU를 생성·감독하는 libvirtd도 파드에 포함됩니다. libvirt는 호스트에서 QEMU 바이너리를 실행합니다.
도식 텍스트
- Kubernetes 위의 컨트롤 서비스 파드
- 베어메탈 컴퓨트 노드
- nova-api — Deployment
- RabbitMQ — StatefulSet
- scheduler · conductor — Deployment
- MariaDB — StatefulSet
- kubelet — 컴퓨트 노드 라벨
- nova-compute — DaemonSet 파드
- libvirtd — DaemonSet 파드 · privileged
- QEMU 프로세스 = VM — /dev/kvm · 파드 cgroup 밖
- RPC
- RPC
- 기록
- RPC
- libvirt
- 실행
- 파드 기동
| 컴포넌트 | 하는 일 | 형태(OpenStack-Helm 소스) |
|---|---|---|
| nova-api | REST 요청을 받아 큐로 넘김 | Deployment |
| nova-scheduler | 인스턴스를 놓을 호스트 선택 | Deployment(StatefulSet 템플릿도 있음) |
| nova-conductor | 생성·리사이즈처럼 조율이 필요한 요청 처리, 컴퓨트 노드 대신 DB 접근 | Deployment(StatefulSet 템플릿도 있음) |
| Placement | 호스트별 자원 재고와 사용량 추적 | 별도 차트(placement) |
| MariaDB | 컨트롤 서비스의 DB. 기본 3개 복제본 | StatefulSet |
| RabbitMQ | 서비스 사이 RPC 메시지 큐. 기본 2개 복제본 | StatefulSet |
| nova-compute | 컴퓨트 노드마다 하나. 큐에서 요청을 받아 하이퍼바이저를 조작 | DaemonSet. hostNetwork·hostPID·hostIPC·privileged |
| libvirtd | QEMU 프로세스의 생성·감독 | DaemonSet. hostNetwork·hostPID·hostIPC·privileged |
| Open vSwitch, OVN controller, neutron OVS agent | VM 네트워크 데이터 경로 | DaemonSet. hostNetwork |
| QEMU/KVM 프로세스 | VM 하나의 CPU·메모리 실행 | 호스트 프로세스 |
API·scheduler·conductor는 DB와 큐를 이용하고 RPC(다른 프로세스의 기능을 호출하는 방식)로 통신합니다. 이 특성상 컨트롤 서비스를 Deployment나 StatefulSet으로 다루기 쉬울 것으로 해석했습니다. 컴퓨트 노드에서는 kubelet이 nova-compute와 libvirt 파드를 띄우지만, 시작 스크립트에는 QEMU의 수명을 파드와 분리하려는 설정이 있습니다. 파드 재시작의 영향과 이 해석의 한계는 4절에서 다룹니다.
컴퓨트 서비스 파드는 호스트 자원에 접근해야 합니다. DaemonSet은 대상 노드마다 파드를 띄우고, hostNetwork는 노드의 네트워크 네임스페이스를 쓰게 하며, hostPID는 노드의 프로세스를 파드에서 볼 수 있게 합니다. libvirt 문서에 따르면 KVM을 쓰려면 /dev/kvm도 필요합니다.
nova-compute가 DB에 직접 접근하지 않고 conductor를 거치는 이유는 업그레이드 때의 통신 호환성입니다. Nova 문서는 DB 접근을 conductor가 맡으면 컨트롤 플레인을 먼저 업그레이드해도 이전 릴리스의 컴퓨트 노드와 통신할 수 있다고 설명합니다.
근거와 측정 조건
| 주장 | 수치·조건 | 출처 | 근거 |
|---|---|---|---|
| nova-api의 역할과 배포 형태 | REST 요청을 받아 큐로 넘김. Deployment | Nova 문서(역할), OpenStack-Helm 소스(배포 형태·기본값) | ✓ |
| nova-scheduler의 역할과 배포 형태 | 인스턴스를 놓을 호스트 선택. Deployment이며 StatefulSet 템플릿도 있음 | Nova 문서(역할), OpenStack-Helm 소스(배포 형태·기본값) | ✓ |
| nova-conductor의 역할과 배포 형태 | 생성·리사이즈처럼 조율이 필요한 요청 처리, 컴퓨트 노드 대신 DB 접근. Deployment이며 StatefulSet 템플릿도 있음 | Nova 문서(역할), OpenStack-Helm 소스(배포 형태·기본값) | ✓ |
| Placement의 역할과 배포 형태 | 호스트별 자원 재고와 사용량 추적. 별도 차트(placement) | Nova 문서(역할), OpenStack-Helm 소스(배포 형태·기본값) | ✓ |
| MariaDB의 역할과 기본값 | 컨트롤 서비스의 DB. StatefulSet, 기본 3개 복제본 | Nova 문서(역할), OpenStack-Helm 소스(배포 형태·기본값) | ✓ |
| RabbitMQ의 역할과 기본값 | 서비스 사이 RPC 메시지 큐. StatefulSet, 기본 2개 복제본 | Nova 문서(역할), OpenStack-Helm 소스(배포 형태·기본값) | ✓ |
| nova-compute의 역할과 배포 형태 | 컴퓨트 노드마다 하나. 큐에서 요청을 받아 하이퍼바이저를 조작. DaemonSet, hostNetwork·hostPID·hostIPC·privileged | Nova 문서(역할), OpenStack-Helm 소스(DaemonSet·호스트 설정) | ✓ |
| libvirtd의 역할과 배포 형태 | QEMU 프로세스의 생성·감독. DaemonSet, hostNetwork·hostPID·hostIPC·privileged | Nova 문서(역할), OpenStack-Helm 소스(DaemonSet·호스트 설정) | ✓ |
| VM 네트워크 데이터 경로의 배포 형태 | Open vSwitch, OVN controller, neutron OVS agent. DaemonSet, hostNetwork | OpenStack-Helm 소스 | ✓ |
| QEMU/KVM 프로세스와 VM의 관계 | VM 하나의 CPU·메모리 실행을 담당하는 호스트 프로세스라는 정리 | libvirt 문서 | ✓ ≈ |
| libvirt의 QEMU 실행 방식과 KVM 사용 조건 | QEMU 바이너리 하나를 실행하는 방식. KVM을 쓰려면 /dev/kvm 필요 | libvirt 문서 | ✓ |
2. VM 하나가 만들어지는 경로
VM 생성 요청은 컨트롤 서비스 파드 사이를 큐로 오가다가 선택된 컴퓨트 노드의 nova-compute에 도착합니다. 아래 순서는 Nova 문서에 나온 개별 컴포넌트의 역할을 연결한 종합이며, 이 요청 경로에는 Kubernetes API가 등장하지 않습니다.
도식 텍스트
- nova-api
- nova-conductor
- scheduler · Placement
- nova-compute
- libvirtd · QEMU
- REST 요청 수신 · 인스턴스를 DB에 기록
- 1. 생성 요청 (큐)
- 2. 호스트 선택 요청
- Placement로 후보 조회 · 후보 중 호스트 선택
- 3. 선택한 호스트
- 4. 빌드 요청 (큐)
- 5. 도메인 정의·시작
- QEMU 프로세스 실행 · = VM
- 6. 상태 갱신 (DB는 conductor 경유)
Placement는 호스트의 자원 재고와 사용량을 기록해 후보를 제공하고, scheduler가 인스턴스를 놓을 호스트를 고릅니다. conductor는 생성·리사이즈를 조율하며 컴퓨트 노드 대신 DB에 접근합니다.
요청을 받은 nova-compute는 하이퍼바이저가 있는 노드에서 동작합니다. Nova 문서의 기본 구성에서는 libvirt를 거쳐 KVM·QEMU를 사용합니다. 문서는 conductor를 nova-compute와 같은 노드에 두지 않도록 안내합니다.
컴퓨트 노드를 나누는 단위도 Nova가 관리합니다.
| 단위 | 누가 보는가 | 하는 일 |
|---|---|---|
| cell | 운영자 | 컴퓨트 노드를 샤딩. 셀마다 DB·큐·conductor가 따로 있음 |
| availability zone(AZ) | 사용자 | 사용자가 고르는 논리 구역. aggregate에 메타데이터를 붙여 정의 |
| host aggregate | 운영자 | 임의의 특성으로 호스트를 나눔. 운영자가 flavor와 연결 |
Nova 문서는 AZ 자체가 장애 도메인을 뜻하지는 않는다고 명시합니다. region 아래의 cell과 AZ를 서로 다른 축으로, host aggregate를 AZ 아래에 붙는 묶음으로 설명한 것은 이 글의 종합입니다.
cell·AZ·host aggregate는 Nova DB의 레코드입니다. Kubernetes 쪽에서 배포 대상을 지정할 때는 OpenStack-Helm과 MOSK의 openstack-compute-node=enabled 노드 라벨이나 RHOSO의 OpenStackDataPlaneNodeSet CR(사용자 정의 리소스)을 사용합니다. 이 차이를 종합하면 라벨과 CR은 nova-compute를 설치할 노드를 정하고, 그 뒤 개별 VM을 배치할 호스트는 Nova가 정하는 관계입니다.
근거와 측정 조건
| 주장 | 수치·조건 | 출처 | 근거 |
|---|---|---|---|
| nova-compute의 실행 위치와 기본 하이퍼바이저 | 하이퍼바이저가 있는 노드에서 한 프로세스씩 실행. 기본 하이퍼바이저는 libvirt를 거친 KVM·QEMU. nova.conf 설정은 compute_driver = libvirt.LibvirtDriver, virt_type = kvm | Nova 문서 | ✓ |
| Kubernetes 쪽의 노드 지정 수단 | OpenStack-Helm과 MOSK의 openstack-compute-node=enabled 노드 라벨, RHOSO의 OpenStackDataPlaneNodeSet CR | OpenStack-Helm prerequisites 문서, MOSK 문서, openstack-operator 업스트림 문서 | ✓ |
3. 컴퓨트 노드를 Kubernetes에 넣는가
OpenStack-Helm에서는 컴퓨트 노드의 kubelet이 nova-compute와 libvirt 파드를 실행합니다. RHOSO에서는 Kubernetes 안에서 실행한 Ansible이 외부 RHEL 노드에 접속해 컴퓨트 서비스를 배포합니다. RHOSO 설명은 업스트림 저장소의 asciidoc을 근거로 했으며 RHOSO 18 제품 문서 본문은 확인하지 못했습니다.
| 구분 | 전부 Kubernetes | 컨트롤만 Kubernetes |
|---|---|---|
| 대표 | OpenStack-Helm, MOSK, Yaook | RHOSO |
| 컴퓨트 노드의 kubelet | 있음. 노드 라벨로 대상 선택 | 없음. RHEL 노드를 Ansible로 관리 |
| nova-compute·libvirt | OpenStack-Helm은 DaemonSet 파드. Yaook의 배포 단위는 아래 구현 표 참조 | 호스트의 RPM 또는 podman 컨테이너 |
| 컴퓨트 노드 배포 | helm 또는 오퍼레이터가 파드를 만듦 | OpenStackDataPlaneDeployment가 Ansible을 실행해 SSH로 접속 |
| 노드 유지보수 | kubectl drain은 맞지 않음. DaemonSet 파드는 drain 대상이 아니고 VM은 Kubernetes 객체가 아님. Atmosphere 문서는 nova host-evacuate-live 사용 | 확인하지 못함 |
| 근거 | 직접 확인 | 직접 확인·미확인 |
OpenStack-Helm의 컴퓨트 파드는 호스트 접근 권한을 넓게 사용합니다. 소스에는 nova-compute와 libvirt 모두 호스트의 네트워크·프로세스·IPC 네임스페이스를 쓰고 privileged로 실행하도록 설정되어 있습니다. libvirt는 호스트 경로도 양방향으로 마운트합니다. Yaook 문서는 privileged를 제거할 수 있는지 검토했지만, /dev/kvm 접근과 nova·libvirt 사이의 소켓 통신, 양방향 마운트 때문에 불가능하다고 결론 냈습니다.
RHOSO는 컨트롤 플레인과 데이터 플레인을 다른 수단으로 관리합니다. openstack-operator가 컨트롤 플레인 CR을 맞추고, 데이터 플레인 노드에는 Ansible이 SSH로 접속합니다. 업스트림 설계 문서는 이 경로에서 Ansible이 Deployment·Pod 같은 워크로드 API와 kubelet을 대신한다고 설명합니다. 노드에 설치되는 소프트웨어는 RPM 또는 podman 컨테이너입니다.
서비스를 파드로 배포해도 VM 이동은 별도로 처리해야 합니다. DaemonSet 파드는 drain 대상이 아니고 VM도 Kubernetes 객체가 아니므로, kubectl drain으로 컴퓨트 노드를 유지보수하기는 적합하지 않다는 판단입니다. Atmosphere 문서는 VM을 옮길 때 nova host-evacuate-live를 사용합니다. RHOSO의 해당 절차는 확인하지 못했습니다.
다른 구현은 확인한 배포 범위가 서로 달라 한 구성으로 묶기 어렵습니다. Atmosphere의 컴퓨트가 파드인지, Yaook의 nova-compute가 노드별 StatefulSet인지는 추정입니다.
| 구현 | 컨트롤 플레인 | 컴퓨트 쪽 | 상태·근거 |
|---|---|---|---|
| Canonical Sunbeam | Kubernetes 위 Charmed Operator, Rock 이미지 | 호스트의 snap | 문서 확인. snap 이름 미확인 |
| Mirantis MOSK | Rockoon 오퍼레이터가 CR을 OpenStack-Helm values로 변환 | 노드 라벨, privileged·hostPID 파드 | 문서 확인. 호스트 접근을 설명하는 서술도 문서에 있음(4절) |
| VEXXHOST Atmosphere | Ansible 컬렉션으로 배포 | libvirt에 Helm values를 넘김 | 컴퓨트가 파드라는 것은 추정 |
| Yaook | 오퍼레이터와 라벨·taint 스케줄링 | NovaComputeNode CR, 노드별 StatefulSet으로 보임 | 추정 |
| StarlingX | Kubernetes 위에 OpenStack을 애플리케이션으로 설치 | 차트가 OpenStack-Helm 기반인지 불명 | 미확인 |
| Airship | 베어메탈부터 Kubernetes와 차트 배포까지 | 확인하지 않음 | 사이트 최신 언급이 2021년. 현재 상태 미확인 |
| Kolla·kolla-ansible | Ansible이 컨테이너를 배포. Kubernetes 아님 | 같음 | 직접 확인 |
Kolla 계열은 Ansible이 컨테이너를 배포하므로 Kubernetes 배포 구성에 포함하지 않습니다. 2018-05-02 은퇴한 kolla-kubernetes의 README는 OpenStack-Helm을 대안으로 안내합니다.
근거와 측정 조건
| 주장 | 수치·조건 | 출처 | 근거 |
|---|---|---|---|
| Atmosphere의 컴퓨트 노드 유지보수 | nova host-evacuate-live 사용 | Atmosphere 문서 | ✓ |
| OpenStack-Helm nova-compute의 배포·권한 설정 | DaemonSet. hostNetwork, hostPID, hostIPC가 모두 true. 컨테이너는 privileged | OpenStack-Helm 소스 | ✓ |
| OpenStack-Helm libvirt의 배포·권한·마운트 설정 | DaemonSet. nova-compute와 같은 호스트 네임스페이스·권한 설정. /var/lib/libvirt와 /var/lib/nova를 mountPropagation: Bidirectional로 마운트 | OpenStack-Helm 소스 | ✓ |
| Yaook이 privileged를 제거할 수 없다고 판단한 이유 | /dev/kvm 접근, nova와 libvirt의 소켓 통신, Bidirectional 마운트 필요 | Yaook 문서 | ✓ |
| RHOSO 컨트롤 플레인과 데이터 플레인의 관리 경로 | openstack-operator가 컨트롤 플레인 CR을 맞춤. 데이터 플레인은 RHEL 노드. Ansible이 Deployment·Pod 같은 워크로드 API와 kubelet을 대신함. Ansible 실행은 클러스터 안의 워크로드이며 데이터 플레인 노드에는 SSH로 접속 | openstack-operator 업스트림 저장소의 설계 문서·asciidoc | ✓ |
| Canonical Sunbeam의 구성 | 컨트롤 플레인은 Kubernetes 위 Charmed Operator와 Rock 이미지. 컴퓨트는 호스트의 snap | Canonical Sunbeam 문서 | ✓ |
| Canonical Sunbeam의 snap 이름 | 확인하지 못함 | — | ? |
| Mirantis MOSK의 구성 | Rockoon 오퍼레이터가 CR을 OpenStack-Helm values로 변환. 컴퓨트는 노드 라벨과 privileged·hostPID 파드 사용. 호스트 접근을 설명하는 문장은 4절 참조 | Mirantis MOSK 문서 | ✓ |
| VEXXHOST Atmosphere의 구성 | Ansible 컬렉션으로 배포. libvirt에 Helm values를 넘김 | Atmosphere 문서 | — |
| VEXXHOST Atmosphere의 추정 범위 | 컴퓨트가 파드라는 것 | — | ≈ |
| Yaook의 구성과 추정 범위 | 오퍼레이터와 라벨·taint 스케줄링, NovaComputeNode CR 사용. 노드별 StatefulSet으로 보임 | — | ≈ |
| StarlingX의 구성과 미확인 범위 | Kubernetes 위에 OpenStack을 애플리케이션으로 설치. 차트가 OpenStack-Helm 기반인지는 불명 | — | ? |
| Airship의 범위와 확인 한계 | 베어메탈부터 Kubernetes와 차트 배포까지 다룸. 컴퓨트 쪽은 확인하지 않음. 사이트 최신 언급은 2021년 | Airship 사이트 | ? |
| Kolla·kolla-ansible의 배포 방식 | Ansible이 컨트롤 플레인과 컴퓨트의 컨테이너를 배포. Kubernetes를 쓰는 계열이 아님 | — | ✓ |
| kolla-kubernetes의 은퇴와 대안 안내 | 2018-05-02 은퇴. README는 OpenStack-Helm을 대안으로 안내 | governance legacy.yaml(은퇴 날짜), kolla-kubernetes README(대안 안내) | ✓ |
4. 얻는 것과 어려운 곳
아래 표는 프로젝트와 벤더가 내세우는 이점이며 이 글이 검증한 것은 아닙니다.
| 주장 | 누가 | 내용 |
|---|---|---|
| 롤링 업데이트 | OpenStack-Helm | OpenStack-Helm이 설명하기로는 모든 업그레이드를 Helm으로 하고, 이미지 변경은 컨테이너 롤링 교체로 처리 |
| 설정 변경도 롤링 | OpenStack-Helm | OpenStack-Helm이 설명하기로는 차트의 configmap에 annotation을 달아 설정 변경이 롤링을 일으킴. 기본값은 max_unavailable: 1, max_surge: 3 |
| 자동 복구 | Airship | Airship이 설명하기로는 모든 서비스가 컨테이너이고 Kubernetes 감독으로 복구됨 |
| 선언형 조정 | MOSK, Yaook | MOSK와 Yaook이 설명하기로는 CR을 값으로 바꿔 계속 맞춤. Yaook은 변경이 없어도 주기적으로 조정한다고 설명 |
| Day 2 운영 | Red Hat 보도자료 | Red Hat 보도자료에 따르면 컨트롤 플레인 운영이 쉬워짐. “컴퓨트 노드 배포가 17.1보다 4배 빠르다"는 측정 조건이 공개되지 않음 |
이 글에서는 이점이 컨트롤 플레인에 집중된다고 해석합니다. API·scheduler·conductor가 상태를 DB와 큐에 두는 방식은 롤링 재시작과 수평 확장에 맞아 보입니다. 컴퓨트 노드에서는 DaemonSet으로 에이전트 버전을 맞출 수 있지만, VM 프로세스와 네트워크에 미치는 영향까지 파드 교체만으로 해결되지는 않습니다.
libvirt 파드와 VM의 수명
OpenStack-Helm 시작 스크립트는 libvirtd를 파드의 cgroup(프로세스의 자원을 묶어 관리하는 커널 단위) 밖에서 실행합니다. 호스트 프로세스와 경로에 접근하는 설정까지 함께 보면, 파드를 정리할 때 QEMU가 종료되지 않게 하려는 장치로 해석됩니다. 실제로 libvirt 파드를 삭제해 VM이 살아남는지는 시험하지 않았고, libvirtd 재시작이 게스트를 유지한다는 libvirt 공식 문장도 확인하지 못했습니다.
컨트롤 플레인 중단과 VM 중단도 구분해야 합니다. Nova 업그레이드 문서는 VM 중단이 없어야 한다고 적으며 nova-compute를 제외한 서비스를 내렸다 올리는 절차를 안내합니다. 여기에 VM 실행 경로에는 API·scheduler·DB·큐가 없다는 점을 연결하면, 생성·삭제·마이그레이션이 멈춰도 실행 중인 VM은 계속 돈다고 추론할 수 있습니다. 컨트롤 플레인 중단 상황을 그대로 설명한 공식 문장은 확인하지 못했습니다. 호스트 재부팅 뒤 게스트를 다시 켜는 동작은 별도 설정인 resume_guests_state_on_host_boot가 정합니다.
네트워크 파드의 교체 영향
OpenStack-Helm의 OVS·Neutron 관련 파드는 호스트 네트워크를 사용합니다. 설치 설정은 노드 NIC를 브리지에 붙이고 IP도 옮깁니다. 해당 NIC에 Kubernetes 노드 IP가 있다면 kubelet과 CNI(컨테이너 네트워크 인터페이스)가 쓰는 주소도 이동한다는 해석이 가능합니다. 테스트 환경은 CNI로 Calico를 설치하므로 한 노드에 파드용·VM용 데이터 경로가 함께 있다고 추정할 수 있습니다.
VEXXHOST는 OVS 자체에 변화가 없어도 이미지 갱신에 따른 DaemonSet 재시작이 모든 노드의 데이터 경로를 끊었다고 보고했습니다. 컴퓨트 서비스의 롤아웃을 VM 트래픽과 별개로 볼 수 없는 사례입니다. CNI와 Neutron의 공존·충돌을 설명하는 공식 문장은 확인하지 못했습니다.
DB·큐와 기반 클러스터
Galera·RabbitMQ는 StatefulSet으로 배포하지만 스토리지는 구현마다 다르게 선택합니다. MOSK와 Atmosphere는 서비스별 RabbitMQ를 사용합니다. 스토리지 차이는 5절에서 다룹니다.
OpenStack이 실행될 Kubernetes도 먼저 준비해야 합니다. OpenStack-Helm은 Kubernetes 설치를 범위 밖으로 둡니다. 설치할 OpenStack의 Nova로 그 아래 Kubernetes의 노드를 만들 수는 없으므로 별도 수단이 필요하며, 같은 의존 관계를 적용하면 Ceph도 OpenStack보다 먼저 떠 있어야 한다고 추정됩니다. Airship과 MOSK는 베어메탈 프로비저닝부터 맡는다고 설명합니다. RHOSO는 OpenShift의 Cluster Baremetal Operator와 Ironic을 사용합니다. 순환 의존 자체를 직접 다룬 공식 문장은 확인하지 못했습니다.
파드 교체 외에 남는 업그레이드 절차
Nova 문서는 Placement를 nova 서비스보다 먼저 올리도록 안내합니다. 새 코드로 DB를 동기화(cell0 포함)한 뒤 conductor를 먼저 시작하고 API를 마지막에 올리는 것이 가장 안전하다는 순서입니다. DB 다운그레이드는 지원하지 않으므로 Helm으로 이미지를 되돌려도 스키마는 돌아오지 않을 것으로 예상됩니다. Kubernetes가 파드를 차례로 교체하더라도 이 서비스 순서와 DB 작업은 차트·오퍼레이터에 반영해야 한다는 것이 문서들을 종합한 판단입니다.
MOSK 문서는 Kubernetes의 역할을 주로 오케스트레이션과 의존성 격리로 설명합니다. 여러 OpenStack 서비스가 호스트의 프로세스·네트워크에 접근하는 privileged 컨테이너로 실행된다는 설명도 함께 적고 있습니다.
근거와 측정 조건
| 주장 | 수치·조건 | 출처 | 근거 |
|---|---|---|---|
| 롤링 업데이트 주장 | 모든 업그레이드를 Helm으로 수행. 이미지 변경은 컨테이너 롤링 교체로 처리 | OpenStack-Helm | Ⓥ |
| 설정 변경에 따른 롤링 | 차트의 configmap에 annotation을 달아 설정 변경이 롤링을 일으킴. 기본값은 max_unavailable: 1, max_surge: 3 | OpenStack-Helm | Ⓥ ✓ |
| 자동 복구 주장 | 모든 서비스가 컨테이너이며 Kubernetes 감독으로 복구됨 | Airship | Ⓥ |
| 선언형 조정 | CR을 값으로 바꿔 계속 맞춤. Yaook은 변경이 없어도 주기적으로 조정 | MOSK, Yaook | Ⓥ |
| Day 2 운영과 배포 속도 주장 | 컨트롤 플레인 운영이 쉬워진다는 설명. “컴퓨트 노드 배포가 17.1보다 4배 빠르다"는 측정 조건 비공개 | Red Hat 보도자료 | Ⓥ |
| 스크립트의 주석과 마지막 명령 | “changing CGROUP is required as restart of the pod will cause domains restarts”. 마지막 줄은 cgexec -g ...:/osh-libvirt systemd-run --scope --slice=system libvirtd --listen | OpenStack-Helm libvirt 시작 스크립트 | ✓ |
| cgroup 용어와 명령 해설 | cgroup은 프로세스가 쓰는 자원을 묶는 커널 단위. 명령은 cgroup을 새로 만들어 libvirtd를 kubepods.slice 밖의 system 슬라이스에서 실행 | — | — |
| 파드 재시작과 QEMU 수명을 분리하려는 의도로 해석 | cgroup 처리, hostPID, /run·/var/lib/libvirt 호스트 경로 마운트를 함께 보면 QEMU가 컨테이너 정리에 휩쓸리지 않게 하려는 장치로 읽힘 | — | Σ |
| 기존 libvirtd 프로세스 처리 | 호스트에 이미 실행 중인 libvirtd가 보이면 kill -9로 종료하기도 함 | OpenStack-Helm libvirt 시작 스크립트 | ✓ |
| Nova 업그레이드 문서의 무중단 안내 | “There should be no VM downtime when you upgrade Nova”. nova-compute를 뺀 서비스를 모두 내렸다 올리는 절차가 있음 | Nova 업그레이드 문서 | ✓ |
| 호스트 재부팅 뒤 게스트 재시작 설정 | resume_guests_state_on_host_boot가 결정. 기본 False | Nova 설정 옵션 문서 | ✓ |
| 네트워크 파드의 호스트 접근 | OVS, neutron OVS agent, OVN controller 파드는 모두 hostNetwork. vswitchd는 privileged로 고정 | OpenStack-Helm 소스 | ✓ |
| 노드 NIC와 IP의 브리지 이동 | auto_bridge_add가 노드 NIC를 br-ex 브리지에 붙이고 인터페이스의 IP를 브리지로 옮김 | OpenStack-Helm 설치 문서 | ✓ |
| 파드용·VM용 데이터 경로의 공존 | OpenStack-Helm 테스트 환경은 CNI로 Calico를 설치하므로 한 노드에 파드용과 VM용 데이터 경로가 함께 있다는 종합 | OpenStack-Helm 테스트 환경 | Σ |
| OVS DaemonSet 롤아웃의 데이터 경로 영향 | Kubernetes가 갱신된 이미지를 감지해 롤아웃. Open vSwitch에 변화가 없어도 재시작이 모든 노드에서 데이터 경로 끊김을 일으켰다는 보고 | VEXXHOST 블로그 | Ⓥ |
| RHOSO의 OVN 업데이트 순서 | 컨트롤 플레인과 데이터 플레인의 OVN을 먼저 올린 뒤 나머지 데이터 플레인 서비스를 업데이트 | openstack-operator 업스트림 저장소의 데이터 플레인 업데이트 문서(asciidoc) | ✓ |
| MOSK의 DB·큐 구성 | 서비스마다 RabbitMQ 인스턴스를 따로 두고 Galera는 3개 이상으로 구성 | MOSK 문서 | ✓ |
| Atmosphere의 큐 구성 | 서비스별 RabbitMQ 사용 | Atmosphere 문서 | ✓ |
| 아래층 Kubernetes의 책임 범위 | Kubernetes 설치는 OpenStack-Helm 범위 밖. 예시로 든 kubeadm과 Ansible은 “not production-ready” | OpenStack-Helm 문서 | ✓ |
| 베어메탈 프로비저닝 범위 | 베어메탈 프로비저닝부터 맡는다는 설명 | Airship, MOSK | Ⓥ |
| RHOSO의 베어메탈 프로비저닝 | OpenShift의 Cluster Baremetal Operator와 Ironic 사용 | — | ✓ |
| RHOSO에서 먼저 쓰는 Ironic의 소속 | 설치할 OpenStack의 Ironic이 아닌 플랫폼의 Ironic이라는 해석 | — | Σ |
| Nova의 업그레이드 순서 | Placement를 nova 서비스보다 먼저 업데이트. 새 코드로 DB 동기화하며 cell0 포함. conductor를 먼저 시작하고 API를 마지막에 올리는 것이 가장 안전하다는 안내 | Nova 업그레이드 문서 | ✓ |
| Nova 릴리스 공존과 DB 다운그레이드 | N과 N-2 릴리스의 nova-compute가 같은 배포에 공존하는 것까지 지원. DB 다운그레이드는 지원하지 않음 | Nova 문서 | ✓ |
| 차트 업그레이드에서 남는 문제 | 이미 끝난 db_sync Job을 새 이미지로 다시 실행해야 하는 문제. 롤링 설정이 PodDisruptionBudget과 충돌할 수 있음 | OpenStack-Helm 문서 | ✓ |
| MOSK가 설명하는 Kubernetes 사용 범위 | “uses Kubernetes mostly for orchestration and dependency isolation. As a result, multiple OpenStack services are running as privileged containers with host PIDs and Host Networking enabled.” | MOSK 문서 | ✓ |
5. 스토리지는 어디서 정해지는가
컨트롤 플레인의 DB·큐는 Kubernetes StorageClass를 사용합니다. VM의 임시 디스크와 영구 볼륨은 Nova와 Cinder 설정을 따릅니다. 따라서 Kubernetes에 어떤 StorageClass를 두는지와 VM 디스크를 어디에 저장하는지는 별도로 결정됩니다.
| 대상 | 정하는 곳 | OpenStack-Helm 기본값 |
|---|---|---|
| 컨트롤 플레인 DB·큐 | Kubernetes StorageClass | general. 문서가 Ceph를 전제 |
| VM 임시 디스크 | 컴퓨트 노드 nova.conf의 [libvirt] images_type | qcow2(로컬 디스크). rbd로 바꾸면 Ceph |
| VM 영구 볼륨 | Cinder의 enabled_backends와 드라이버 | rbd(rbd1) |
OpenStack-Helm 문서는 MariaDB·RabbitMQ의 PV(퍼시스턴트 볼륨) 백엔드로 Ceph를 전제하고, StatefulSet이 general이라는 StorageClass를 찾는다고 설명합니다. MOSK 문서는 다른 선택을 보여 줍니다. Ceph CSI를 사용하지만 일부 워크로드에는 네트워크 스토리지의 지연이 맞지 않아, local-volume-provisioner의 별도 StorageClass에 Galera 파일을 둡니다. 로컬 PV는 DB 파드를 노드에 묶습니다. 이 조건을 보면 노드를 잃었을 때 Galera 복제가 필요하고, MOSK가 요구하는 최소 복제본 수와도 연결된다고 해석할 수 있습니다.
OpenStack 설계 문서는 VM 삭제와 함께 사라지는 임시 디스크와 Cinder가 맡는 영구 볼륨을 구분합니다. OpenStack-Helm의 Nova 기본값은 로컬 qcow2이고 Cinder 기본값은 RBD 드라이버입니다. libvirt 차트는 시작할 때 Ceph 키를 libvirt secret으로 등록합니다. 이 설정으로부터 VM의 RBD 볼륨은 QEMU가 Ceph에 직접 접근하며 Kubernetes CSI(컨테이너 스토리지 인터페이스)를 지나지 않는다고 해석했습니다.
이 경로에서 VM 디스크를 Kubernetes PV·PVC와 별개로 봅니다. VM 디스크 경로는 02 VM 디스크 경로에서, 로컬 디스크를 쓸 때의 가용성은 03 로컬 디스크 HA에서 다룹니다.
설정 지점이 달라도 저장소는 같을 수 있습니다. 같은 Rook-Ceph 클러스터가 컨트롤 플레인 PV와 VM의 RBD를 공급한다면, DB와 테넌트 디스크가 한 장애 도메인을 공유한다고 추정할 수 있습니다.
근거와 측정 조건
| 주장 | 수치·조건 | 출처 | 근거 |
|---|---|---|---|
| 컨트롤 플레인 DB·큐의 스토리지 결정 지점 | Kubernetes StorageClass. OpenStack-Helm 기본값은 general이며 문서는 Ceph를 전제 | OpenStack-Helm 문서 | ✓ |
| VM 임시 디스크의 결정 지점과 기본값 | 컴퓨트 노드 nova.conf의 [libvirt] images_type. OpenStack-Helm 기본값은 qcow2(로컬 디스크). rbd로 바꾸면 Ceph | Nova KVM 문서(결정 지점), nova 차트(기본값) | ✓ |
| VM 영구 볼륨의 결정 지점과 기본값 | Cinder의 enabled_backends와 드라이버. OpenStack-Helm 기본값은 rbd(rbd1) | OpenStack-Helm | ✓ |
| 컨트롤 플레인 PV의 백엔드와 StorageClass | Ceph를 MariaDB·RabbitMQ 같은 서비스의 PV 백엔드로 사용. StatefulSet이 general이라는 StorageClass를 찾음 | OpenStack-Helm 문서 | ✓ |
| mariadb 차트 기본값 | 복제본 3개, 볼륨 5Gi | mariadb 차트 | ✓ |
| MOSK의 Galera 스토리지 선택 | Ceph CSI를 쓰지만 일부 워크로드에는 지연 때문에 네트워크 스토리지가 맞지 않는다고 설명. local-volume-provisioner를 별도 StorageClass로 두고 Galera 파일을 저장 | MOSK 문서 | ✓ |
| 로컬 PV와 Galera 복제의 관계 | 로컬 PV를 쓰면 DB 파드가 노드에 묶임. 노드를 잃었을 때 Galera 복제로 버텨야 한다는 추론이며, MOSK가 최소 3개를 요구하는 조건과 연결 | — | Σ |
| Nova·Cinder 차트의 디스크 기본값 | nova 차트는 images_type: qcow2, cinder 차트는 RBD 드라이버 | nova·cinder 차트 | ✓ |
| RBD 접근 경로 | libvirt 차트는 시작할 때 Ceph 키를 libvirt secret으로 등록. 이를 바탕으로 VM의 RBD 볼륨에 QEMU가 Ceph로 직접 접근하고 Kubernetes CSI를 지나지 않는다고 설명 | libvirt 차트 | ✓ Σ |
6. KubeVirt 비교와 Kubernetes on OpenStack
KubeVirt에서는 kube-scheduler가 virt-launcher 파드를 노드에 배치합니다. OpenStack-Helm 구성에서는 nova-scheduler가 VM의 호스트를 고르고, kube-scheduler는 nova-compute DaemonSet 파드를 배치합니다. VM을 나타내는 객체도 KubeVirt의 VMI와 Nova DB의 instance로 다릅니다.
도식 텍스트
- KubeVirt: Kubernetes가 VM을 돌린다
- OpenStack on Kubernetes: Kubernetes가 OpenStack을 돌린다
- Kubernetes on OpenStack: OpenStack이 Kubernetes를 돌린다
- VMI 객체 — Kubernetes CR
- kube-scheduler — 파드를 노드에 배치
- virt-launcher 파드 — VM마다 하나 · 안에 libvirtd
- QEMU — 파드 cgroup 안
- Nova API — instance는 Nova DB
- nova-scheduler — 호스트를 선택
- nova-compute 파드 — 노드당 하나 · libvirtd도 노드당 하나
- QEMU — 파드 cgroup 밖
- Magnum · CAPO — Kubernetes 클러스터 요청
- Nova API — 노드 VM 생성
- 컴퓨트 노드의 VM — 일반 OpenStack 경로
- Kubernetes 노드 — 테넌트의 클러스터
- 파드
- 배치
- 실행
- 요청
- 선택
- 실행
- API
- 생성
- 부팅
| 항목 | KubeVirt | OpenStack on Kubernetes(OpenStack-Helm) |
|---|---|---|
| 배치 결정 | kube-scheduler | nova-scheduler와 Placement |
| VM의 API 객체 | VMI(Kubernetes CR) | Nova DB의 instance. Kubernetes는 VM을 모름 |
| libvirtd 단위 | VM마다 하나(파드 안) | 컴퓨트 노드마다 하나 |
| QEMU의 cgroup | 파드 cgroup 안 | 파드 cgroup 밖으로 일부러 뺌 |
| 파드와 VM의 생사 | 파드가 종료되면 VM 종료. virt-launcher가 VM 종료를 기다리며 파드 종료를 미룸 | libvirt 파드가 재시작해도 VM이 남도록 설계 |
| 네트워크·스토리지 | CNI·PVC | Neutron·Cinder |
KubeVirt 문서는 스케줄링·네트워크·스토리지를 Kubernetes에 맡기고 가상화 기능을 제공한다고 설명합니다. 이 글의 정리로는 KubeVirt에서 Kubernetes는 VM을 실행하고, OpenStack on Kubernetes에서는 VM 관리 소프트웨어를 실행합니다.
파드와 VM의 수명 관계도 이 구분에 연결됩니다. KubeVirt에서는 VM이 파드와 함께 종료되며 virt-launcher가 VM 종료를 기다립니다. OpenStack-Helm의 libvirt 스크립트는 파드가 재시작해도 VM이 남게 하려는 설계로 읽힙니다. 표의 후자는 소스에서 의도를 해석한 내용입니다. OpenStack on Kubernetes가 KubeVirt를 사용하지 않는다고 명시한 문장은 찾지 않았고, OpenStack-Helm과 RHOSO의 컴퓨트 경로에 KubeVirt 컴포넌트가 없다는 점만 소스와 문서에서 확인했습니다.
OpenStack 위에 만드는 Kubernetes
그림의 마지막 줄인 Kubernetes on OpenStack은 OpenStack on Kubernetes와 배포 방향이 반대입니다. Magnum은 OpenStack의 VM·베어메탈 위에 Kubernetes 클러스터를 만드는 API입니다. Cluster API Provider OpenStack(CAPO)은 Cluster API가 OpenStack API를 호출해 노드 VM을 만들게 합니다.
한 시스템에 양쪽 방향이 함께 나타날 수도 있습니다. OpenStack-Helm에는 magnum 차트가 있고, Atmosphere는 Magnum용 Cluster API 드라이버를 소개합니다. 문서들을 종합하면 OpenStack을 실행하는 아래층 Kubernetes와 테넌트가 Magnum으로 만드는 위층 Kubernetes는 서로 다른 클러스터로 볼 수 있습니다. OpenStack Foundation 백서에 따르면 CERN은 Magnum으로 200개 이상의 Kubernetes 설치를 관리합니다. 이것도 Kubernetes on OpenStack 방향의 사례입니다.
근거와 측정 조건
| 주장 | 수치·조건 | 출처 | 근거 |
|---|---|---|---|
| libvirtd의 실행 단위 | KubeVirt는 VM마다 하나이며 파드 안에서 실행. OpenStack-Helm은 컴퓨트 노드마다 하나 | — | ✓ |
| QEMU의 cgroup 위치 | KubeVirt는 파드 cgroup 안. OpenStack-Helm은 파드 cgroup 밖으로 일부러 빼려는 설계로 해석 | — | ✓ Σ |
| 파드와 VM의 수명 관계 | KubeVirt는 파드가 종료되면 VM 종료. virt-launcher는 VM 종료를 기다리며 파드 종료를 미룸. OpenStack-Helm은 libvirt 파드가 재시작해도 VM이 남도록 설계된 것으로 해석 | — | ✓ Σ |
| 네트워크·스토리지 경로 | KubeVirt는 CNI·PVC. OpenStack-Helm 구성은 Neutron·Cinder | — | ✓ Σ |
| Magnum과 CAPO의 역할 | Magnum은 OpenStack VM·베어메탈 위에 Kubernetes 클러스터를 만드는 API. Cluster API Provider OpenStack(CAPO)은 Cluster API가 OpenStack API를 불러 노드 VM을 생성 | Magnum 문서, Cluster API Provider OpenStack README | ✓ |
| 양쪽 방향을 함께 구성하는 사례 | OpenStack-Helm에 magnum 차트가 있음. Atmosphere는 Magnum용 Cluster API 드라이버를 내세움 | OpenStack-Helm 차트·Atmosphere | ✓ |
| CERN 사례의 방향과 규모 | Magnum으로 관리하는 200개 이상의 Kubernetes 설치. Kubernetes on OpenStack 방향의 사례 | OpenStack Foundation 백서 | Ⓥ |
7. 확인하지 못한 것
| 항목 | 상태 |
|---|---|
| RHOSO 18 제품 문서 본문 | docs.redhat.com이 JS로 렌더링되어 읽지 못함. 업스트림 asciidoc과 보도자료로 대체 ? |
| 컨트롤 플레인이 내려가도 VM이 돈다는 공식 문장 | 업그레이드 문서의 “no VM downtime"과 실행 경로를 바탕으로 한 추론만 있음 ? |
| libvirtd 재시작이 실행 중 게스트를 건드리지 않는다는 libvirt 문장 | 찾지 못함 ? |
| OpenStack-Helm에서 libvirt 파드를 지웠을 때 VM 생존 | 소스에서 의도만 확인했으며 실행해 보지 않음 ? |
| CNI와 Neutron 데이터 경로의 공존·충돌 설명 | 이를 설명하는 공식 문장을 찾지 못함 ? |
| 순환 의존을 직접 다룬 문장, MAAS 조합의 1차 문서 | 찾지 못함 ? |
| MOSK·Atmosphere의 libvirt cgroup 처리 | OpenStack-Helm 차트를 그대로 쓰는지 소스를 열어 보지 않음 ? |
| Sunbeam 하이퍼바이저 snap의 이름, Yaook nova-compute가 노드별 StatefulSet인지 | 확인하지 못함 ? |
| StarlingX 차트의 기반, Airship의 현재 상태 | 확인하지 못함. Airship 사이트의 최신 언급은 2021년이며 저장소 일부에는 2026-10에도 push가 있음 ? |
| 운영 사례의 규모 | AT&T 사례는 2018년 무렵 재단 백서에 “still testing"으로 적힌 계획이며 현재 상태는 모름 Ⓥ ≈ ?. SAP는 sapcc/helm-charts 저장소가 있다는 점까지 확인 ✓. CERN은 on-Kubernetes 사례가 아님 |
| OpenStack-Helm README의 “2025.2 (Dalmatian)” 표기 | 2025.2의 코드명은 Flamingo이므로 오기로 보지만 확인하지 않음 ≈ |
| Rook-Ceph 하나를 컨트롤 플레인 PV와 VM RBD가 함께 쓸 때 분리하라는 권고 | 확인하지 않음 ? |
| 성능 수치 | 조건이 명시된 자료를 찾지 못해 싣지 않음. Red Hat의 “4x faster"는 조건 비공개 Ⓥ |
참고 자료
- Nova System Architecture, Compute service overview, Upgrades — OpenStack Nova 문서. 컴포넌트 정의, 업그레이드 순서
- Host aggregates, Availability Zones, Cells (v2) — OpenStack Nova 문서. 노드 묶음
- KVM, libvirt QEMU/KVM driver — nova.conf 설정, QEMU 프로세스
- openstack/openstack-helm — master. nova·libvirt·openvswitch·mariadb·rabbitmq·cinder 차트, 설치·prerequisites·upgrades 문서
- openstack-k8s-operators/openstack-operator — main. README, design.adoc, creating-the-data-plane.adoc
- Red Hat OpenStack Services on OpenShift now generally available — Red Hat 보도자료, 2024-08-26
- Canonical OpenStack Architecture — Sunbeam
- MOSK Reference Architecture, OpenStack cluster — Mirantis. 노드 라벨, DB·큐 배치
- Atmosphere, Maintenance Guide — VEXXHOST
- Why is the Yaook Nova Container privileged? — Yaook 문서
- Zero-Downtime OpenStack Upgrades: Suppressing Open vSwitch Restarts — VEXXHOST 블로그
- Leveraging Containers and OpenStack — OpenStack Foundation 백서. AT&T·CERN 사례
- KubeVirt architecture, components — KubeVirt 저장소
- Magnum, Cluster API Provider OpenStack — 반대 방향 구도
- Storage concepts — OpenStack arch-design. 임시 디스크와 Cinder
- Airship, StarlingX OpenStack install — 자동 복구 주장, 애플리케이션 설치 구조
- kolla-kubernetes README, governance legacy.yaml — 2018-05-02 은퇴
- sapcc/helm-charts — SAP 저장소
- Yaook scheduling, Yaook operators — 라벨·taint 배치, 조정 루프
- Atmosphere RabbitMQ, Atmosphere storage — 서비스별 큐, 스토리지 기본값
- Kolla, Kolla Ansible — 비 Kubernetes 계열