학습·이미지 빌드·서빙은 k3s 의 파드로 돕니다. 이 페이지에서는 k3s 를 올리고, 파드가 GPU 를 쓸 수 있게 하고, 앱이 GPU 를 "슬롯" 으로 셀 수 있게 만듭니다. 명령은 모두 서버에서 실행하며, 소스는 /opt/geo-mlops 에 있다고 가정합니다.

1. NVIDIA 드라이버와 Container Toolkit

k3s 는 시작할 때 nvidia-container-runtime 이 있는지 보고 containerd 에 nvidia 런타임을 등록합니다. 그래서 드라이버와 NVIDIA Container Toolkit 을 k3s 보다 먼저 설치합니다(설치 방법은 NVIDIA 공식 문서를 따릅니다). 이미 k3s 가 떠 있다면 Toolkit 설치 뒤 sudo systemctl restart k3s 로 다시 읽게 합니다.

nvidia-smi                       # 드라이버 확인
which nvidia-container-runtime   # Toolkit 확인

2. k3s 설치

  1. k3s 를 설치합니다(공식 설치 스크립트).

    curl -sfL https://get.k3s.io | sh -
  2. 노드가 Ready 인지, kubeconfig 가 생겼는지 확인합니다. 앱 컨테이너는 이 파일을 그대로 읽습니다.

    sudo k3s kubectl get nodes
    ls -l /etc/rancher/k3s/k3s.yaml
  3. RuntimeClass nvidia 가 있는지 봅니다. 없으면 만듭니다.

    sudo k3s kubectl get runtimeclass nvidia || \
    cat <<'EOF' | sudo k3s kubectl apply -f -
    apiVersion: node.k8s.io/v1
    kind: RuntimeClass
    metadata:
      name: nvidia
    handler: nvidia
    EOF

3. NVIDIA device plugin

RuntimeClass 만으로도 파드에 GPU 를 넣을 수는 있지만, 그러면 클러스터가 GPU 점유를 모릅니다. GPU 한 장에 두 파드가 올라가 서로 메모리 부족으로 죽습니다. device plugin 은 노드가 GPU 를 nvidia.com/gpu 자원으로 광고(클러스터에 몇 개 있는지 알림)하게 합니다. 그러면 자리가 없을 때 파드가 Pending 으로 기다립니다. 앱의 GPU 슬롯 화면도 이 광고값을 셉니다.

설치 파일은 두 가지입니다. 둘 중 하나만 적용합니다(같은 DaemonSet 이름을 씁니다).

파일언제
scripts/serving/nvidia-device-plugin.ymlGPU 한 장 = 슬롯 하나. GPU 가 여러 장이고 파드마다 한 장씩 주면 될 때
scripts/serving/nvidia-device-plugin-timeSlicing.ymlGPU 한 장을 여러 슬롯(기본 8) 으로 나눠 광고. GPU 가 한두 장인데 학습·서빙을 여럿 함께 올려야 할 때
  1. 하나를 적용합니다. kubeconfig 만 있으면 됩니다.

    sudo k3s kubectl apply -f /opt/geo-mlops/scripts/serving/nvidia-device-plugin-timeSlicing.yml
  2. 노드마다 광고되는 GPU 수를 확인합니다(시분할이면 GPU 수 × 8).

    sudo k3s kubectl get nodes -o custom-columns='NAME:.metadata.name,ALLOC:.status.allocatable.nvidia\.com/gpu'
  3. 앱에 전역 관리자로 로그인해 시스템 콘솔의 GPU 슬롯 화면을 엽니다. device plugin 이 Ready 이고 총 슬롯이 위 숫자와 같으면 됩니다.

    GPU 슬롯: 노드가 광고하는 GPU 와 device plugin 상태

replicas(기본 8)를 바꾸려면 ConfigMap 을 고쳐 다시 적용한 뒤 반드시 롤아웃합니다. 그러지 않으면 반영되지 않습니다.

sudo k3s kubectl apply -f /opt/geo-mlops/scripts/serving/nvidia-device-plugin-timeSlicing.yml
sudo k3s kubectl -n kube-system rollout restart ds/nvidia-device-plugin-daemonset

4. 컨테이너 레지스트리를 k3s 가 받을 수 있게

앱의 내장 레지스트리(/v2)는 평문 HTTP 입니다. 이미지가 오가는 길은 둘입니다.

방향누가기본 주소설정
push빌드 파드 안의 BuildKit10.42.0.1:10000BuildKit 에 insecure 가 이미 켜져 있음(GEO_MLOPS_SERVING_REGISTRY_INSECURE=true)
pull노드의 containerdlocalhost:10000containerd 는 localhost 를 insecure 로 취급하므로 단일 노드면 할 일 없음

그래서 서버 한 대 구성에서는 registries.yaml 이 필요 없습니다. pull 주소를 localhost 가 아닌 값으로 바꾼 경우(노드가 여럿이라 GEO_MLOPS_SERVING_REGISTRY_PULL호스트:포트 로 지정한 경우)에만, 각 노드의 /etc/rancher/k3s/registries.yaml 에 그 주소를 insecure 로 등록합니다.

# /etc/rancher/k3s/registries.yaml: <registry-host>:10000 을 실제 pull 주소로
mirrors:
  "<registry-host>:10000":
    endpoint: ["http://<registry-host>:10000"]
configs:
  "<registry-host>:10000":
    tls:
      insecure_skip_verify: true
sudo systemctl restart k3s    # registries.yaml 은 k3s 가 시작할 때 읽는다

다음: 필수 보안 설정

2026-09-21 기준 플랫폼에 맞춰 작성했습니다.

© Geo-MLOps