GPU 지원 및 영속적 모델 저장소를 활용한 Docker Compose에서의 Ollama 설정

GPU 및 영구 저장 기능을 갖춘 Compose 우선 Ollama 서버

Page content

Ollama는 베어 메탈(bare metal) 환경에서도 훌륭하게 작동합니다. 서비스처럼 다룰 때 더 재미가 생깁니다: 안정적인 엔드포인트, 고정된 버전, 영속적 저장소, 그리고 사용 가능하거나 불가능한 GPU.

이 글은 Docker Compose를 사용한 재현 가능한 로컬 또는 단일 노드 Ollama “서버” 구성에 초점을 맞춥니다. GPU 가속과 모델 저장소의 영속성을 포함합니다.

ollama docker compose

이 글은 일반 Docker 및 Compose 기초 내용은 고의로 생략합니다. 가장 자주 사용하는 명령어 목록(이미지, 컨테이너, 볼륨, docker compose)이 필요할 때 Docker 치트시트는 좋은 동반자입니다.

Ollama 앞에 HTTPS, 올바른 스트리밍 및 WebSocket 프록시, 그리고 엣지 제어(인증, 시간 초과, 레이트 리밋)를 원한다면 Caddy 또는 Nginx 리버스 프록시를 사용한 HTTPS 스트리밍용 Ollama 구성를 확인하세요.

Ollama가 vLLM, Docker Model Runner, LocalAI 및 클라우드 호스팅 트레이드오프와 함께 어떻게 위치하는지에 대해서는 2026년 LLM 호스팅: 로컬, 셀프 호스티드 & 클라우드 인프라 비교를 참조하세요.

이 Compose 스택이 실제 동시 트래픽을 처리하기 시작하면, 다음 질문은 종종 Ollama 자체가 여전히 적합한 엔진인지 여부가 됩니다. Ollama에서 vLLM으로: 로컬 LLM 서버를 마이그레이션할 때은 검증 동안 두 컨테이너를 나란히 실행하게 하는 단계별 마이그레이션 경로를 제공합니다.

Compose가 베어 메탈 설치보다 우세할 때

네이티브 설치에는 개발자 한 명이 머신 한 대를 사용할 때 가장 마찰이 적습니다. 다음 중 하나라도 적용되는 순간, Compose가 사용성에서 우위를 점하기 시작합니다:

팀 구성은 서비스 정의가 검토, 버전 관리, 공유할 수 있는 파일이기 때문에 이점을 얻습니다. 단일 노드 서버는 업그레이드가 이미지 태그 변경과 재시작으로 전환되고, 모델 저장소가 제자리에 머물러 있기 때문에(볼륨에 있는 한) 이점을 얻습니다. Ollama도 사이드카 옆에 위치하는 경향이 있습니다: Web UI, 리버스 프록시, 인증 게이트웨이, 벡터 DB, 또는 에이전트 런타임. Compose는 호스트를 스노플레이크(snowflake, 고유하게 커스터마이징된 시스템)로 만들지 않으면서도 “하나의 명령어로 전체 스택 시작"에 능숙합니다.

이 접근법은 공식 Ollama 컨테이너의 설계 방식과 잘 조화를 이룹니다: 이미지는 기본적으로 ollama serve를 실행하고, 포트 11434를 노출하며, 마운트 가능한 디렉터리 아래에 상태를 유지하도록 설계되었습니다. ollama serve가 읽는 OLLAMA_* 환경 변수 전체 세트로 — OLLAMA_HOST, OLLAMA_CONTEXT_LENGTH, OLLAMA_KEEP_ALIVE, OLLAMA_NUM_PARALLEL 및 기타 — 는 Ollama CLI 치트시트에 문서화되어 있습니다.

Ollama에 실제로 유용한 Compose 스켈레톤

두 가지 결정으로 시작하세요:

첫째, 버전을 고정하는 방법입니다. Docker Hub 이미지는 ollama/ollama이므로, latest에 의존하지 않고 .env에서 특정 태그를 고정할 수 있습니다.

둘째, 모델 데이터가 어디에 위치할 것인가입니다. 공식 문서는 컨테이너가 교체될 때마다 모델이 다시 다운로드되지 않도록 볼륨을 /root/.ollama에 마운트합니다.

아래는 이러한 결정을 반영하고 “조작자(knobs)“를 서비스 근처에 유지하는 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

# 콜드 스타트 지연 시간과 메모리 점유율 사이에서 Keep-alive를 조정합니다.
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 컨테이너 툴킷을 사용한 NVIDIA GPU 지원

Ollama는 Docker에서 NVIDIA GPU를 사용할 수 있지만, 이미지가 GPU를 마술처럼 만들어 내지는 않습니다. 호스트에는 작동하는 NVIDIA 드라이버와 NVIDIA 컨테이너 툴킷이 필요하며, Docker가 이를 사용하도록 구성되어야 합니다. Ollama Docker 문서는 명시적으로 nvidia-container-toolkit 설치, nvidia-ctk runtime configure --runtime=docker를 통한 런타임 구성, 그리고 Docker 재시작을 지적합니다.

Compose 측면에서, 깔끔하고 최신 방식은 장치 예약(device reservations)입니다. Docker는 deploy.resources.reservations.devices, capabilities: [gpu], driver: nvidia, 그리고 count(또는 all) 또는 device_ids를 사용하여 Compose에서 GPU 접근을 문서화합니다.

NVIDIA 호스트에 있는 경우 ollama 서비스에 추가하세요:

deploy:
  resources:
    reservations:
      devices:
        - driver: nvidia
          count: all
          capabilities: [gpu]

여러 개의 GPU가 있고 Ollama를 특정 장치에 유지하려면, Docker 문서화대로 count에서 device_ids로 전환하세요(상호 배타적입니다).

레거시 Compose 예제에서 runtime: nvidia를 사용하는 것을 가끔 볼 수 있습니다. 이는 더 최신 설정에서 “unknown or invalid runtime name: nvidia"와 같은 오류로 실패할 수 있으며, 이는 지원되는 장치 예약 패턴으로 전환하고 호스트에서 툴킷이 구성되었는지 확인해야 한다는 강력한 힌트입니다.

눈앞에 숨겨져 있는 유용한 세부 사항: 공식 ollama/ollama 이미지는 NVIDIA_VISIBLE_DEVICES=all과 NVIDIA_DRIVER_CAPABILITIES=compute,utility를 설정합니다. 이는 NVIDIA 컨테이너 런타임이 인식하는 표준 조작자이며, 오버라이드하지 않는 한 이미 존재합니다.

실제로 GPU 추론(단순히 시작되는 컨테이너가 아닌)을 얻고 있는지 확인하려면, Ollama는 ollama ps를 사용하고 모델이 GPU 메모리에 있는지 여부를 보여주는 “Processor” 열을 확인하는 것을 권장합니다.

플랫폼 현실 체크: Ollama는 Docker에서의 GPU 가속이 Linux(및 WSL2가 있는 Windows)에서 사용 가능하며, GPU 패스스루가 부족하기 때문에 macOS용 Docker Desktop에서는 사용 불가하다고 명시합니다.

네트워킹 선택: host vs bridge, 포트 및 CORS

네트워킹은 대부분의 “실행은 되지만 앱이 연결할 수 없다"는 버그가 발생하는 곳입니다.

게시된 포트와 함께 하는 브리지 네트워킹

기본 Compose 네트워크는 브리지 네트워크입니다. 이 설정에서 11434:11434를 게시하면 포트 11434에서 호스트에서 Ollama에 도달할 수 있으며, 다른 컨테이너는 서비스 이름 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) 아래에 저장되므로, 컨테이너를 교체해도 모델을 다시 다운로드할 필요가 없습니다.

롤백은 단순히 태그를 되돌리는 것

롤백은 역방향의 동일한 메커니즘입니다: 이전 태그를 설정하고, 컨테이너를 재생성하고, 동일한 볼륨을 유지합니다. 이 곳에서 고정(pinning)이 그 값을 증명합니다.

데이터 마이그레이션은 대부분 저장 경로에 관한 것

단일 노드 설정에서 대부분의 “마이그레이션"은 데이터베이스 스키마에 관한 것이 아닙니다. 디스크 레이아웃에 관한 것입니다. 모델 디렉터리를 변경하거나(OLLAMA_MODELS를 통해) 마운트된 볼륨을 새 디스크로 이동하는 경우, 그것이 마이그레이션인지 그렇지 않은지 불문하고 데이터 마이그레이션을 수행하고 있는 것입니다.

실제 머신에서 모델 디렉터리를 재구성하는 실용적인 가이드를 원한다면, 참조: move-ollama-models .

놓치기 쉬운 마지막 참고: Ollama API 문서는 API가 안정적이고 역 호환될 것이며, 드문 비추천(deprecations)은 릴리스 노트에서 공지된다고 명시적으로 말합니다. 이는 단일 노드 서비스 엔드포인트의 합리적인 기본 기대치인 “서버 업그레이드, 클라이언트 동작 유지"를 뒷받침합니다.

공통 실패: GPU 권한, 드라이버 불일치, OOM

이 섹션은 의도적으로 증상 중심입니다. 목표는 “가능한 모든 Docker 오류"가 아니라, Ollama + GPU + 영속적 저장소 설정에서 특별히 나타나는 실패만 다루는 것입니다.

호스트에서는 GPU가 보이지만 컨테이너에서는 없음

호스트에 작동하는 NVIDIA 드라이버가 있지만 컨테이너에서 GPU를 인식하지 못하면, 일반 원인은 다음과 같습니다:

NVIDIA 컨테이너 툴킷이 설치되어 있지 않거나 Docker 런타임이 nvidia-ctk를 통해 구성되지 않았습니다. Ollama의 Docker 문서에서 이를 직접 지적합니다.

Compose가 GPU 장치를 예약하지 않았습니다. 지원되는 방법은 Docker 문서화대로 gpu 기능을 가진 deploy.resources.reservations.devices입니다.

레거시 runtime: nvidia 구성이 이를 인식하지 않는 데몬에서 사용되어 “unknown or invalid runtime name: nvidia"가 생성됩니다.

검증을 위해, ollama ps는 실용적인 체크를 제공합니다: 모델이 GPU 메모리에 로드되었는지 여부를 보여줍니다.

GPU 장치에 대한 권한 거부

GPU 실패의 “권한 거부(permission denied)” 유형은 보통 Ollama 자체가 아니라 환경 제약을 가리킵니다. 예시에는 루트리스(rootless) Docker 실행, 보안 정책, 또는 디바이스 노드가 예상대로 노출되지 않는 경우 등이 포함됩니다. Docker Compose GPU 지원 문서는 호스트에 GPU 장치가 있어야 하고 Docker 데몬이 그에 따라 설정되어야 한다고 명시합니다.

의심이 들면 변수를 줄이세요: 툴킷 구성(호스트)을 확인하고, GPU 예약(Compose)을 확인하고, GPU 사용(ollama ps)을 확인합니다.

잘못된 드라이버, 잘못된 기대

Docker에서의 Ollama는 호스트 드라이버 스택에 의존합니다. 호스트 드라이버가 누락되었거나, 너무 오래되었거나, 잘못 구성되면 “Ollama가 망가졌다"처럼 보이지만 실제로는 “CUDA 스택이 사용 불가능합니다"인 실패가 표시됩니다. 공식 문서는 NVIDIA GPU 사용의 선결 조건으로 컨테이너 툴킷 및 Docker 데몬 구성을 배치합니다.

메모리 부족: VRAM 또는 RAM이 빠르게 사라짐

OOM(Out of Memory)은 로컬 추론의 가장 예측 가능한 실패 모드이며, 보통 구성에 의해 스스로 발생합니다.

Ollama는 여러 로드된 모델과 병렬 요청 처리를 통해 동시 처리를 지원하지만, 사용 가능한 메모리(CPU 추론의 경우 시스템 RAM, GPU 추론의 경우 VRAM)에 의해 제한됩니다. GPU 추론이 사용될 때, 동시 모델 로드를 허용하려면 새 모델이 VRAM에 맞춰져야 합니다.

두 가지 구성 세부 사항은 1급 “서버 설정"으로 취급할 가치가 있습니다:

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 네이티브 아티팩트 및 워크플로우에 표준화되어 있다면, Ollama를 장기 실행 서비스 컨테이너로 실행하는 것보다 Docker Model Runner(DMR)가 더 적합할 수 있습니다.

Docker는 DMR을 Docker를 통해 모델을 직접 관리, 실행, 서빙하는 방식으로 포지셔닝하며, Docker Hub 또는 기타 OCI 레지스트리에서 가져오고 OpenAI 호환 및 Ollama 호환 API를 서빙합니다.

여러 추론 엔진(llama.cpp, NVIDIA GPU가 있는 Linux에서의 vLLM 포함)도 지원하므로, “로컬에서 하나의 모델 실행"만이 아니라 처리량(characters/throughput) 특성이 중요할 때 차이가 있을 수 있습니다.

실용적인 명령어 참조 및 더 깊은 비교 관점을 원한다면, 참조: Docker Model Runner Cheatsheet: Commands & Examples.

구독하기

시스템, 인프라, AI 엔지니어링에 관한 새 글을 받아보세요.