Furiosa 의 NPU 를 오픈스택에서 설정해 볼 수 있는 기회가 있어서 그 사용기를 공유해 보고자 합니다.
kolla ansible 을 사용해 NPU passthrough 설정을 하여 설치합니다.
또한 passthrough 된 NPU 장치를 가진 VM 을 생성해서 쿠버네티스에서도 사용해 보겠습니다.
간단하게 다음 스펙 정도의 서버와 비슷한 스펙의 NPU 4장짜리 더해서 2대로 구성하였습니다.
32 코어 x 2 소켓
메모리 1TB
NPU 8장
OS : Ubuntu 24.04
furiosa 의 NPU 는 오픈스택에서 사용할 때 passthrough 방식만 지원합니다. passthrough 를 사용할 경우 nvidia GPU 의 passthrough 와 설정법이 다르진 않습니다.
다만 furiosa 에서 제공해 주신 오픈스택 설정 가이드에는 numa 설정과 hugepage 사용이 권고 설정으로 되어 있어 해당 설정을 같이 해보겠습니다.
iommu 설정과 passthrough 설정, hugepage 설정과 vfio 설정이 들어갑니다.
hugepage 설정값은 이후 VM 에서 사용할 수 있는 메모리 설정값이 되므로 참고하여 설정합니다.
* hugepagesz x hugepages = hugepage 사용하는 VM에서 사용할 수 있는 메모리
grep "^GRUB_CMDLINE_LINUX_DEFAULT=" /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on iommu=pt hugepagesz=2M hugepages=217088 vfio-pci.ids=1ed2:0001 pci=realloc"
# grub update
update-grub
vfio 에서 NPU 장치를 선점할 수 있도록 initramfs 업데이트까지 진행합니다.
# vfio config
echo 'options vfio-pci ids=1ed2:0001' > /etc/modprobe.d/vfio.conf
echo "vfio vfio_iommu_type1 vfio_pci" > /etc/modules-load.d/vfio.conf
# update initramfs
update-initramfs -u
passthrough 로 사용할 경우는 vfio 드라이버를 사용하므로 NPU 드라이버를 설치하지 않습니다.
VM 생성 전에 NPU cli 로 정보를 확인하고 싶거나 등의 이유가 있으면 오픈스택 배포 전에 driverctl 등으로 vfio 드라이버를 사용하도록 설정해야 합니다.
NPU 장치를 사용하려면 nova 에서만 추가 설정을 하면 됩니다. numa 설정도 포함됩니다.
vendor,product id 를 확인한 정보로 설정하고 device_type 은 PCI로 합니다.
# nova api
cat << EOF > /etc/kolla/config/nova/nova-api.conf
[pci]
alias = {"vendor_id": "1ed2", "product_id": "0001", "device_type": "type-PCI", "name": "RNGDNPU", "numa_policy": "preferred"}
device_spec = [{"vendor_id": "1ed2", "product_id": "0001"}]
EOF
일반적인 필터들에 passthorugh, numa 필터를 추가합니다.
# nova scheduler 설정 - pci passthrough filter, numa filter 추가
cat << EOF > /etc/kolla/config/nova/nova-scheduler.conf
[filter_scheduler]
available_filters = nova.scheduler.filters.all_filters
enabled_filters = ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter,ServerGroupAffinityFilter,NUMATopologyFilter,PciPassthroughFilter
EOF
numa 설정은 사전에 cpu 정보를 확인해서 적용해야 합니다. NPU 장치가 있는 numa 를 dedicated 로 설정하도록 합니다.
# nova compute - passthrough 설정, numa 설정, vfio 설정
cat << EOF > /etc/kolla/config/nova/nova-compute.conf
[libvirt]
cpu_mode = host-passthrough
[compute]
cpu_dedicated_set = "0-95"
cpu_shared_set = "96-127"
[pci]
alias = {"vendor_id": "1ed2", "product_id": "0001", "device_type": "type-PCI", "name": "RNGDNPU", "numa_policy": "preferred"}
device_spec = [{"vendor_id": "1ed2", "product_id": "0001"}]
EOF
배포 설정 부분의 nova 설정만 완료되면 일반 kolla ansible 배포와 같으므로 여기선 생략합니다.
다음은 예제로 numa 설정에 vm 에서 사용할 cpu를 dedicated 쪽으로 설정한 것입니다.
필요한 경우 numa 고정/해제, hugepage 사용 여부 등을 고려해서 해당 값을 수정하여 사용합니다.
# flavor - NPU x 1
openstack flavor create --vcpu 8 --ram 108544
--property hw:cpu_policy='dedicated'
--property hw:emulator_threads_policy='share'
--property hw:numa_nodes=2
--property hw:mem_page_size=large
--property hw:cpu_sockets=1
--property pci_passthrough:alias=RNGDNPU:1
n1v8r1
# flavor - NPU x 2
openstack flavor create --vcpu 16 --ram 217088
--property hw:cpu_policy='dedicated'
--property hw:emulator_threads_policy='share'
--property hw:numa_nodes=2
--property hw:mem_page_size=large
--property hw:cpu_sockets=1
--property pci_passthrough:alias=RNGDNPU:2
n1v16r2
# flavor - NPU x 4
openstack flavor create --vcpu 32 --ram 434176
--property hw:cpu_policy='dedicated'
--property hw:emulator_threads_policy='share'
--property hw:numa_nodes=2
--property hw:mem_page_size=large
--property hw:cpu_sockets=1
--property pci_passthrough:alias=RNGDNPU:4
n1v32r4
# flavor 생성
openstack flavor create --vcpu 64 --ram 393216
--property hw:cpu_policy='dedicated'
--property hw:emulator_threads_policy='share'
--property hw:numa_nodes=2
--property hw:cpu_sockets=1
--property hw:mem_page_size=large
--property pci_passthrough:alias=RNGDNPU:4
n1r4_crtest
# 서버 생성
openstack server create --flavor n1v32r4 --image ubuntu-22.04
--network internal-network --boot-from-volume 250 kubernetes-worker
# 콘솔에서 확인
# lspci | grep -i furiosa
00:05.0 Processing accelerators: FuriosaAI, Inc. Device 0001 (rev 01)
00:06.0 Processing accelerators: FuriosaAI, Inc. Device 0001 (rev 01)
00:07.0 Processing accelerators: FuriosaAI, Inc. Device 0001 (rev 01)
00:08.0 Processing accelerators: FuriosaAI, Inc. Device 0001 (rev 01)
오픈스택에서는 flavor 외에 특별히 설정할 부분이 없어 바로 쿠버네티스 설정으로 들어가 보겠습니다.
kubespray 를 사용하여 설치할 건데 여기서도 필요한 부분의 설정만 설명하겠습니다.
게스트 VM에서는 pci realloc 설정으로 qemu bios 의 메모리 비정상 매핑 문제를 해결할 필요가 있다고 합니다.
또한 컨테이너 런타임으로는 containerd 를 사용할 건데 NPU 를 사용할 때는 cdi 라는 플러그인을 사용하므로 해당 설정도 해야 합니다.
# /etc/default/grub
GRUB_CMDLINE_LINUX=".... pci=realloc"
# 적용
update-grub
# furiosa apt config
apt update && apt install -y curl gnupg
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg
| gpg --dearmor -o /etc/apt/trusted.gpg.d/cloud.google.gpg
echo "deb [arch=$(dpkg --print-architecture)] http://asia-northeast3-apt.pkg.dev/projects/furiosa-ai $(. /etc/os-release && echo "$VERSION_CODENAME") main"
| tee /etc/apt/sources.list.d/furiosa.list
# furiosa driver install
apt update
apt install -y build-essential linux-modules-extra-$(uname -r) linux-headers-$(uname -r)
apt install -y furiosa-driver-rngd furiosa-smi
# furiosa cdi install
apt install -y furiosa-cdi
# cdi generate
furiosa-cdi generate
# cdi check
furiosa-cdi list
kubespray 에선 containerd 의 설정 옵션을 켜면 설정되게 되어 있습니다. enable_cdi 값으로 기본값도 들어가 있지 않으므로 containerd 설정 파일에 추가합니다.
# cat inventory/group_vars/all/containerd.yml
...
enable_cdi: true
...
마찬가지로 일반 kubespray 배포 방법과 다르지 않아 생략합니다.
npu 오퍼레이터를 설치하기 위해선 node feature discovery 가 사전 설치되어 있어야 합니다.
# node feature discovery 설치
helm install -n node-feature-discovery --create-namespace nfd
oci://registry.k8s.io/nfd/charts/node-feature-discovery --version 0.18.3
# furiosa repo add
helm repo add furiosa https://furiosa-ai.github.io/helm-charts
helm repo update
# furiosa-npu-operator install
helm install furiosa-npu-operator furiosa/furiosa-npu-operator
-n furiosa-system --create-namespace
NPU 오퍼레이터 설치 후 npu 설정들은 클러스터 파일로 합니다. device plugin, metrics 등을 선택하여 설치/설정 합니다. 각 서비스들은 개별 helm 으로 설치할 수도 있습니다.
리소스 할당과 관련된 어노테이션은 devicePlugin 이나 draDriver 둘 중 하나를 선택하여 설치하고 사용합니다.
# cat example-furiosa-config.yaml
apiVersion: furiosa.ai/v1alpha1
kind: FuriosaClusterConfig
metadata:
name: example
spec:
featureDiscovery:
enabled: true
registry: docker.io/furiosaai/furiosa-ai
tag: 2026.1.0-rc0
image: furiosa-feature-discovery
devicePlugin:
enabled: true
registry: docker.io/furiosaai/furiosa-ai
tag: 2026.1.0-rc0
image: furiosa-device-plugin
draDriver:
enabled: false
registry: docker.io/furiosaai/furiosa-ai
tag: 2026.1.0-rc0
image: furiosa-dra-driver
metricsExporter:
enabled: true
registry: docker.io/furiosaai/furiosa-ai
tag: 2026.1.0-rc0
image: furiosa-metrics-exporter
config:
serviceType: ClusterIP
servicePort: 6254
enableScrapeAnnotations: true
collectInterval: 10
systemManager:
enabled: true
registry: docker.io/furiosaai/furiosa-ai
tag: 2026.1.0-rc0
installerImagePrefix: furiosa-system-manager-installer
validatorImage: furiosa-system-manager-validator
enableFirmwareInstall: false
enableDriverInstall: true
upgradePolicy:
autoUpgrade: false
# 적용
# kubectl apply -f example-furiosa-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: llama-3-8b
labels:
app: llama-3-8b
spec:
replicas: 1
selector:
matchLabels:
app: llama-3-8b
template:
metadata:
labels:
app: llama-3-8b
spec:
containers:
- name: llama-3-8b
image: furiosaai/furiosa-llm:latest
args:
- "serve"
- "furiosa-ai/Llama-3.1-8B-Instruct"
ports:
- containerPort: 8000
resources:
# Recommended resources for one RNGD card: 10 CPU cores and 100GB memory
limits:
cpu: 10
memory: 100Gi
furiosa.ai/rngd: "1"
requests:
cpu: 10
memory: 100Gi
furiosa.ai/rngd: "1"
env:
- name: HF_TOKEN
valueFrom:
secretKeyRef:
name: hf-token-secret
key: token
volumeMounts:
- name: model-storage
mountPath: /root/.cache/huggingface
securityContext:
capabilities:
drop:
- ALL
seccompProfile:
type: Unconfined
# Increase initialDelaySeconds of livenessProbe and readinessProbe if larger models take longer to load
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 180
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 180
periodSeconds: 5
volumes:
# If dynamic PVC provisioning isn’t possible in your cluster, consider using a hostPath volume.
- name: model-storage
persistentVolumeClaim:
claimName: llama-storage
오픈스택과 쿠버네티스에서 NPU 를 사용하는 방법 자체는 어렵지 않습니다. 오픈스택에서는 일반적인 passthrough 설정이고 쿠버네티스에서는 오퍼레이터를 helm chart 로 제공하고 거의 기본 제공 설정으로 사용이 가능합니다.
중요한 건 이걸 어떻게 잘 사용하느냐 효율적으로 사용하느냐 일 것 같습니다.
VM으로 사용할지 베어메탈로 그냥 사용할지 쿠버네티스에서 NPU device plugin 을 사용할지 dra Driver 를 사용할지 또는 다른 스케줄러를 사용할지를 많이 고민해 봐야 할 것 같습니다.
시간이 된다면 다양한 설정 방법, 스케줄링 방법을 검증해 보고 싶네요.
Quick Start for deployment/evaluation — kolla-ansible 22.1.0.dev183 documentation
CPU topologies — nova 33.1.0.dev325 documentation
GitHub – kubernetes-sigs/kubespray: Deploy a Production Ready Kubernetes Cluster
Installing Furiosa NPU Operator — FuriosaAI Developer Center 2026.3.0 documentation
Deploying Furiosa-LLM on Kubernetes — FuriosaAI Developer Center 2026.3.0 documentation