K3S에 GPU worker 노드 추가하는 방법
홈 네트워크에 구축한 K3S 에 GPU 서버 노드를 추가한후 사용할 수 있도록 셋팅해보자.
우선 알아둬야할 배경지식이 있다.
k3s 는 컨테이너엔진을 기반으로 동작하는데, 아래 세가지 중 하나의 컨테이너 엔진을 선택할 수 있다.
k3s의 default 엔진은 containerd를 사용하도록 되어있으므로 해당 엔진을 기반으로 설명하도록 하겠음.
GPU 사용을 위해서 nvidia에서 제공하는 containerd 엔진을 default로 사용하도록 셋팅하는 작업이 필요하다.
https://github.com/NVIDIA/k8s-device-plugin#prerequisites 에 자세한 내용이 설명되어있다.
간략하게 서두에서 요약해보면 GPU 노드에서 다음의 과정들이 필요하다.
nvidia driver 와 nvcc 설치
sudo ubuntu-drivers list
sudo ubuntu-drivers autoinstall # reboot 하면 nvidia-smi 사용가능
sudo apt-get install nvidia-cuda-toolkit # nvcc --version
nvidia-container-toolkit 설치
nvidia-container toolkit 을 gpu node에 설치하고, default로 사용하도록 셋팅하고 containerd 재시작
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=containerd
sudo systemctl restart containerd (만약 containerd 관련 에러가 뜨면 아래 sub 불릿 참고)
만약, containerd 가 없다면 설치가 필요 (참고: https://github.com/containerd/containerd/blob/main/docs/getting-started.md)
containerd, runs, cni plugins
가 설치되어있어야한다.
k3s 에 worker로 gpu node 추가
https://docs.k3s.io/kr/quick-start 가이드를 따라 수행한다.
K3S_TOKEN
은 k3s master 서버의 /var/lib/rancher/k3s/server/node-token
에 저장되어있어서 확인 필요.
curl -sfL https://get.k3s.io | K3S_URL=https://$K3S_SERVER:6443 K3S_TOKEN=$K3S_TOKEN sh -
노드를 추가한 이후 다음과 같이 노드가 뜬다.
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
mango Ready <none> 16h v1.28.8+k3s1
raspberrypi Ready control-plane,master 43d v1.28.6+k3s2
gpu 노드에 label을 지정해준다.
k label nodes mango machine=gpu
다음과 같이 role 지정을 해줘도 됨
$ kubectl label node mango kubernetes.io/role=worker
node/mango labeled
$ kubectl get nodes # --show-labels 붙혀주면 레이블도 볼 수 있음
NAME STATUS ROLES AGE VERSION
raspberrypi Ready control-plane,master 43d v1.28.6+k3s2
mango NotReady worker 16h v1.28.8+k3s1
nvidia-device-plugin 배포
k3s 재시작하고, nvidia-container-runtime 이 있으면 자동으로 감지하도록 설정
https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.5/nvidia-device-plugin.yml 를 배포
그대로 배포해서는 안되고, RuntimeClass를 생성하고 이를 참고하도록 DaemonSet를 생성한다.
# cat nvidia-runtime-class.yml
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
# The name the RuntimeClass will be referenced by.
# RuntimeClass is a non-namespaced resource.
name: "nvidia"
# The name of the corresponding CRI configuration
handler: "nvidia"
spec.template.spec에 다음의 node selecter 혹은 affinity 를 통해 gpu 노드를 선택하도록 변경이 필요
# cat nvidia-device-plugin.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nvidia-device-plugin-daemonset
namespace: kube-system
spec:
selector:
matchLabels:
name: nvidia-device-plugin-ds
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
name: nvidia-device-plugin-ds
spec:
runtimeClassName: nvidia
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: machine
operator: In
values:
- "gpu"
nodeSelector:
machine: gpu
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
priorityClassName: "system-node-critical"
containers:
- image: nvcr.io/nvidia/k8s-device-plugin:v0.14.5
name: nvidia-device-plugin-ctr
env:
- name: FAIL_ON_INIT_ERROR
value: "false"
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
volumeMounts:
- name: device-plugin
mountPath: /var/lib/kubelet/device-plugins
volumes:
- name: device-plugin
hostPath:
path: /var/lib/kubelet/device-plugins
Running GPU Jobs
RuntimeClass로 nvidia
를 갖는 pod이 gpu를 사용할 수있는지 테스트 해봄
# test-gpu-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
restartPolicy: OnFailure
runtimeClassName: nvidia
containers:
- name: cuda-container
image: nvidia/cuda:12.3.2-base-ubuntu22.04
command: ["nvidia-smi"]
resources:
limits:
nvidia.com/gpu: 1 # requesting 1 GPU
(base) ➜ nvidia git:(dev) ✗ k logs gpu-pod
Sat Mar 30 09:32:22 2024
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.161.07 Driver Version: 535.161.07 CUDA Version: 12.3 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 NVIDIA GeForce GTX 1060 6GB Off | 00000000:01:00.0 Off | N/A |
| 34% 25C P8 6W / 120W | 139MiB / 6144MiB | 0% Default |
| | | N/A |
+-----------------------------------------+----------------------+----------------------+
+---------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
+---------------------------------------------------------------------------------------+
주의사항
https://github.com/NVIDIA/k8s-device-plugin#quick-start 가이드를 따라 진행하는데 조심해야할 2가지 요소가 있었음
- nvidia-device-plugin (DaemonSet) 배포시 RuntimeClass 지정과, gpu node를 선택하도록 해야함
- pod 배포시 RuntimeClass 지정과 gpu 노드를 선택하도록 해야함