모델 서빙 인프라

환경에 모델 서빙 솔루션이 아직 없는 경우 IBM Bob 온프레미스를 위한 모델 엔드포인트를 배포하고 구성합니다.

IBM Bob을 대형 언어 모델(LLM)에 연결하려면 먼저 배포된 모델 엔드포인트에 접근할 수 있어야 합니다. Bob IDE는 모델 서빙 인프라를 프로비저닝, 호스팅 또는 관리하지 않습니다. 조직에서 이미 Red Hat OpenShift Container Platform(OCP) AI, GPU 기반 추론 서버, 클라우드 AI 서비스 또는 기타 추론 플랫폼을 통해 모델 엔드포인트를 제공하는 경우 모델 추론 게이트웨이 구성으로 바로 진행하세요.

환경 및 운영 요구 사항에 가장 적합한 옵션을 선택하세요.

옵션사용 시기
OpenShift AI (온클러스터, OCI/ModelCar)에어갭 또는 자체 호스팅 모델; Red Hat OpenShift AI가 이미 클러스터에서 사용 가능한 경우
퍼블릭 클라우드 모델 엔드포인트AWS Bedrock, Azure OpenAI 또는 Google Vertex AI를 통한 프론티어 모델
프라이빗 인프라 모델 엔드포인트별도의 GPU 서버 또는 전용 추론 클러스터에서 서빙하는 모델

OpenShift AI를 사용한 모델 배포(온클러스터, OCI/ModelCar)

Red Hat OpenShift AI(RHOAI)는 에어갭 배포를 포함하여 온클러스터 모델 서빙을 위해 권장되는 플랫폼입니다. 모델 가중치를 로드하는 선호 방식은 OCI/ModelCar 패턴입니다. 모델 파일을 /models/ 아래에 OCI 이미지로 빌드하여 프라이빗 레지스트리에 푸시합니다. InferenceService가 배포될 때 KServe가 modelcar-init init 컨테이너를 주입하여 이미지를 가져오고 가중치를 공유 볼륨 /mnt/models/에 복사하며, 서빙 런타임(예: vLLM)이 이를 로드합니다. 모델 이미지는 첫 번째 풀 후 노드에 캐시됩니다. 동일한 노드에서 이후 재시작 시에는 다운로드를 건너뜁니다.

전제 조건:

  • 클러스터에 Red Hat OpenShift AI 오퍼레이터가 설치되어 있어야 합니다.
  • KServe가 활성화되고 구성되어 있어야 합니다.
  • NVIDIA GPU 오퍼레이터(또는 동급)가 구성된 GPU 지원 워커 노드가 필요합니다.
  • 대상 네임스페이스에 리소스를 생성할 수 있는 권한으로 대상 클러스터에 인증된 oc CLI가 필요합니다.
  • 클러스터에서 접근 가능하고 이미지를 푸시할 자격 증명이 있는 프라이빗 컨테이너 레지스트리가 필요합니다.

Red Hat OpenShift AI 구성

다음과 같이 DataScienceClusterInitialization 및 DataScienceCluster 리소스를 구성합니다:

  • serviceMesh를 비활성화합니다.
  • managementState: Managed를 설정하여 KServe를 활성화합니다.
  • KServe가 RawDeployment 모드를 사용하도록 구성합니다.
  • 사용하지 않는 Red Hat OpenShift AI 컴포넌트를 모두 제거합니다.

KServe 구성 예시:

kserve:
  defaultDeploymentMode: RawDeployment
  nim:
    managementState: Managed
  rawDeploymentServiceConfig: Headed
  serving:
    ingressGateway:
      certificate:
        type: OpenshiftDefaultIngress
    managementState: Removed
    name: knative-serving
  managementState: Managed

ModelCar 지원 활성화

ModelCar 지원은 redhat-ods-applications 네임스페이스의 inferenceservice-config ConfigMap으로 제어됩니다. storageInitializer 키에 "enableModelcar": true가 포함되어야 합니다.

현재 구성을 확인합니다:

oc get configmap inferenceservice-config \
  -n redhat-ods-applications \
  -o jsonpath='{.data.storageInitializer}'

출력에 다음이 포함되어야 합니다:

{
  "enableModelcar": true,
  "cpuModelcar": "10m",
  "memoryModelcar": "15Mi"
}

enableModelcar가 없거나 false이면 ConfigMap을 업데이트합니다:

# 현재 값 가져오기, 플래그 병합 후 패치
CURRENT=$(oc get configmap inferenceservice-config \
  -n redhat-ods-applications \
  -o jsonpath='{.data.storageInitializer}')
PATCHED=$(echo "$CURRENT" | python3 -c "
import json, sys
d = json.load(sys.stdin)
d['enableModelcar'] = True
print(json.dumps(d))
")
oc patch configmap inferenceservice-config \
  -n redhat-ods-applications \
  --type merge \
  -p "{\"data\":{\"storageInitializer\":$(echo $PATCHED | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')}}"

KServe 컨트롤러를 재시작하여 변경 사항을 적용합니다:

oc rollout restart deployment kserve-controller-manager -n redhat-ods-applications
oc rollout status deployment kserve-controller-manager -n redhat-ods-applications

모델 파일을 OCI 이미지로 패키징

Hugging Face에서 모델 가중치를 다운로드하여 OCI 이미지로 패키징합니다. 이미지는 모든 모델 파일이 /models 디렉터리 아래에 있어야 합니다. 자세한 내용은 모델 데이터가 포함된 OCI 이미지 준비에 관한 KServe 문서를 참조하세요. vLLM 배포의 경우 safetensors 모델 샤드를 포함하고 .bin, .pt, original/* 같은 레거시 체크포인트 파일은 제외합니다.

Dockerfile 예시:

FROM busybox:latest

# 모델 가중치 -- safetensors 샤드 및 인덱스
COPY <model-name>/model-*.safetensors        /models/
COPY <model-name>/model.safetensors.index.json /models/

# 모델 구성
COPY <model-name>/config.json            /models/
COPY <model-name>/generation_config.json /models/

# 토크나이저
COPY <model-name>/tokenizer.json          /models/
COPY <model-name>/tokenizer_config.json   /models/
COPY <model-name>/special_tokens_map.json /models/

모델에 채팅 템플릿(예: chat_template.jinja)이 포함된 경우 추가하세요. 또는 전체 디렉터리를 한 번에 복사할 수 있으며 이는 더 간단하지만 vLLM에 필요하지 않은 파일도 포함됩니다:

FROM busybox:latest
COPY <model-name>/ /models/

프라이빗 레지스트리에 이미지 푸시

클러스터에서 접근 가능한 프라이빗 컨테이너 레지스트리에 OCI 이미지를 푸시합니다:

<registry>/<project>/<model-name>:latest

환경에 맞는 도구를 사용하세요(podman push, skopeo copy, CI 파이프라인 등).

대상 네임스페이스 및 이미지 풀 시크릿 생성

프로젝트 네임스페이스를 생성하고 모델 이미지 풀을 위한 자격 증명을 구성합니다.

네임스페이스를 생성합니다:

oc new-project <namespace>

레지스트리 풀 시크릿을 생성합니다:

# KServe가 프라이빗 레지스트리에서 모델 이미지를 풀할 수 있도록 하는 풀 시크릿
oc create secret docker-registry model-registry-secret \
  --docker-server=<registry> \
  --docker-username=<username> \
  --docker-password=<password-or-token> \
  -n <namespace>

서비스 계정을 생성합니다:

# KServe predictor에서 사용하는 서비스 계정
oc create sa model-puller-sa -n <namespace>

풀 시크릿을 서비스 계정에 연결합니다:

# 풀 시크릿 연결 -- 두 명령 모두 필요합니다:
# oc secrets link는 일반적인 시크릿 사용을 처리하고;
# imagePullSecrets는 KServe의 ModelCar init 컨테이너에 특별히 필요합니다
oc secrets link model-puller-sa model-registry-secret --for=pull -n <namespace>
oc patch serviceaccount model-puller-sa -n <namespace> \
  -p '{"imagePullSecrets": [{"name": "model-registry-secret"}]}'
참고:

두 명령 모두 필요합니다. imagePullSecrets 항목은 모델 이미지 가져오기 중에 ModelCar 초기화 컨테이너에서 사용됩니다.

ServingRuntime 생성

대상 네임스페이스에 vLLM 기반 ServingRuntime을 배포합니다.

apiVersion: serving.kserve.io/v1alpha1
kind: ServingRuntime
metadata:
  name: vllm-runtime
  namespace: <namespace>
spec:
  multiModel: false
  supportedModelFormats:
    - name: pytorch
      autoSelect: true
  containers:
    - name: kserve-container
      image: vllm/vllm-openai:<version>
      ports:
        - containerPort: 3000
          protocol: TCP
      livenessProbe:
        httpGet:
          path: /health
          port: 3000
        periodSeconds: 30
        timeoutSeconds: 5
        failureThreshold: 3
      readinessProbe:
        httpGet:
          path: /health
          port: 3000
        periodSeconds: 10
        timeoutSeconds: 5
        failureThreshold: 3
      startupProbe:
        httpGet:
          path: /health
          port: 3000
        periodSeconds: 10
        timeoutSeconds: 5
        failureThreshold: 60

런타임 구성을 적용합니다:

oc apply -n <namespace> -f serving-runtime-vllm.yaml

InferenceService 배포

oci:// 스토리지 URI를 사용하여 OCI 모델 이미지를 참조하는 InferenceService를 생성합니다.

주요 구성 요구 사항:

  • 이전에 생성한 ServingRuntime을 참조합니다.
  • storageUri에 OCI 이미지 위치를 지정합니다.
  • 모델 요구 사항에 맞는 CPU, 메모리, GPU 리소스 제한을 구성합니다.
  • vLLM을 위한 공유 메모리(/dev/shm)를 마운트합니다.
  • vLLM 런타임 인수 및 환경 변수를 구성합니다.
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: <model-name>
  annotations:
    serving.kserve.io/autoscalerClass: external
    serving.kserve.io/deploymentMode: RawDeployment
spec:
  predictor:
    affinity:
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
            - matchExpressions:
                - key: kubernetes.io/arch
                  operator: In
                  values:
                    - amd64
    tolerations:
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
    volumes:
      - name: shm
        emptyDir:
          medium: Memory
          sizeLimit: 64Gi
    model:
      modelFormat:
        name: pytorch
      runtime: vllm-runtime
      storageUri: "oci://<registry>/<namespace-or-project>/<model-name>:latest"
      resources:
        requests:
          cpu: "<cpu-request>"          # 예: "8"
        limits:
          cpu: "<cpu-limit>"            # 예: "16"
          memory: <memory-limit>        # 예: 96Gi -- 모델 VRAM 요구 사항에 맞게 설정
          nvidia.com/gpu: "<gpu-count>" # 예: "1"
      volumeMounts:
        - name: shm
          mountPath: /dev/shm
      args:
        - /mnt/models/
        - --served-model-name=<model-name>
        - --port=3000
        - --enable-auto-tool-choice
        - --tool-call-parser=openai
      env:
        - name: HOME
          value: /tmp
        - name: MAX_LOG_LEN
          value: "100"        # vLLM 로그 라인이 로그 범람을 방지하도록 잘라냄
        - name: HF_HUB_CACHE
          value: /tmp
        - name: TRITON_CACHE_DIR
          value: /tmp
        - name: XDG_CACHE_HOME
          value: /tmp
        - name: HF_HOME
          value: /tmp/hf_home
        - name: NUM_GPUS
          value: "<gpu-count>" # 위의 nvidia.com/gpu 제한과 일치해야 합니다
        - name: CUDA_VISIBLE_DEVICES
          value: "<gpu-indices>" # 예: 단일 GPU의 경우 "0"; 두 GPU의 경우 "0,1"
        - name: VLLM_WORKER_MULTIPROC_METHOD
          value: spawn
        - name: LOGNAME
          value: vllm
        - name: USER
          value: vllm

InferenceService 매니페스트를 적용합니다:

oc apply -n <namespace> -f isvc-<model-name>.yaml

배포 확인

배포 상태, 파드 시작, 런타임 로그를 모니터링합니다:

# InferenceService가 Ready 상태에 도달할 때까지 감시
oc get inferenceservice <model-name> -n <namespace> -w

# predictor 파드 시작 감시
oc get pods -n <namespace> -w

# predictor 로그 추적 (Running 상태 이후 모델 로드에 수 분이 소요될 수 있음)
oc logs -f deployment/<model-name>-predictor -n <namespace>

InferenceService가 READY: True를 보고하면 엔드포인트를 검증합니다.

모델 등록을 확인하고 테스트 추론 요청을 전송합니다:

POD=$(oc get pods -n <namespace> \
  -l app=isvc.<model-name>-predictor \
  -o jsonpath='{.items[0].metadata.name}')

oc exec -n <namespace> "$POD" -c kserve-container -- \
  curl -fsS http://127.0.0.1:3000/v1/models

oc exec -n <namespace> "$POD" -c kserve-container -- \
  curl -fsS http://127.0.0.1:3000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "<model-name>",
    "messages": [{"role": "user", "content": "Hello"}],
    "max_tokens": 50
  }'

문제 해결

문제가능한 원인해결 방법
ErrImagePull레지스트리 자격 증명 누락 또는 유효하지 않음model-registry-secret이 존재하고 유효한 자격 증명을 가지며 oc secrets link와 imagePullSecrets 패치를 모두 사용하여 model-puller-sa에 연결되어 있는지 확인하세요.
ImagePullBackOffModelCar에 대한 이미지 풀 시크릿이 구성되지 않음서비스 계정에 imagePullSecrets 항목이 포함되어 있는지 확인하세요. 3단계의 oc patch serviceaccount 명령을 참조하세요.
predictor가 Init:0/1 상태에 머뭄모델 이미지 다운로드 진행 중oc describe pod 이벤트에서 Pulling/Pulled 진행 상황을 확인하세요. 풀 시간은 이미지 크기와 레지스트리 대역폭에 따라 다릅니다.
predictor가 Init:0/1 상태에 무기한 머뭄모델 파일을 찾을 수 없음모델 파일이 OCI 이미지의 /models 아래에 저장되어 있는지 확인하세요.
Engine core initialization failed초기 CUDA 컴파일 타임아웃캐시가 생성되는 동안 첫 번째 시작이 더 오래 걸릴 수 있습니다. 재시작 후 다시 시도하세요.
모델 로딩 실패지원되지 않는 모델 파일 형식Hugging Face safetensors 파일을 사용하고 레거시 체크포인트는 제외하세요.
OpenSSL FIPS 자체 테스트 오류컨테이너 이미지가 FIPS 호환되지 않음FIPS 호환 vLLM 이미지를 사용하세요.
OutOfMemory / OOMKilledGPU 메모리 부족GPU 리소스를 늘리거나, 컨텍스트 길이를 줄이거나, 양자화된 모델을 사용하세요.
InferenceService가 Pending 상태에 머뭄클러스터 리소스 부족GPU 가용성을 확인하고 사용하지 않는 워크로드에서 리소스를 해제하세요.

추가 리소스

퍼블릭 클라우드 모델 엔드포인트 사용

IBM watsonx, AWS Bedrock, Azure OpenAI 또는 Google Vertex AI 같은 클라우드 공급자가 모델을 호스팅하는 경우 이 옵션을 사용하세요.

전제 조건:

  • Red Hat OpenShift Container Platform(OCP) 클러스터에서 클라우드 서비스 엔드포인트로의 아웃바운드 HTTPS(포트 443) 연결이 필요합니다.
  • 유효한 API 키, IAM 자격 증명 또는 이에 상응하는 인증 자격 증명이 필요합니다.

시작하기 전에:

다음을 확인하세요:

  • 모델 배포가 프로비저닝되어 활성화되어 있습니다.
  • 인증 자격 증명이 생성되어 안전하게 저장되어 있습니다.
  • 공급자별 네트워킹 또는 접근 요구 사항이 완료되었습니다.

엔드포인트를 사용할 수 있게 되면 모델 추론 게이트웨이 구성으로 진행하세요.

프라이빗 인프라 모델 엔드포인트 사용

다음과 같이 IBM Bob 클러스터 외부의 고객 관리 인프라에서 모델이 호스팅되는 경우 이 옵션을 사용하세요:

  • 전용 GPU 서버
  • 별도의 OpenShift 클러스터
  • 베어 메탈 추론 서버
  • 엔터프라이즈 AI 플랫폼

전제 조건:

  • 모델 엔드포인트가 OpenAI 호환 API를 노출합니다.
  • IBM Bob 클러스터와 엔드포인트 간에 HTTPS 연결이 있습니다.
  • 인증 자격 증명을 Kubernetes 시크릿으로 사용할 수 있습니다.

시작하기 전에:

다음을 확인합니다:

  • 클러스터에서 엔드포인트로의 네트워크 연결.
  • 필요한 경우 TLS 또는 상호 TLS 구성.
  • 네트워크 정책 및 방화벽이 접근을 허용합니다.
  • 엔드포인트 인증이 올바르게 작동합니다.

연결 및 인증이 확인되면 모델 추론 게이트웨이 구성으로 진행하세요.

이 주제는 어떤가요?