Ollama를 Kubernetes에서 프로덕션으로 운용하는 법
⏱️ 예상 읽기 시간: 9분
Ollama는 2026년 1분기 기준 월 5200만 다운로드를 기록했다. 실험 도구 수준을 넘어 팀 단위 인프라로 쓰이는 사례가 많아졌다. 로컬 Mac에서 ollama run으로 돌리는 것과 Kubernetes 클러스터에서 팀 전체가 쓰는 서빙 레이어로 운용하는 것은 설계가 완전히 다르다. 이 글은 후자를 다룬다.
왜 Ollama인가: vLLM과의 포지셔닝
vLLM은 처리량 최적화에 집중한다. PagedAttention, continuous batching, FP8 추론처럼 GPU 자원을 극한까지 쓰는 데 초점이 있다. 반면 Ollama는 설치와 모델 관리의 단순함이 강점이다. ollama pull llama3:70b 한 줄로 모델을 받고, OpenAI 호환 API 서버가 자동으로 뜬다.
두 도구는 경쟁 관계라기보다 계층이 다르다. 처리량이 중요한 공개 인퍼런스 엔드포인트에는 vLLM이 맞고, 내부 개발팀이 쓰는 코드 보조 도구나 소규모 프라이빗 챗봇에는 Ollama의 운용 편의성이 더 적합하다.
기본 Kubernetes 배포
Namespace와 RBAC
kubectl create namespace ollama
kubectl label namespace ollama kueue.x-k8s.io/team=internal-tools
GPU PersistentVolumeClaim
모델 파일은 수십 GB에서 수백 GB다. PVC를 쓰지 않으면 Pod가 재시작할 때마다 모델을 다시 다운로드한다. 이건 운용상 재앙이다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ollama-models
namespace: ollama
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-retain # 클러스터에 맞는 StorageClass 사용
resources:
requests:
storage: 500Gi
여러 Pod가 같은 모델 볼륨을 공유해야 한다면 ReadWriteMany를 지원하는 StorageClass(NFS, CephFS, Azure Files 등)가 필요하다. ReadWriteOnce면 Pod 하나에만 붙는다.
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: ollama
namespace: ollama
spec:
replicas: 1
selector:
matchLabels:
app: ollama
template:
metadata:
labels:
app: ollama
spec:
tolerations:
- key: nvidia.com/gpu
operator: Equal
value: present
effect: NoSchedule
containers:
- name: ollama
image: ollama/ollama:latest
ports:
- containerPort: 11434
env:
- name: OLLAMA_MODELS
value: "/models"
- name: OLLAMA_NUM_PARALLEL
value: "4" # 동시 요청 처리 수
- name: OLLAMA_MAX_LOADED_MODELS
value: "2" # 메모리에 올려둘 최대 모델 수
volumeMounts:
- name: models
mountPath: /models
resources:
limits:
nvidia.com/gpu: "1"
memory: "32Gi"
requests:
nvidia.com/gpu: "1"
memory: "16Gi"
volumes:
- name: models
persistentVolumeClaim:
claimName: ollama-models
OLLAMA_NUM_PARALLEL은 동시에 처리할 요청 수를 제한한다. GPU 메모리가 충분하지 않으면 여러 요청을 동시에 처리할 수 없다. 기본값(1)을 그대로 두면 요청이 직렬로 처리되어 응답 지연이 길어진다.
Service
apiVersion: v1
kind: Service
metadata:
name: ollama
namespace: ollama
spec:
selector:
app: ollama
ports:
- port: 11434
targetPort: 11434
type: ClusterIP
클러스터 외부에서 접근이 필요하면 Ingress를 올리거나 LoadBalancer로 노출한다. 인증 레이어가 없으므로 외부 노출 시 반드시 인증 프록시를 앞에 놓아야 한다.
Modelfile로 커스텀 모델 구성
Ollama의 Modelfile은 베이스 모델을 기반으로 시스템 프롬프트, 파라미터, 컨텍스트 길이를 고정한 커스텀 모델을 만드는 도구다.
FROM llama3:8b
SYSTEM """
당신은 ThakiCloud 내부 코드 리뷰 도우미입니다.
Go, Kubernetes YAML, Python 코드에 특화되어 있습니다.
보안 취약점, 성능 문제, 코드 스타일을 순서대로 검토합니다.
"""
PARAMETER temperature 0.1 # 코드 리뷰는 낮은 temperature가 유리
PARAMETER num_ctx 8192 # 긴 파일을 다루려면 충분한 컨텍스트 필요
PARAMETER num_predict 2048
Modelfile을 빌드하고 배포하는 방법은 두 가지다.
방법 1: InitContainer로 모델 프리로드
initContainers:
- name: model-puller
image: ollama/ollama:latest
command:
- sh
- -c
- |
ollama serve &
sleep 5
ollama pull llama3:8b
# Modelfile을 ConfigMap으로 마운트한 뒤 build
ollama create code-reviewer -f /modelfiles/Modelfile
kill %1
volumeMounts:
- name: models
mountPath: /models
- name: modelfiles
mountPath: /modelfiles
방법 2: Job으로 별도 실행
Pod가 뜬 뒤 별도 Job을 실행해 모델을 pull하고 Modelfile을 빌드한다. 초기 배포 시 한 번만 돌리면 된다.
구조화된 출력(Structured Output)
Ollama는 format 파라미터로 JSON 출력을 강제할 수 있다.
curl http://ollama:11434/api/generate -d '{
"model": "llama3:8b",
"prompt": "다음 코드에서 보안 취약점을 찾아 JSON으로 반환해:",
"format": "json",
"stream": false
}'
Modelfile에서도 출력 형식을 시스템 프롬프트로 고정할 수 있다.
SYSTEM """
요청에 대한 응답을 항상 다음 JSON 스키마로 반환합니다:
{"issues": [{"severity": "high|medium|low", "line": number, "description": string}]}
JSON 구조 외에 다른 텍스트를 포함하지 않습니다.
"""
실무에서는 format: "json"을 켜도 모델이 스키마를 완전히 지키지 않는 경우가 있다. 응답을 파싱한 뒤 스키마를 검증하는 레이어가 필요하다.
Prometheus 모니터링
Ollama는 /metrics 엔드포인트로 Prometheus 메트릭을 노출한다.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: ollama
namespace: ollama
spec:
selector:
matchLabels:
app: ollama
endpoints:
- port: http
path: /metrics
interval: 30s
핵심 메트릭:
# 요청 처리 중 개수
ollama_request_duration_seconds_count
# 평균 처리 시간
rate(ollama_request_duration_seconds_sum[5m])
/ rate(ollama_request_duration_seconds_count[5m])
# 로드된 모델 수
ollama_loaded_model_count
HPA 오토스케일링
GPU 기반 HPA는 GPU 가동률 메트릭을 기반으로 스케일한다. NVIDIA의 DCGM Exporter를 통해 GPU 활용률을 Prometheus로 수집하면 HPA의 커스텀 메트릭으로 사용할 수 있다.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ollama
namespace: ollama
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ollama
minReplicas: 1
maxReplicas: 4
metrics:
- type: Pods
pods:
metric:
name: ollama_queue_depth # 대기 중인 요청 수 (커스텀 메트릭)
target:
type: AverageValue
averageValue: "10"
GPU 노드가 부족하면 HPA가 스케일 아웃을 시도해도 Pod가 Pending 상태에 머문다. Cluster Autoscaler나 Karpenter와 함께 써야 노드 레벨 스케일도 된다.
인증 프록시 패턴
Ollama 자체에 인증 기능이 없다. 팀 내부 서비스라도 인증 없이 열면 누구나 모델을 써버린다. 간단한 방법은 OAuth2 Proxy나 Nginx에서 API 키를 검증하는 것이다.
# Nginx ConfigMap 예시
nginx.conf: |
location / {
if ($http_x_api_key != "your-team-key") {
return 401;
}
proxy_pass http://ollama:11434;
}
Keycloak 같은 IdP와 연동하면 팀별 접근 권한도 관리할 수 있다.
운용 팁
모델 업데이트는 별도 Job으로 스케줄한다. ollama pull은 실행 중인 Pod와 함께 돌릴 수 있지만, 업데이트 중 용량 부족으로 Pod가 재시작하는 일이 생긴다. 점검 시간에 Job으로 별도 실행하는 쪽이 안전하다.
OLLAMA_MAX_LOADED_MODELS를 GPU 메모리에 맞게 조정한다. 70B 모델 두 개를 동시에 올리면 VRAM이 부족하다. 실제 VRAM 대비 모델 크기를 계산하고 이 값을 설정해야 한다.
로그 레벨을 조정한다. 기본 설정에서 Ollama는 요청마다 상세 로그를 남긴다. OLLAMA_DEBUG=false로 프로덕션 로그를 줄일 수 있다.
정리
Ollama를 Kubernetes에서 제대로 운용하려면 모델 PVC, GPU toleration, 인증 프록시, 모니터링 네 가지를 갖춰야 한다. Modelfile로 팀 전용 모델을 구성하면 시스템 프롬프트와 파라미터를 버전 관리할 수 있다. 처리량보다 운용 단순함이 중요한 내부 도구 서빙에서 Ollama는 설정 비용 대비 좋은 선택이다.