GPU 및 영구 모델 스토리지 사용 Docker Compose 기반 Ollama
GPU 와 영속성을 갖춘 Compose 우선 Ollama 서버
Ollama 는 베어 메탈 (bare metal) 환경에서 훌륭하게 작동합니다. 이를 서비스처럼 다룰 때 더욱 흥미로운데, 안정적인 엔드포인트, 고정된 버전, 영구 저장소, 그리고 GPU 가 있거나 없는 명확한 상태를 보장받기 때문입니다.
이 글은 Docker Compose 를 사용하여 GPU 가속과 영구 모델 저장을 갖춘 재현 가능한 로컬 또는 단일 노드 Ollama “서버"를 구축하는 하나의 목표를 중심으로 다룹니다.

이 글은 일반적인 Docker 와 Compose 기초는 일부러 생략합니다. 가장 자주 사용하는 명령어 (이미지, 컨테이너, 볼륨, docker compose) 의 간결한 목록이 필요할 때, Docker Cheatsheet 이 훌륭한 참고 자료입니다.
Ollama 앞에 HTTPS 를 배치하고, 올바른 스트리밍과 WebSocket 프록시를 설정하며, 엣지 제어 (인증, 시간 초과, 속도 제한) 를 적용하고 싶다면 Ollama behind a reverse proxy with Caddy or Nginx for HTTPS streaming 을 참고하세요.
Ollama 가 vLLM, Docker Model Runner, LocalAI 및 클라우드 호스팅의 트레이드오프와 어떻게 공존하는지에 대해서는 LLM Hosting in 2026: Local, Self-Hosted & Cloud Infrastructure Compared 를 참조하세요.
Compose 가 베어 메탈 설치보다 유리한 경우
네이티브 설치는 단일 머신에 있는 단일 개발자에게는 마찰이 없습니다. 하지만 다음 중 하나라도 발생하면 Compose 가 사용성 측면에서 우위를 점하기 시작합니다.
팀 설정은 서비스 정의가 검토, 버전 관리, 공유할 수 있는 파일이므로 유리합니다. 단일 노드 서버는 업그레이드가 이미지 태그 변경과 재시작으로 끝나고 모델 저장소는 유지되므로 (볼륨에 저장된 경우) 유리합니다. 또한 Ollama 는 사이드카 (Web UI, 리버스 프록시, 인증 게이트웨이, 벡터 DB, 에이전트 런타임 등) 와 함께 운영되는 경향이 있습니다. Compose 는 호스트를 눈송이 (snowflake, 고유하게 설정된 서버) 로 만들지 않고 “명령어 하나로 전체 스택을 시작"하는 데 탁월합니다.
이 접근 방식은 공식 Ollama 컨테이너 설계 철학과 잘 맞습니다: 이미지는 기본적으로 ollama serve 를 실행하고, 포트 11434 를 노출하며, 마운트 가능한 디렉토리 아래에서 상태를 유지하도록 설계되었습니다.
Ollama 에 실제로 유용한 Compose 기본 구조
두 가지 결정부터 시작하세요.
첫째, 버전을 어떻게 고정할지입니다. Docker Hub 이미지는 ollama/ollama 이므로 latest 에 의존하는 대신 .env 에서 특정 태그를 고정할 수 있습니다.
둘째, 모델 데이터가 어디에 있을지입니다. 공식 문서에서는 컨테이너가 교체될 때마다 모델이 다시 다운로드되지 않도록 볼륨을 /root/.ollama 에 마운트하도록 권장합니다.
아래는 이러한 결정을 반영하고 “레버"를 서비스 가까이 두는 Compose 파일입니다.
services:
ollama:
image: ollama/ollama:${OLLAMA_IMAGE_TAG:-latest}
container_name: ollama
restart: unless-stopped
# 기본적으로 로컬로 유지하고, 필요시 나중에 노출합니다.
ports:
- "${OLLAMA_BIND_IP:-127.0.0.1}:11434:11434"
# 영구적인 모델 및 서버 상태.
volumes:
- ollama:/root/.ollama
environment:
# 공식 이미지는 이미 컨테이너 내부에서 0.0.0.0:11434 로 기본 설정되어 있지만,
# 나중에 오버라이드할 때 명시적으로 유지하는 것이 도움이 됩니다.
- OLLAMA_HOST=0.0.0.0:11434
# 서비스 튜닝.
- OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-5m}
- OLLAMA_NUM_PARALLEL=${OLLAMA_NUM_PARALLEL:-1}
- OLLAMA_MAX_LOADED_MODELS=${OLLAMA_MAX_LOADED_MODELS:-1}
# 선택 사항이지만, 브라우저 기반 UI 가 Ollama 와 직접 통신할 때 관련이 있습니다.
# 네트워크 섹션에서 이것이 존재하는 이유를 확인하세요.
- OLLAMA_ORIGINS=${OLLAMA_ORIGINS:-}
# GPU 예약은 아래 별도 섹션에서 다룹니다.
# NVIDIA GPU 가 실제로 있는 호스트에서만 추가하세요.
volumes:
ollama: {}
일치하는 .env 파일은 업그레이드를 지루하게 만듭니다:
# 테스트한 이미지 버전을 고정합니다.
OLLAMA_IMAGE_TAG=latest
# 기본적으로 로컬입니다. 의도적으로 노출할 때 0.0.0.0 으로 변경하세요.
OLLAMA_BIND_IP=127.0.0.1
# 콜드 스타트 지연 시간과 메모리 사용량 사이의 트레이드오프를 조절합니다.
OLLAMA_KEEP_ALIVE=5m
# 동시성 레버.
OLLAMA_NUM_PARALLEL=1
OLLAMA_MAX_LOADED_MODELS=1
# 브라우저 클라이언트가 Ollama 를 직접 호출하는 경우를 제외하고는 비워둡니다.
OLLAMA_ORIGINS=
작지만 중요한 뉘앙스가 있습니다: Ollama 자체는 일반 설정에서 127.0.0.1:11434 를 기본 바인딩으로 사용하지만, 공식 컨테이너 이미지는 서비스가 게시된 포트를 통해 접근 가능하도록 OLLAMA_HOST=0.0.0.0:11434 를 설정합니다.
클라이언트 SDK 를 사용하지 않고 빠른 검증이 필요하다면, Ollama API 는 GET /api/tags 에서 “로컬 모델 목록” 엔드포인트를 제공합니다.
영구 모델 저장 및 가장 고통 없는 이동 방법
기억해야 할 점이 있다면 하나만 기억하세요: 컨테이너는 영구 저장소를 가져야 합니다. 그렇지 않으면 모든 재빌드마다 다시 다운로드해야 합니다.
Ollama 는 OLLAMA_MODELS 를 사용하여 모델 디렉토리를 선택할 수 있습니다. 참조 구현에서는 기본값이 $HOME/.ollama/models 이며, OLLAMA_MODELS 를 설정하면 이를 오버라이드합니다.
공식 Docker 이미지 내부에서 $HOME 은 문서화된 볼륨 마운트 (/root/.ollama) 가 사용하는 /root 레이아웃에 자연스럽게 매핑되므로, 공식 docker run 예제가 해당 디렉토리를 마운트하는 이유가 바로 이것입니다.
실제로 잘 작동하는 두 가지 저장 패턴이 있습니다:
이름이 지정된 Docker 볼륨이 가장 간단하고 이동성이 좋습니다. 또한 실수로 고아 (orphan) 볼륨을 만들 가능성이 있으므로 의도적으로 이름 (예: ollama) 을 지정하고 Compose 리팩토링 전반에 걸쳐 안정적으로 유지하는 것이 좋습니다.
모델 크기가 루트 파일 시스템을 지배하기 시작할 때는 전용 디스크에 바인드 마운트하는 것이 더 좋습니다. 이 경우 전체 /root/.ollama 를 해당 디스크에 마운트하거나 커스텀 디렉토리를 마운트하고 OLLAMA_MODELS 를 해당 디렉토리를 가리키도록 설정합니다.
저장을 능동적으로 재구성 중이라면, 명시적인 “모델 이동” 플레이북이 도움이 됩니다. 참고: move-ollama-models .
Compose 와 NVIDIA Container Toolkit 을 통한 NVIDIA GPU 지원
Ollama 는 Docker 에서 NVIDIA GPU 를 사용할 수 있지만, 이미지가 GPU 를 무에서 유로 만들어내는 마법은 없습니다. 호스트에는 작동하는 NVIDIA 드라이버와 NVIDIA Container Toolkit 이 설치되어 있어야 하며, Docker 가 이를 사용하도록 구성되어 있어야 합니다. Ollama Docker 문서는 nvidia-container-toolkit 설치, nvidia-ctk runtime configure --runtime=docker 를 통한 런타임 구성, 그리고 Docker 재시작을 명시적으로 강조합니다.
Compose 측면에서 깔끔하고 현대적인 방법은 장치 예약입니다. Docker 는 Compose 에서 GPU 접근을 deploy.resources.reservations.devices 를 사용하여 문서화하며, capabilities: [gpu], driver: nvidia, 그리고 count(또는 all) 또는 device_ids 를 포함합니다.
NVIDIA 호스트를 사용할 경우 ollama 서비스에 다음을 추가하세요:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
여러 개의 GPU 가 있고 특정 장치에서만 Ollama 를 실행하려면 Docker 가 문서화한 대로 count 대신 device_ids 로 전환하세요 (서로 배타적입니다).
가끔 runtime: nvidia 를 사용하는 레거시 Compose 예제를 볼 수 있습니다. 이는 “unknown or invalid runtime name: nvidia"와 같은 오류로 인해 새 설정에서 실패할 수 있으며, 이는 지원되는 장치 예약 패턴으로 이동하고 호스트에서 툴킷이 구성되어 있는지 확인해야 한다는 강력한 신호입니다.
눈에 띄지 않는 유용한 세부 사항: 공식 ollama/ollama 이미지는 NVIDIA_VISIBLE_DEVICES=all 과 NVIDIA_DRIVER_CAPABILITIES=compute,utility 를 설정합니다. 이는 NVIDIA 컨테이너 런타임이 인식하는 표준 레버이며, 오버라이드하지 않는 한 이미 존재합니다.
실제로 GPU 추론을 하고 있는지 (단순히 컨테이너가 시작되는 것이 아님) 확인하려면 Ollama 는 ollama ps 를 사용하고 “Processor” 열을 확인하여 모델이 GPU 메모리에 로드되었는지 확인하는 것을 권장합니다.
플랫폼 현실 확인: Ollama 는 Docker 에서 GPU 가속이 Linux(WSL2 를 사용한 Windows 포함) 에서 사용 가능하지만, macOS 의 Docker Desktop 에서는 GPU 패스스루가 부족하여 사용 불가능하다고 명시합니다.
네트워킹 선택: 호스트 대 브릿지, 포트, CORS
네트워킹은 “실행은 되는데 앱이 연결되지 않는다"는 오류가 발생하는 주요 원인입니다.
게시된 포트를 사용한 브릿지 네트워킹
기본 Compose 네트워크는 브릿지 네트워크입니다. 이 설정에서 11434:11434 를 게시하면 Ollama 는 호스트의 포트 11434 에서 접근 가능해지며, 다른 컨테이너는 서비스 이름 ollama( localhost 가 아님) 를 사용하여 통신해야 합니다. 많은 사람들이 컨테이너 내부의 localhost 가 “이 컨테이너"를 의미하며 “Ollama 컨테이너"를 의미하지 않는다는 점을 놓칩니다.
Ollama 자체는 포트 11434 에서 HTTP 서버를 실행하며 (이미지가 노출함), 일반적인 관례는 포트를 게시할 때 호스트에서 클라이언트가 http://localhost:11434 를 사용한다는 것입니다.
호스트 네트워킹
network_mode: host 는 단일 노드 서버에서 포트 게시를 제거하고 localhost 세맨틱을 단순화하므로 유혹적일 수 있습니다. 단점은 브릿지 네트워크의 격리와 네임스페이스 이점을 잃게 되며, 포트 충돌에 더 자주 부딪히게 된다는 것입니다.
의도적으로 Ollama 노출
일반 설치의 Ollama 는 기본적으로 127.0.0.1 에 바인딩되며, 바인딩 주소를 변경하는 문서화된 방법은 OLLAMA_HOST 입니다.
Docker 에서는 두 가지 레이어가 있습니다:
OLLAMA_HOST 로 제어되는 Ollama 바인딩 주소 (컨테이너 이미지는 컨테이너 내부에서 모든 인터페이스에 바인딩하는 것이 기본값입니다).
컨테이너 외부 접근성, Compose ports 와 호스트 방화벽으로 제어됩니다.
저의 선호하는 패턴은 127.0.0.1:11434:11434 를 통해 “기본적으로 로컬에 바인딩"한 후, 노출할 명분이 있을 때만 0.0.0.0:11434:11434 로 전환하는 것입니다.
브라우저 클라이언트 및 OLLAMA_ORIGINS
브라우저 기반 UI 또는 확장이 Ollama 를 직접 호출하는 경우 CORS 영역에 들어갑니다. Ollama 는 기본적으로 127.0.0.1 과 0.0.0.0 에서의 교차 출처 요청을 허용하며, OLLAMA_ORIGINS 를 사용하여 추가 출처를 구성할 수 있습니다.
이는 단일 노드에서도 중요합니다. “curl 로 작동한다"는 “브라우저 앱에서 작동한다"는 것을 의미하지 않기 때문입니다.
단일 노드 서버에 적합한 업그레이드 및 롤백 패턴
Ollama 는 빠르게 발전합니다. Compose 파일은 이를 밤늦은 시간의 놀라움이 아닌 차분한 프로세스로 만들 수 있습니다.
“latest"가 작동하기를 바라지 말고 태그를 변경하여 업그레이드
가장 실용적인 업그레이드 전략은 .env 에서 이미지의 태그를 알려진 안정적인 버전으로 고정하고, 의도적으로 올리는 것입니다. 이미지는 Docker Hub 에 ollama/ollama 로 게시됩니다.
모델 데이터와 서버 상태는 마운트된 디렉토리 (/root/.ollama 공식 문서) 아래에 저장되므로, 컨테이너를 교체해도 모델을 다시 다운로드하지 않습니다.
롤백은 태그를 이전으로 변경하는 것뿐
롤백은 역방향으로 같은 메커니즘입니다: 이전 태그를 설정하고 컨테이너를 재생성하며 동일한 볼륨을 유지합니다. 이것이 태그 고정이 그 대가를 치르는 곳입니다.
데이터 마이그레이션은 주로 저장 경로에 관한 것
단일 노드 설정에서 대부분의 “마이그레이션"은 데이터베이스 스키마에 관한 것이 아닙니다. 디스크 레이아웃에 관한 것입니다. 모델 디렉토리를 변경하거나 (OLLAMA_MODELS 를 통해) 마운트된 볼륨을 새 디스크로 이동하면, 그것을 마이그레이션이라고 부르는지 여부와 상관없이 데이터 마이그레이션을 수행하는 것입니다.
실제 머신에서 모델 디렉토리를 재구성하는 실용적인 가이드가 필요하면 다음을 참조하세요: move-ollama-models .
놓치기 쉬운 마지막 참고 사항: Ollama 의 API 문서에서는 API 가 안정적이고 역방향 호환되며 드물게 릴리스 노트에서 폐기 사항이 발표된다고 명시합니다. 이는 단일 노드 서비스 엔드포인트에서 “서버를 업그레이드하되 클라이언트는 작동한다"는 것이 합리적인 기본 기대치임을 의미합니다.
일반적인 오류: GPU 권한, 드라이버 불일치, OOM
이 섹션은 의도적으로 증상 중심입니다. 목표는 “가능한 모든 Docker 오류"가 아니라, Ollama + GPU + 영구 저장소 설정에서 특히 나타나는 실패만을 다룹니다.
호스트에서는 GPU 가 보이는데 컨테이너에서는 없음
호스트에 작동하는 NVIDIA 드라이버가 있지만 컨테이너에서 GPU 를 인식하지 못한다면 일반적인 원인은 다음과 같습니다:
NVIDIA Container Toolkit 이 설치되지 않았거나 Docker 런타임이 nvidia-ctk 를 통해 구성되어 있지 않습니다. Ollama 의 Docker 문서에서 이를 직접 지적합니다.
Compose 가 GPU 장치를 예약하지 않았습니다. Docker 가 문서화한 대로 deploy.resources.reservations.devices 와 gpu 기능으로 지원하는 방식입니다.
레거시 runtime: nvidia 설정이 이를 인식하지 못하는 데몬에서 사용되어 “unknown or invalid runtime name: nvidia"오류가 발생합니다.
검증을 위해 ollama ps 를 사용하면 실용적인 확인이 가능합니다: 모델이 GPU 메모리에 로드되었는지 보여줍니다.
GPU 장치에 대한 권한 거부
“권한 거부"유형의 GPU 실패는 일반적으로 Ollama 자체보다는 환경 제약으로 인해 발생합니다. 예시에는 루트리스 Docker 실행, 보안 정책, 또는 예상대로 노출되지 않은 장치 노드가 포함됩니다. Docker Compose GPU 지원 문서는 호스트에 GPU 장치가 있어야 하고 Docker 데몬이 이에 맞게 설정되어야 한다고 명시합니다.
의심스러우면 변수를 줄이세요: 툴킷 구성 (호스트) 을 확인한 후, GPU 예약 (Compose) 을 확인하고, GPU 사용 (ollama ps) 을 확인하세요.
잘못된 드라이버, 잘못된 기대치
Docker 의 Ollama 는 호스트 드라이버 스택에 의존합니다. 호스트 드라이버가 누락되었거나 너무 오래되었거나 잘못 설정된 경우 “Ollama 가 고장 났다"처럼 보이지만 실제로는 “CUDA 스택을 사용할 수 없다"는 실패를 볼 것입니다. 공식 문서는 NVIDIA GPU 사용을 위한 필수 요건으로 컨테이너 툴킷과 Docker 데몬 구성을 명시합니다.
메모리 부족: VRAM 이나 RAM 이 빠르게 사라짐
OOM(메모리 부족) 은 로컬 추론에서 가장 예측 가능한 실패 모드이며, 일반적으로 설정으로 인해 스스로 유발됩니다.
Ollama 는 여러 로드된 모델과 병렬 요청 처리를 통해 동시 처리를 지원하지만, 사용 가능한 메모리 (CPU 추론의 경우 시스템 RAM, GPU 추론의 경우 VRAM) 로 제한됩니다. GPU 추론을 사용할 때 새 모델은 동시 모델 로드를 허용하기 위해 VRAM 에 맞아야 합니다.
두 가지 구성 세부 사항은 일급 “서버 설정"으로 취급할 가치가 있습니다:
OLLAMA_NUM_PARALLEL 은 모델당 병렬 요청 처리를 증가시키지만, 필요한 메모리는 OLLAMA_NUM_PARALLEL * OLLAMA_CONTEXT_LENGTH 와 비례하여 증가합니다.
OLLAMA_KEEP_ALIVE 는 모델이 로드된 상태를 유지하는 시간을 제어합니다 (기본값 5 분). 모델을 로드 상태로 유지하면 콜드 스타트 지연 시간이 줄어들지만, 메모리가 고정됩니다.
부하 하에서 단일 노드 서비스를 안정화 중이라면, 극적인 수정은 일반적으로 다음과 같습니다:
다른 변경 사항 전에 병렬성과 컨텍스트 기본값을 낮춥니다.
동시에 로드된 상태를 유지할 수 있는 모델 수를 제한합니다.
병목 현상이 메모리가 아닌 원시 연산 능력인 경우 Flash Attention (OLLAMA_FLASH_ATTENTION=1) 과 낮은 정밀도 K/V 캐시 유형 (OLLAMA_KV_CACHE_TYPE) 과 같은 메모리 감소 기능을 고려합니다.
Ollama 가 아닌 경우: Docker Model Runner 선택
가끔 “실패"는 실제로 도구 불일치입니다. 조직이 이미 Docker 네이티브 아티팩트와 워크플로우를 표준화했다면, Docker Model Runner(DMR) 는 장기간 서비스 컨테이너로 Ollama 를 실행하는 것보다 더 적합할 수 있습니다.
Docker 는 DMR 을 Docker 를 통해 모델을 직접 관리, 실행, 제공하기 위한 방법으로 포지셔닝하며, Docker Hub 또는 다른 OCI 레지스트리에서 가져와 OpenAI 호환 및 Ollama 호환 API 를 제공합니다.
또한 여러 추론 엔진 (llama.cpp 포함, NVIDIA GPU 가 있는 Linux 의 vLLM 등) 을 지원하므로, 단순히 “로컬에서 하나의 모델을 실행"하는 것뿐만 아니라 처리량 특성에 관심이 있다면 중요합니다.
실용적인 명령어 참조와 더 깊은 비교 각도가 필요하면 다음을 참조하세요: Docker Model Runner Cheatsheet: Commands & Examples.