OllamaをDockerコンテナで運用する方法|docker-compose.ymlとGPU設定で本番環境に安定デプロイする

運営:リナックスマスター.JP(代表 宮崎智広)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Docker > OllamaをDockerコンテナで運用する方法|docker-compose.ymlとGPU設定で本番環境に安定デプロイする
「Ollamaをサーバーに直接インストールしたら依存ライブラリが競合して環境が壊れた」
「チームメンバーのUbuntuバージョンが違うせいで、同じ手順を実行しても動かない」

そんな悩みを抱えるインフラエンジニアやサーバー管理者は少なくない。Ollamaは単体でも動作するが、本番運用を見据えるとDockerコンテナ化が断然有利だ。この記事では、docker-compose.ymlを使ってOllamaをコンテナとして立ち上げ、GPUパススルー設定・リソース制限・Open WebUI連携・ヘルスチェック・日常運用コマンドまでをステップ順に解説する。さらに、profilesキーを使ったサービスの選択起動とdocker-compose.override.ymlを活用した開発・本番・CI設定の分離パターン、マージルールの落とし穴まで詳しく紹介する。Ubuntu Server 22.04 LTS + NVIDIA GPUの構成を基本とするが、GPUなしのCPU運用でも手順はほぼ同じだ。

この記事のポイント

・docker-compose.ymlとNVIDIA Container Toolkitで再現性のある運用環境を構築できる
・GPUパススルー・ヘルスチェック・環境変数の外部化で本番品質の構成に仕上げる手順を解説
・profilesキーで特定サービスを選択起動し、COMPOSE_PROFILES変数で環境ごとに制御できる
・docker-compose.override.ymlで開発・本番設定を分離し、本番への誤設定混入を防ぐ方法も紹介
・environmentはマッピング形式(KEY: VALUE)で書くと上書きが確実に機能する
・command・entrypointはスカラー値として完全置換されるためoverride.ymlでの制御が容易
・override.ymlで新規ボリュームを追加するとき、トップレベルのvolumes:セクションも同時に必要
・--env-fileオプションで本番用の.envを明示指定し環境変数を切り替える手順を解説
・compose.ci.ymlと--abort-on-container-exitでCIテスト実行を自動化する手順も解説
・マージルールの落とし穴(配列は追加マージ・マッピングはキー単位上書き)を理解して設定混入を防ぐ
・deploy.resources.limitsでCPU/メモリを制限し、ホスト全体の安定性を守る方法も紹介
・docker statsで実消費量を把握してから制限値を設定する手順を解説
・Open WebUIをcomposeに同梱することでチーム共有UIをワンコマンドで起動できる
・COMPOSE_FILE環境変数で-fオプションと同等のファイルセットを指定でき、CI/CDパイプラインで活用できる
・dev/stg/prod3環境のファイル構成パターンとそれぞれの起動コマンドを解説
・docker statsはリアルタイム確認に便利だが、履歴保存・アラート通知・複数コンテナ比較には不十分
・cAdvisor・Prometheus・Grafanaをcomposeのmonitoringプロファイルに追加し、Ollamaの使用状況を時系列で把握できる
・dcgm-exporterとPrometheusを組み合わせるとGPU(VRAM使用率)も時系列データとして蓄積できる


OllamaをDockerコンテナで運用する方法|docker-compose.ymlとGPU設定で本番環境に安定デプロイする

「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜOllamaをDockerコンテナで動かすべきなのか

ローカルLLMの導入を検討するとき、「まずサーバーに直接インストールしてみる」というアプローチを取る人が多い。実際、Ubuntu ServerでローカルLLMを構築する方法で解説した手順は確かに手早く動作確認できる。ただし、直接インストールには「ライブラリの競合」「Pythonバージョン依存」「移行コスト」という3つの問題が伴う。

Dockerを使うと、これらの問題が構造的に解消される。コンテナはホストOSのライブラリに依存せず、docker-compose.ymlという1ファイルで全構成が記述される。チームメンバーがそのファイルを手元に持てば、同じ環境を数分で再現できる。バージョン管理リポジトリにcomposeファイルをコミットすれば、構成変更の履歴も自動で残る。

また、デフォルト設定のDockerコンテナはホストマシンのCPUとメモリを上限なく消費できる。Ollamaが大量の推論リクエストを受けたとき、同じホスト上の他のサービスが道連れになるケースがある。docker-compose.ymlにリソース制限を明記しておくことで、こうした問題を事前に防げる。

典型的なケースとして、検証段階は直接インストールで済ませ、社内展開フェーズでDockerに移行することが多い。直接インストール版とコンテナ版の主な違いは次のとおりだ。

直接インストール版はセットアップが速い半面、サーバー移行時に「どのバージョンを入れたか」が曖昧になりやすい。一方、Docker版はcomposeファイルが設計書として機能するため、「3ヶ月前の構成をそのまま再現したい」といった場面で威力を発揮する。チームで複数台のサーバーにOllamaを展開する予定があるなら、最初からDockerで構築する価値は高い。

この記事ではその「本番化」のステップを詳しく見ていく。

事前準備|Docker EngineとNVIDIA Container Toolkitを整える

1. Docker Engineのインストール確認

Ubuntu ServerへのDocker Engineのインストールは公式ドキュメントの手順が最も確実だ。既にインストール済みの場合はバージョン確認だけ行う。

# Dockerのバージョン確認 $ docker --version Docker version 26.1.4, build 5650f9b # docker compose plugin(V2)の確認 $ docker compose version Docker Compose version v2.27.1

docker-compose(V1・ハイフン区切り)ではなく docker compose(V2・スペース区切り)が使える状態であることを確認する。V1は2023年にメンテナンス終了しているため、V2への移行を推奨する。インストールされていない場合は次のコマンドで追加できる。

# docker compose plugin(V2)の追加インストール $ sudo apt update $ sudo apt install -y docker-compose-plugin # 一般ユーザーでdockerコマンドを使えるようにグループ追加 $ sudo usermod -aG docker $USER # グループ変更を反映(再ログインが必要) $ newgrp docker

newgrp docker コマンドで現在のシェルセッションに変更を反映できる。ただし完全に反映するにはログアウト&再ログインが確実だ。

2. NVIDIA Container Toolkitのインストール

GPUを使ってOllamaを動かすには、NVIDIA Container Toolkitが必要だ。これはDockerコンテナからGPUにアクセスするためのランタイムで、ホストOS側にインストールする。

CUDAドライバーが既にインストール済みであることを前提とする(nvidia-smi コマンドで確認できる。未導入の場合はUbuntu ServerでGPUを使ってローカルLLMを動かす方法を参照してほしい)。

# NVIDIA Container Toolkitのリポジトリ追加 $ curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg $ curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list $ sudo apt update && sudo apt install -y nvidia-container-toolkit # Dockerランタイムへの登録 $ sudo nvidia-ctk runtime configure --runtime=docker $ sudo systemctl restart docker # 動作確認(コンテナ内でnvidia-smiが正常に動けばOK) $ docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi

最後のコマンドでGPU情報が表示されれば、コンテナからGPUを正しく認識できている状態だ。GPU UUIDや接続中のGPU名が表示されれば準備完了だ。

3. 作業ディレクトリの構成を整える

作業用ディレクトリを作成する。モデルファイルは数GB以上になるため、ストレージ容量が十分なパスに配置する。

# 作業ディレクトリを作成 $ mkdir -p ~/ollama-docker/{models,webui-data} $ cd ~/ollama-docker # ディレクトリ構成の確認 $ ls -la drwxr-xr-x 4 ubuntu ubuntu 4096 Jun 28 10:00 . drwxr-xr-x 12 ubuntu ubuntu 4096 Jun 28 10:00 .. drwxr-xr-x 2 ubuntu ubuntu 4096 Jun 28 10:00 models drwxr-xr-x 2 ubuntu ubuntu 4096 Jun 28 10:00 webui-data

./models はOllamaのモデルデータ保存先、./webui-data はOpen WebUIのデータ保存先として使う。この2ディレクトリにコンテナのデータを永続化するため、コンテナを削除・再作成してもデータが消えない構成になる。

Ollamaコンテナを最小構成で起動する方法

1. 最小構成のdocker-compose.ymlを作成する

まずシンプルな1サービス構成から始めて動作を確認する。~/ollama-docker/ ディレクトリに以下の内容でdocker-compose.ymlを作成する。

# ~/ollama-docker/docker-compose.yml(最小構成) services: ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped ports: - "11434:11434" volumes: - ./models:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu]

各設定の意味を確認しておく。volumes の ./models:/root/.ollama がポイントで、コンテナを削除・再作成してもモデルファイルはホスト側の ./models に残るため再ダウンロードが不要になる。restart: unless-stopped により、サーバー再起動後もOllamaが自動で起動する。

GPUを使わないCPUのみの環境では deploy: ブロック全体を削除する。CPU運用でも動作するが、推論速度はGPUに比べて大幅に遅くなる(トークン生成速度が10分の1以下になることもある)。

2. コンテナを起動してモデルを取得する

# コンテナをバックグラウンドで起動 $ docker compose up -d # 起動確認(STATUSがUpになればOK) $ docker compose ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS ollama ollama/ollama:latest "/bin/ollama serve" ollama 5 seconds ago Up 4 seconds 0.0.0.0:11434->11434/tcp # モデルの取得(コンテナ内でollama pullを実行) $ docker exec -it ollama ollama pull llama3.3:8b-instruct-q4_0 # テスト推論(APIが正常に応答するか確認) $ curl http://localhost:11434/api/generate -d '{"model":"llama3.3:8b-instruct-q4_0","prompt":"こんにちは","stream":false}'

docker exec -it ollama ollama pull というコマンド体系に最初は戸惑うかもしれない。外側の docker exec -it ollama がDockerのコマンドでコンテナ名を指定し、ollama pull がコンテナ内で実行するOllamaのCLIコマンドだ。モデル取得には数分かかる。curlのレスポンスに response フィールドが返ってきたら成功だ。

docker-compose.ymlで本番構成に仕上げる

1. 環境変数による設定の外部化

本番環境では、設定値を .env ファイルに切り出してdocker-compose.ymlから参照する構成が保守しやすい。チームで設定を共有しつつ、サーバーごとの差分は .env だけ変更すれば済む。

# ~/ollama-docker/.env OLLAMA_HOST=0.0.0.0 OLLAMA_MAX_LOADED_MODELS=2 OLLAMA_NUM_PARALLEL=4 OLLAMA_KEEP_ALIVE=30m

# docker-compose.yml(環境変数追加版) services: ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped ports: - "11434:11434" volumes: - ./models:/root/.ollama environment: - OLLAMA_HOST=${OLLAMA_HOST:-0.0.0.0} - OLLAMA_MAX_LOADED_MODELS=${OLLAMA_MAX_LOADED_MODELS:-1} - OLLAMA_NUM_PARALLEL=${OLLAMA_NUM_PARALLEL:-2} - OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-10m} deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu]

${VARIABLE:-default} の形式にすると、.env ファイルがなくてもデフォルト値でコンテナが起動する。チーム展開時の安全弁として覚えておきたい。

また、本番環境で「必須パラメータが未設定のまま起動してしまう」事故を防ぐには ${VARIABLE:?エラーメッセージ} の形式が有効だ。たとえば OLLAMA_HOST: ${OLLAMA_HOST:?OLLAMA_HOST must be set} と書いておくと、.env に値がない場合にコンテナが起動せずエラーで止まる。機密情報やパスの設定ミスを早期に発見できる。

OLLAMA_MAX_LOADED_MODELS はVRAMに同時に展開するモデルの上限数だ。VRAM 8GBの環境では 1 に絞ることを推奨する。OLLAMA_KEEP_ALIVE はモデルをVRAMに保持する時間で、頻繁にリクエストが来る環境では長めに設定するとレスポンスが速くなる。設定変更後は docker compose up -d で再起動すれば反映される。

2. ヘルスチェックの追加で本番品質に仕上げる

本番環境ではコンテナのヘルスチェックを設定しておく。サービスが応答しなくなったときに自動検知でき、後述するOpen WebUI連携の起動順制御にも使える。

# docker-compose.yml(ヘルスチェック追加版) services: ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped ports: - "11434:11434" volumes: - ./models:/root/.ollama environment: - OLLAMA_HOST=${OLLAMA_HOST:-0.0.0.0} - OLLAMA_MAX_LOADED_MODELS=${OLLAMA_MAX_LOADED_MODELS:-1} - OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-10m} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/"] interval: 30s timeout: 10s retries: 3 start_period: 30s deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu]

設定後に docker compose ps を実行すると、STATUS列に Up (healthy) と表示されれば正常稼働している。Up (starting) は起動直後の状態で、30秒ほど待てば Up (healthy) に変わる。

3. CPUとメモリの制限でOllamaコンテナを安定稼働させる

デフォルト設定のDockerコンテナは、ホストマシンのCPUとメモリを上限なく消費できる。OllamaがGPUで推論しているときでも、モデルのロード処理や並列リクエスト処理でホストCPUとメモリを大量に使うことがある。deploy.resources.limits で上限を設けておくことで、ホスト全体の安定性を守れる。

注意: deploy.resources.limits によるCPU・メモリ制限はGPUパススルー(reservations.devices)と同一の deploy: ブロックに共存できる。

# docker-compose.yml(リソース制限追加版) services: ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped ports: - "11434:11434" volumes: - ./models:/root/.ollama environment: - OLLAMA_HOST=${OLLAMA_HOST:-0.0.0.0} - OLLAMA_MAX_LOADED_MODELS=${OLLAMA_MAX_LOADED_MODELS:-1} - OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-10m} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/"] interval: 30s timeout: 10s retries: 3 start_period: 30s deploy: resources: limits: cpus: '4.00' memory: 16G reservations: cpus: '1.00' memory: 4G devices: - driver: nvidia count: all capabilities: [gpu]

limits がハードリミット(上限値)、reservations がソフトリミット(最低保証量)だ。memory の値はモデルのサイズに合わせて設定する。7Bモデル(量子化4bit)なら最低4GB、13Bモデルなら8GB以上が目安だ。制限値を決める前は、後述の docker stats で実際の消費量を計測してから数値を決めることを強く推奨する。

設定後に docker stats --no-stream を実行して制限値が反映されているか確認できる。

4. docker-compose.override.ymlで開発・本番設定を分離する

Ollamaを本番に展開するとき、「開発中はデバッグログを有効にしていたのに本番でもそのままだった」「検証機ではAPIポートをホストに直接公開していたが本番では閉じるべきだった」という設定混入は現場でよく起きる。こうしたミスを構造的に防ぐのが docker-compose.override.yml を使った環境別設定の分離だ。

docker compose up を実行すると、DockerはカレントディレクトリのComposeファイルを2段階で読み込む。まず docker-compose.yml(共通ベース定義)を読み込み、次に docker-compose.override.yml が存在すれば自動的にマージする。このoverride.ymlに開発専用設定を切り出すことで、本番へのデプロイ時に開発設定が混入しなくなる。

ディレクトリ構成のイメージは次のとおりだ。

# 推奨ディレクトリ構成 ~/ollama-docker/ ├── docker-compose.yml # ベース設定(全環境共通) ├── docker-compose.override.yml # 開発用追加設定(docker compose upで自動マージ) ├── compose.prod.yml # 本番用設定(-fで明示指定) ├── compose.stg.yml # ステージング用設定(-fで明示指定) ├── compose.ci.yml # CI用設定(-fで明示指定) ├── .env # 環境変数(.gitignoreに追加必須) ├── .env.example # .envの雛形(gitにコミットする) └── .env.prod # 本番用環境変数(本番サーバーのみに配置)

開発環境向けのoverride.yml例を示す。

# docker-compose.override.yml(開発環境専用の設定。本番には含めない) services: ollama: environment: - OLLAMA_DEBUG=1 # デバッグログを有効化(開発時のみ) - OLLAMA_KEEP_ALIVE=5m # VRAMを早めに解放して他の作業と共存させる ports: - "11434:11434" # 開発機からAPIを直接叩けるようにホスト公開 deploy: resources: limits: cpus: '2.00' # 開発機なので本番より緩い上限 memory: 8G

本番デプロイ時は -f オプションでファイルを明示指定する。-f を1つでも指定するとoverride.ymlの自動読み込みが無効になるため、ベースファイルと本番専用ファイルを両方 -f で渡す。

# 本番デプロイ(override.ymlを読ませない) $ docker compose -f docker-compose.yml -f compose.prod.yml up -d # mergeされた最終設定を事前確認(デプロイ前の必須チェック) $ docker compose -f docker-compose.yml -f compose.prod.yml config | grep -A10 environment # 開発環境での起動(override.ymlが自動適用される) $ docker compose up -d

docker compose config コマンドはmerge後の最終設定を出力する。「意図しない環境変数が入っていないか」「ポートが余分に開いていないか」をデプロイ前に確認する習慣をつけると、本番トラブルを未然に防げる。

compose.prod.ymlには本番特有の設定(固定タグのイメージ、strictなリソース制限、restart設定など)をまとめる。本番パスワードを直書きしたファイルは .gitignore に必ず追加すること。

本番環境で .env とは別の .env.prod を使いたい場合は --env-file で明示指定できる。これにより、開発用の .env(git管理)と本番用の .env.prod(本番サーバーのみに配置)を完全に分離できる。

# 本番用の.envファイルを明示指定して起動する $ docker compose --env-file .env.prod -f docker-compose.yml -f compose.prod.yml up -d # .env.prodの例(本番サーバーのみに配置・gitignoreに追加する) OLLAMA_HOST=0.0.0.0 OLLAMA_MAX_LOADED_MODELS=3 OLLAMA_NUM_PARALLEL=8 OLLAMA_KEEP_ALIVE=60m

--env-file を指定すると .env の代わりに指定したファイルが読み込まれる。開発用の .env と本番用の .env.prod を分けておくことで、開発中に設定した低いリソース上限や短い OLLAMA_KEEP_ALIVE 値が本番に混入するリスクを排除できる。

docker-compose.override.ymlをgitリポジトリにどう含めるかは、チーム運用によって2パターンある。

パターンA:.gitignoreに追加して個人設定扱いにする
個人の開発マシンごとに設定が異なる場合はこの選択が適している。代わりに docker-compose.override.yml.example をコミットしてテンプレートを共有し、各開発者がコピーして使う。

パターンB:チームで共有するためにコミットする
開発環境をチーム全員で統一したい場合はコミットする。この場合、本番サーバーに git clone したときも自動でマージされてしまうため、本番起動時は必ず -f で明示指定し、override.ymlを読ませないコマンドを徹底する。どちらのパターンでも、本番では docker compose config でマージ結果を必ず確認してほしい。

また、CI/CDパイプラインでは COMPOSE_FILE 環境変数にコロン(Linux/macOS)またはセミコロン(Windows)区切りでファイルパスをまとめて設定する方法も使われる。-f オプションと同等の効果が得られる。

# COMPOSE_FILE変数を使った本番起動の例(CI/CDパイプライン等で使用) export COMPOSE_FILE="docker-compose.yml:compose.prod.yml" docker compose up -d # 環境変数を解除するときは unset unset COMPOSE_FILE

注意: COMPOSE_FILE 変数が設定されていると compose.override.yml の自動読み込みも無効になる。開発端末に誰かが変数を設定したまま忘れていると、docker compose up がoverride.ymlを読まずに起動してしまう。echo $COMPOSE_FILE で変数の存在を確認し、不要なら unset COMPOSE_FILE で解除する手順を周知しておくことを推奨する。

3環境(dev/stg/prod)を管理する場合の起動コマンドをまとめると次のようになる。

# 開発環境(override.ymlが自動適用) $ docker compose up -d # ステージング環境(明示指定) $ docker compose -f docker-compose.yml -f compose.stg.yml up -d # 本番環境(明示指定) $ docker compose -f docker-compose.yml -f compose.prod.yml up -d # 本番環境(環境変数も本番用に切り替える) $ docker compose --env-file .env.prod -f docker-compose.yml -f compose.prod.yml up -d

5. profilesでモニタリング・デバッグサービスを選択起動する

override.ymlが「設定の上書き」を担うのに対し、profiles は「サービスの選択起動」を担う。Ollamaと同じcomposeにGPUメトリクス収集ツールや管理用コンテナを定義しておき、開発・監視時だけ有効にしたい場合に有効だ。

profiles: キーを付けたサービスはデフォルトで起動しない。--profile オプションまたは COMPOSE_PROFILES 環境変数で明示的に指定したときのみ起動する。

# docker-compose.yml(profiles付きモニタリングサービスを追加した例) services: ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped ports: - "11434:11434" volumes: - ./models:/root/.ollama # 監視時だけ起動するサービスの例(GPUメトリクス収集) dcgm-exporter: image: nvcr.io/nvidia/k8s/dcgm-exporter:3.3.9-3.6.0-ubuntu22.04 profiles: - monitoring ports: - "9400:9400" deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu]

# 通常起動(dcgm-exporterは起動しない) $ docker compose up -d $ docker compose ps NAME IMAGE STATUS ollama ollama/ollama:latest Up (healthy) # monitoringプロファイルを指定してGPUメトリクス収集も起動 $ docker compose --profile monitoring up -d $ docker compose --profile monitoring ps NAME IMAGE STATUS ollama ollama/ollama:latest Up (healthy) dcgm-exporter nvcr.io/nvidia/k8s/dcgm-exporter:... Up

COMPOSE_PROFILES 環境変数を使うと、毎回 --profile を手打ちせずにプロファイルを固定できる。開発環境の .env に書いておくだけで、コマンドは docker compose up -d のままで済む。

# .env(監視環境用) COMPOSE_PROFILES=monitoring # .envが読み込まれた状態では通常どおりdocker compose up -dを実行するだけでOK $ docker compose up -d # 本番環境の.envではCOMPOSE_PROFILESを書かないか空にする # COMPOSE_PROFILES= # 複数プロファイルを同時に有効にする場合はカンマ区切り # COMPOSE_PROFILES=monitoring,debug

【注意】profilesキーの値は大文字・小文字を区別する。Monitoring と monitoring は一致しない。小文字に統一するのが無難だ。

起動対象サービスを確認するには docker compose config --services が便利だ。profilesを指定した場合とそうでない場合の違いをデプロイ前に検証できる。

# プロファイルなしで起動されるサービスを確認 $ docker compose config --services ollama open-webui # monitoringプロファイル指定時に追加されるサービスを確認 $ docker compose --profile monitoring config --services ollama open-webui dcgm-exporter

6. compose.ci.ymlでCI環境のテスト実行を自動化する

override.ymlが開発専用設定の切り出しを担い、compose.prod.ymlが本番設定を担うのと同様に、CI環境(GitHub ActionsやJenkins等)専用の設定を compose.ci.yml に切り出すと、テスト実行の構成が明確になる。

CI環境では、バインドマウントを使わず(イメージ内にコードを含める)、ポートも公開せず、テスト実行に特化した構成にするのが原則だ。こうすることで、CI実行環境に依存しない再現性の高いテストが実現できる。

# compose.ci.yml(CI環境専用設定) services: ollama: image: ollama/ollama:latest container_name: ollama-ci environment: - OLLAMA_HOST=0.0.0.0 - OLLAMA_KEEP_ALIVE=5m # CIでは早めに解放して次のジョブに備える deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu]

CIパイプラインからの呼び出しには --abort-on-container-exit と --exit-code-from を組み合わせるのが標準的な構成だ。

# CI実行(いずれかのコンテナが終了した時点で他も停止する) $ docker compose -f docker-compose.yml -f compose.ci.yml up --abort-on-container-exit # GitHub Actionsからの呼び出し例(.github/workflows/test.yml) # - name: Run tests # run: | # docker compose -f docker-compose.yml -f compose.ci.yml up \ # --abort-on-container-exit \ # --exit-code-from ollama # run --rmで一時コンテナを実行後に削除する(pytestなど単発テストに便利) # docker compose -f docker-compose.yml -f compose.ci.yml run --rm ollama ollama list # down -v で匿名ボリュームも含めてクリーンアップする # docker compose -f docker-compose.yml -f compose.ci.yml down -v # デプロイ前の設定検証(CI/CDパイプラインに組み込む) # 合成が成功すれば終了コード0を返す(YAML構文エラーや変数欠落は非0で止まる) $ docker compose -f docker-compose.yml -f compose.ci.yml config --quiet

--abort-on-container-exit はいずれかのコンテナが終了した時点で他のコンテナも停止させるオプションだ。--exit-code-from と組み合わせることで、Ollamaコンテナの終了コードをCIジョブの成否に反映させられる。一時コンテナで完結する単発テストには run --rm を使い、テスト後は down -v で匿名ボリュームを含めてクリーンアップするのが定石だ。

config --quiet は合成に成功したとき出力を抑止して終了コード0を返す。CI/CDパイプラインの「デプロイ前ゲート」として組み込んでおくと、設定ファイルの構文エラーや ${VAR:?} 形式で必須指定した環境変数の欠落を自動検出できる。本番デプロイのジョブが始まる前に config --quiet を挟むだけで、設定ミスによる本番障害を未然に防げる。

7. override.yml・extends・profilesの使い分け

Docker Composeには設定を分割・切り替える仕組みが複数ある。機能の違いを理解した上で使い分けることが重要だ。
仕組み 単位 主な用途
compose.override.yml / -f ファイル全体 環境(dev/stg/prod)ごとに設定を差し替える
extends サービス単位 共通サービス定義を別ファイルから継承・再利用する
profiles サービスの有無 起動するサービスの組み合わせを切り替える(DCGMエクスポーターのon/off等)
YAMLアンカー フィールド単位 同一ファイル内での設定の再利用(& / * 構文)
Ollamaのように「環境ごとにリソース制限・ポート・環境変数を変えたい」というケースには compose.override.yml + -f が最も素直に対応できる。「DCGMエクスポーターやデバッグ用コンテナなど、特定の場面だけ追加したいサービスを on/off したい」なら profiles が向いている。「同じGPU設定を持つ複数サービスを定義したい」なら extends で共通定義を継承する設計が有効だ。

docker-compose.override.ymlのマージルールと落とし穴

override.ymlを使い始めると、「設定を書いたはずなのに反映されない」「ポートが二重に公開されてしまった」というトラブルに出くわすことがある。原因はDockerのマージ動作への理解不足だ。設定の種類によってマージ動作が異なるため、事前に整理しておきたい。

1. マッピング(environment・labels)はキー単位の上書きマージ

environment や labels のような「キー: 値」形式のマッピングは、同じキーが存在すれば後から読んだファイルの値で上書きされ、新しいキーは追加される。削除はできない。

# docker-compose.yml(ベース) services: ollama: environment: - OLLAMA_HOST=0.0.0.0 - OLLAMA_KEEP_ALIVE=10m # docker-compose.override.yml(開発用) services: ollama: environment: - OLLAMA_KEEP_ALIVE=5m # 上書き(10mをここで置き換える) - OLLAMA_DEBUG=1 # 追加(ベースにはないキー) # docker compose configで確認したマージ結果 services: ollama: environment: OLLAMA_HOST: 0.0.0.0 # ベースの値がそのまま残る OLLAMA_KEEP_ALIVE: 5m # override.ymlの値で上書きされた OLLAMA_DEBUG: "1" # override.ymlで追加された

デプロイ前に docker compose config を実行してマージ結果を確認するのが確実だ。意図しない環境変数が入っていないかを目視で確認する癖をつけておくと、本番の設定ミスを未然に防げる。

なお、environmentはリスト形式(- KEY=VALUE)よりもマッピング形式(KEY: VALUE)で書くほうが上書きをより確実に機能させられる。リスト形式では同じキーがベースとoverrideの両方に残る状態になりえるため、予期しない動作を起こすツールがある。environmentはマッピング形式に統一することを推奨する。

# 推奨(マッピング形式)— 同じキーはoverride側が確実に上書き # docker-compose.override.yml services: ollama: environment: OLLAMA_KEEP_ALIVE: 5m OLLAMA_DEBUG: "1" # 注意が必要(リスト形式)— 同じキーがベースとoverride両方に残る可能性あり # docker-compose.override.yml services: ollama: environment: - OLLAMA_KEEP_ALIVE=5m - OLLAMA_DEBUG=1

2. 配列(ports・volumes)は追加マージになる

ports、volumes、devices のような配列形式の設定は、ベースファイルの内容に追加される。上書き(置き換え)にはならない。この動作が予期しないポートの二重公開につながることがある。

# docker-compose.yml(ベース) services: ollama: ports: - "11434:11434" # docker-compose.override.yml(開発用 ── 別ポートを追加しようとした) services: ollama: ports: - "11435:11434" # 追加マージ(置き換えではない!) # マージ結果(docker compose configで確認) services: ollama: ports: - "11434:11434" # ベースの設定がそのまま残る - "11435:11434" # override.ymlで追加された # 両方のポートが公開された状態になる

「ベースのportsをoverride側の定義で完全に置き換えたい」という場合、配列マージでは実現できない。次の h3 で説明する expose を使った設計パターンで回避できる。

3. portsの競合を防ぐ|ベースはexposeのみ記述する設計

ポートの追加マージ問題を構造的に解消するには、ベースファイルのサービス定義に ports: を書かず、expose: のみ記述する設計が有効だ。expose: はコンテナ間通信(サービスディスカバリ)のためのポート宣言で、ホストにはポートを公開しない。ホストへのポート公開は各環境ファイルで担う。

# docker-compose.yml(ベース ── portsではなくexposeのみ記述) services: ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped expose: - "11434" # コンテナ間通信のみ(ホストへは公開しない) volumes: - ./models:/root/.ollama environment: - OLLAMA_HOST=${OLLAMA_HOST:-0.0.0.0} - OLLAMA_MAX_LOADED_MODELS=${OLLAMA_MAX_LOADED_MODELS:-1} - OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-10m} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/"] interval: 30s timeout: 10s retries: 3 start_period: 30s deploy: resources: limits: cpus: '4.00' memory: 16G reservations: cpus: '1.00' memory: 4G devices: - driver: nvidia count: all capabilities: [gpu] # docker-compose.override.yml(開発環境 ── ポートを追加) services: ollama: ports: - "11434:11434" # 開発機から直接アクセスするためにホスト公開 # compose.prod.yml(本番 ── ポートをリバースプロキシ経由にする場合は不要) services: ollama: ports: - "127.0.0.1:11434:11434" # ループバックのみ(Nginx等から内部転送)

この構成では、ベースの ports: が空なので配列マージが発生しない。開発・本番でそれぞれ必要なポートだけを各環境ファイルで定義できる。Open WebUIのような同一compose内のサービスは expose 経由でコンテナ名を使って通信できるため、ポート公開がなくても連携に支障はない。

4. command・entrypointはスカラー値として完全置換される

environment(マッピング)やports(配列)とは異なり、commandとentrypointはスカラー値(単一の値)として扱われる。override.ymlで指定すると、ベース側の値が完全に置き換えられる。

この動作はCI環境でテスト用コマンドに差し替えたいときに活用できる。

# docker-compose.yml(ベース) services: ollama: image: ollama/ollama:latest command: serve # 通常起動コマンド # docker-compose.override.yml(CI専用) services: ollama: command: serve --verbose # ベースのserveを完全に置き換える(追加マージにはならない) # マージ結果(docker compose configで確認) services: ollama: command: serve --verbose # override側の値のみが有効

commandの完全置換はスカラー値の特性だ。意図せず本番のコマンドをoverride.ymlで上書きしてしまうと、サービスが正常起動しなくなる。docker compose configでmerge結果を確認する習慣をつけておくと、こうしたミスを早期に発見できる。

5. 新規ボリュームをoverride.ymlで追加するとき、volumes:セクションも必要

override.yml内でサービスに新しいボリュームを追加する場合、そのボリューム名をトップレベルのvolumes:セクションにも定義しなければならない。ベースのdocker-compose.ymlに書いていないボリューム名をoverride.ymlのサービスで参照すると、docker compose up時にエラーになる。

# docker-compose.override.yml(開発環境専用キャッシュボリュームを追加する例) services: ollama: volumes: - dev_cache:/tmp/ollama-cache # 開発時のみ使うキャッシュボリューム # トップレベルのvolumes:セクションも同時に必要(ないとエラーになる) volumes: dev_cache:

ベースのdocker-compose.ymlにすでに定義されているボリュームを使い回す場合は、override.ymlにトップレベルのvolumes:を書く必要はない。新規に追加するボリューム名のみ定義が必要な点に注意しよう。

Open WebUIを同一composeに追加してチームで使う

1. docker-compose.ymlにOpen WebUIサービスを追加する

OllamaにOpen WebUIを導入する方法でも紹介したOpen WebUIは、同じdocker-composeファイルで一元管理できる。以下の open-webui サービスブロックを追加する。

# docker-compose.yml(Ollama + Open WebUI完成構成) services: ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped volumes: - ./models:/root/.ollama environment: - OLLAMA_HOST=0.0.0.0 - OLLAMA_MAX_LOADED_MODELS=${OLLAMA_MAX_LOADED_MODELS:-1} - OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-10m} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/"] interval: 30s timeout: 10s retries: 3 start_period: 30s deploy: resources: limits: cpus: '4.00' memory: 16G reservations: cpus: '1.00' memory: 4G devices: - driver: nvidia count: all capabilities: [gpu] open-webui: image: ghcr.io/open-webui/open-webui:main container_name: open-webui restart: unless-stopped ports: - "3000:8080" volumes: - ./webui-data:/app/backend/data environment: - OLLAMA_BASE_URL=http://ollama:11434 depends_on: ollama: condition: service_healthy

OLLAMA_BASE_URL=http://ollama:11434 の ollama はコンテナ名だ。同じdocker-composeで立ち上げたコンテナは自動的に同一ネットワークに属するため、コンテナ名でホスト解決できる。localhost や 127.0.0.1 を指定すると別コンテナに届かないため、必ずコンテナ名を使う。

depends_on に condition: service_healthy を指定することで、Ollamaのヘルスチェックが通過してからOpen WebUIが起動する。起動順の依存を明示的に制御でき、「OllamaがまだAPIを受け付けていないのにOpen WebUIが先に起動してしまう」という問題を防げる。

2. 起動と動作確認

# 全サービスをまとめて起動 $ docker compose up -d # 全サービスのステータス確認 $ docker compose ps NAME IMAGE STATUS ollama ollama/ollama:latest Up (healthy) open-webui ghcr.io/open-webui/open-webui:main Up # Open WebUIのポートでアクセスできるか確認 $ curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/ 200

ブラウザで http://サーバーIP:3000 にアクセスする。初回アクセス時に管理者アカウントの作成が求められる。その後、左上のモデル選択メニューで取得済みのモデルが表示されれば連携成功だ。

チームメンバーに共有する際はサーバーのIPアドレスとポート3000を伝えるだけでいい。composeファイルをgitで管理しておけば、新規サーバーへの展開も git clone + docker compose up -d の2コマンドで完了する。社内でChatGPTが使えない環境でのローカルLLM活用の背景については、社内でChatGPTが使えないときの代替手段も参照してほしい。

コンテナの日常運用|ログ監視・モデル更新・バックアップ

1. ログの確認方法

# 全サービスのログをリアルタイムで確認 $ docker compose logs -f # Ollamaのログのみ確認(推論状況・エラーはここで把握) $ docker compose logs -f ollama # 過去100行のみ表示 $ docker compose logs --tail=100 ollama # タイムスタンプ付きで表示 $ docker compose logs -f --timestamps ollama

推論リクエストのたびにログが出力される。モデルのロード時間・使用中のGPU・エラーはここで確認できる。本番サービスでは Elasticsearch や CloudWatch への転送設定も検討する価値がある。

2. モデルの追加・更新手順

# 新しいモデルを追加取得 $ docker exec -it ollama ollama pull mistral:7b-instruct-q8_0 # 現在取得済みのモデル一覧(SIZE列でストレージ使用量を確認) $ docker exec -it ollama ollama list NAME ID SIZE MODIFIED llama3.3:8b-instruct-q4_0 abc123def456 4.9 GB 2 days ago mistral:7b-instruct-q8_0 def456abc789 7.7 GB 1 minute ago # 不要なモデルの削除(ストレージ解放) $ docker exec -it ollama ollama rm phi-4:latest # Ollamaイメージ自体を最新版にアップデート $ docker compose pull ollama $ docker compose up -d ollama

モデルファイルはホスト側の ./models ディレクトリに保存されているため、docker compose pull でOllamaイメージを更新してもモデルデータは消えない。イメージとデータが分離している点がDockerコンテナ運用の大きな利点だ。チームで採用するモデルを選ぶ際は、ローカルLLMのモデルを比較する方法も参考にしてほしい。

3. バックアップと別サーバーへの移行

composeファイルをgitで管理するのがベストプラクティスだ。モデルデータはOllamaの公式リポジトリから再ダウンロードできるため、基本的にバックアップは不要だ。ただし帯域・時間コストを節約したいなら、./models をそのまま別サーバーへ転送できる。

# composeファイルをgitで管理(.envはgitignoreに追加する) $ git init $ echo ".env" >> .gitignore $ git add docker-compose.yml .gitignore $ git commit -m "initial ollama docker setup" # モデルデータを別サーバーへrsyncで転送(大容量のため時間がかかる) $ rsync -avz --progress ./models/ user@new-server:~/ollama-docker/models/ # 移行先でcomposeを起動するだけで環境が復元される # (モデルを再ダウンロードする必要がない)

注意: .env ファイルはパスワードやAPIキーが含まれる可能性があるため、gitignoreに必ず追加してリポジトリから除外する。.env.example としてキーの雛形だけコミットするのが一般的なやり方だ。

OllamaのREST APIを業務システムに組み込む方法で解説したAPI連携を行う場合、この構成のポート11434をそのまま利用できる。

4. docker statsでリソース消費をリアルタイム監視する

本番運用では、制限値を設定する前に実際のリソース消費量を計測することが重要だ。根拠のない数値で上限を設けると、Ollamaがメモリ不足で落ちたり、逆に制限が緩すぎて他のサービスに影響が出たりする。docker stats で実消費量を把握してから制限値を決めるのが現場での鉄則だ。

# 全コンテナのリソース使用量をリアルタイム表示 $ docker stats # 出力例(環境により異なります) CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O a1b2c3d4e5f6 ollama 12.5% 6.8GiB / 16.0GiB 42.5% 8.2kB / 2.1kB 42MB / 120MB 7890abcdef12 open-webui 0.80% 128.3MiB / 16.0GiB 0.8% 1.2kB / 0.8kB 0B / 4.1MB # 1回だけ出力して終了(シェルスクリプトや定期確認に便利) $ docker stats --no-stream

各列の見方は次のとおりだ。

・CPU %: 直近の瞬間CPU使用率(ホスト全体に対する割合)
・MEM USAGE / LIMIT: 現在のメモリ使用量 / 設定上限(制限なしならホストの全メモリが表示される)
・MEM %: 設定上限に対する使用率
・NET I/O: コンテナのネットワーク送受信量
・BLOCK I/O: ディスクI/O量

負荷試験を実施したときのピーク MEM USAGE を確認し、その1.5倍程度を memory: limits の値として設定するのが目安だ。Ollamaは推論中だけでなくモデルのロード直後にもメモリを大量消費するため、モデルを切り替えながら計測することを推奨する。
docker statsは現時点のリソース状況を手軽に把握できる一方、「昨日の推論ピーク時に何が起きたか」を事後調査したり、VRAM使用率が閾値を超えたときにアラートを飛ばしたりするには機能が不足する。継続的なメトリクス収集が必要な場合は、後述するPrometheus+cAdvisorの組み合わせが有効だ。

PrometheusとcAdvisorでOllamaコンテナを継続監視する

1. docker statsだけでは足りない場面と監視スタックの概要

docker statsはリアルタイムのリソース確認に便利だが、本番でOllamaを継続運用するにつれ、次の3つの限界にぶつかることが多い。

・履歴が残らない:ターミナルを閉じるとデータが消える。「昨晩3時にメモリが急増した原因」を後から調べられない
・アラートがない:VRAM使用率が90%を超えても通知されず、気づくのは障害発生後になりやすい
・複数コンテナの横断比較ができない:ollamaとopen-webuiのCPU傾向を重ねて見ることが難しい

これらを解決するには、cAdvisor・Prometheus・Grafanaを組み合わせた継続監視スタックが有効だ。3つのコンポーネントの役割は次のとおりだ。

・cAdvisor(Container Advisor):ホストのcgroupとDockerソケットを読み取り、コンテナのCPU・メモリ・ネットワーク・ディスクI/Oをエンドポイント /metrics でHTTP公開する
・Prometheus:設定した間隔でcAdvisorの /metrics をスクレイプし、時系列DBに蓄積する。dcgm-exporterを同時にスクレイプすればGPUメトリクスも一元管理できる
・Grafana:Prometheusをデータソースとして接続し、ダッシュボードを構築するUI。コミュニティのテンプレートをインポートするだけでよく使われる可視化が揃う

データの流れは「cAdvisor → Prometheus → Grafana」の一方向だ。3つのサービスすべてに profiles: [monitoring] を付けると、通常の docker compose up -d には含まれず、--profile monitoring を指定したときのみ起動する。

2. 監視スタックをdocker-compose.ymlに追加する

作業ディレクトリ ~/ollama-docker/ にPrometheusの設定ファイル用サブディレクトリを作成する。

# Prometheusの設定ファイル用サブディレクトリを作成 $ mkdir -p ~/ollama-docker/prometheus

次に ~/ollama-docker/prometheus/prometheus.yml を作成する。dcgm-exporterも同じmonitoringプロファイルで起動している場合、scrape_configs に追記することでGPUメトリクスも収集できる。

# prometheus/prometheus.yml global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: 'cadvisor' static_configs: - targets: ['cadvisor:8080'] # dcgm-exporterも同じmonitoringプロファイルで起動している場合は追記する # - job_name: 'dcgm-exporter' # static_configs: # - targets: ['dcgm-exporter:9400']

docker-compose.ymlに3つのサービスを追加する。Open WebUIがポート3000を使っているため、GrafanaはホストポートをLocal portの3001にマッピングする。cAdvisorは privileged: true が必要で、cgroupv2環境ではこれがないと一部メトリクスが取れない。

# docker-compose.yml(monitoringプロファイルの監視スタックを追加) services: cadvisor: image: gcr.io/cadvisor/cadvisor:v0.47.2 container_name: cadvisor profiles: - monitoring privileged: true ports: - "8080:8080" volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro - /dev/disk/:/dev/disk:ro restart: unless-stopped prometheus: image: prom/prometheus:v2.48.0 container_name: prometheus profiles: - monitoring ports: - "9090:9090" volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.retention.time=30d' depends_on: - cadvisor restart: unless-stopped grafana: image: grafana/grafana:10.2.0 container_name: grafana profiles: - monitoring ports: - "3001:3000" environment: - GF_SECURITY_ADMIN_USER=admin - GF_SECURITY_ADMIN_PASSWORD=changeme volumes: - grafana_data:/var/lib/grafana depends_on: - prometheus restart: unless-stopped # 既存のvolumes:セクションに追記する volumes: prometheus_data: grafana_data:

GF_SECURITY_ADMIN_PASSWORD は初期パスワードであり、本番環境では .env ファイルや docker compose secrets で管理し、compose.ymlに直書きしないことを推奨する。

監視スタックを起動するには --profile monitoring を指定する。起動後は次のURLで各コンポーネントのUIにアクセスできる。

# 監視スタックをmonitoringプロファイルで起動する $ docker compose --profile monitoring up -d # 全サービスのステータス確認(出力例。環境により異なります) $ docker compose --profile monitoring ps NAME IMAGE STATUS ollama ollama/ollama:latest Up (healthy) open-webui ghcr.io/open-webui/open-webui:main Up cadvisor gcr.io/cadvisor/cadvisor:v0.47.2 Up prometheus prom/prometheus:v2.48.0 Up grafana grafana/grafana:10.2.0 Up # アクセスURL # http://ホストIP:8080 - cAdvisor UI # http://ホストIP:9090 - Prometheus UI # http://ホストIP:3001 - Grafana UI(ログイン: admin / changeme) # 監視スタックだけ停止する場合 $ docker compose --profile monitoring stop cadvisor prometheus grafana

3. PromQLでOllamaコンテナのリソース使用量を確認する

Prometheus UI(http://ホストIP:9090)の「Graph」タブでPromQLを入力すると、蓄積済みのメトリクスを確認できる。Ollamaコンテナに絞り込む場合は name="ollama" のラベルフィルターを使う。

# Ollamaコンテナのみ(5分間のCPU使用率平均) rate(container_cpu_usage_seconds_total{name="ollama"}[5m]) # Ollamaコンテナのメモリ使用量(バイト) container_memory_usage_bytes{name="ollama"} # Ollamaコンテナのネットワーク受信量(5分平均) rate(container_network_receive_bytes_total{name="ollama"}[5m]) # 全コンテナのCPU傾向比較({name!=""}でルートcgroupエントリを除外) rate(container_cpu_usage_seconds_total{name!=""}[5m])

{name!=""} の条件は、cAdvisorが内部用途で生成するルートcgroupのエントリを除外するフィルターだ。これがないとシステム全体を集計した行が混在して見づらくなる。

GrafanaへのPrometheusデータソース追加手順:
・Grafana UI(http://ホストIP:3001)→ Connections → Add new connection → Prometheus を選択
・Connection URL に http://prometheus:9090 を入力(Dockerのサービス名で接続できる。localhostでは接続できない)
・「Save & test」で「Successfully queried the Prometheus API.」と表示されれば完了

コミュニティ公開のダッシュボードテンプレート「Dashboard ID: 893」はcAdvisorのメトリクスに対応しており、インポートするだけでコンテナ全体のCPU・メモリ傾向をグラフで確認できる。バージョン差異でパネルが表示されない場合は別IDのテンプレートを試してほしい。

よくあるトラブルと対処法

Dockerを使ったOllama運用でよく遭遇するトラブルとその対処をまとめる。

「Error response from daemon: could not select device driver "" with capabilities: [[gpu]]」
NVIDIA Container Toolkitが正しくDockerに登録されていない。sudo nvidia-ctk runtime configure --runtime=docker を再実行し、sudo systemctl restart docker でDockerを再起動する。それでも解消しない場合は /etc/docker/daemon.json に "runtimes" キーが追記されているか確認する。

「open-webuiが "Failed to connect to Ollama" と表示される」
OLLAMA_BASE_URL が http://localhost:11434 になっている場合に発生する。コンテナ間通信では localhost はそれぞれのコンテナ自身を指すため、Ollamaには届かない。http://ollama:11434(コンテナ名)に変更して docker compose up -d で再起動する。

「GPUが認識されているのに推論が遅い」
VRAM不足でモデルが自動的にCPUにオフロードされている可能性がある。docker compose logs -f ollama でログを確認し、「offloading N layers to CPU」のメッセージがあればモデルが大きすぎる。量子化レベルを q4_0(4bit量子化)に下げるか、より小さいパラメータ数のモデルを選ぶ。

「docker compose up -d が "no space left on device" で失敗する」
モデルファイルがディスクを埋めている。df -h でパーティション使用率を確認し、不要なモデルを docker exec -it ollama ollama rm <モデル名> で削除する。./models ディレクトリは du -sh ./models で容量を確認できる。

# ディスク使用量の確認 $ df -h # 出力例(環境により異なります) Filesystem Size Used Avail Use% Mounted on /dev/sda1 1.8T 297G 1.4T 18% /mnt/hdd /dev/mmcblk0p2 113G 59G 50G 55% / # モデルデータのサイズ確認 $ du -sh ~/ollama-docker/models # 不要なモデルの削除 $ docker exec -it ollama ollama rm phi-4:latest

「モデルのダウンロード中にコンテナが停止する」
ネットワークタイムアウトまたはメモリ不足が原因なことが多い。docker exec -it ollama ollama pull <モデル名> を再実行すると途中から再開される。ホストのメモリ使用状況は free -h で確認する。

# ホストのメモリ状況確認 $ free -h # 出力例(環境により異なります) total used free shared buff/cache available Mem: 7.8Gi 1.7Gi 141Mi 324Ki 6.1Gi 6.1Gi Swap: 4.0Gi 791Mi 3.2Gi

「Ollamaコンテナが突然停止してdocker compose psでExited (137)と表示される」
カーネルのOOM Killerによってプロセスが強制終了されている可能性が高い。次のコマンドで原因を確認する。

# OOM Killerで落ちたか確認する $ docker inspect ollama --format '{{.State.OOMKilled}} {{.State.ExitCode}}' # OOM Killedの場合の出力 true 137 # OOMKilled=true、ExitCode=137(SIGKILL)はメモリ上限超過を意味する # ホスト側のOOMログも確認する $ dmesg | grep -i 'oom\|killed'

OOMKilled=true が確認されたら memory limits の値が小さすぎる。docker stats で実消費量を確認し、制限値を増やすかアプリ側のメモリ使用量を最適化する。

「docker compose up -d 後にopen-webuiが起動しない」
Ollamaのヘルスチェックに時間がかかりタイムアウトしている場合がある。start_period を 60s に延長する。また docker compose ps でOllamaのSTATUSが starting のままになっていないか確認する。

「override.ymlを変更したのに設定が反映されない」
docker compose up -d だけでは設定変更が反映されないことがある。environmentやvolumesの変更はコンテナの再作成が必要だ。次のどちらかで対応する。

# コンテナを停止・削除してから再起動する(確実な方法) $ docker compose down $ docker compose up -d # --force-recreateで強制的にコンテナを再作成する(ボリュームは保持される) $ docker compose up -d --force-recreate # 反映されているかどうかはdocker compose configで事前確認できる $ docker compose config | grep -A5 environment

「本番デプロイで -f を使っているのにoverride.ymlの設定が混入している」
-f を1つでも指定した場合、docker-compose.yml も -f で明示しなければ予期しない動作をすることがある。-f compose.prod.yml(ベースファイルを省略)ではなく、-f docker-compose.yml -f compose.prod.yml と両方指定する。docker compose config でmerge結果を事前確認するのが確実だ。

「ports配列を上書きしたつもりが二重に公開されてしまった」
ports・volumes・devices のような配列形式の設定は上書きではなく追加マージになる。ベースファイルに ports: - "11434:11434" と書いた状態でoverride.ymlにも ports: を書くと、両方のポートが公開された状態になる。ベースファイルの ports: を削除して expose: のみを残し、ポート公開は各環境ファイルで定義する設計に変えることで解消できる。

「必須の環境変数が未設定のまま起動してしまった」
.env に値を書き忘れた場合、${VARIABLE:-} と書いていると空文字として起動してしまう。${VARIABLE:?エラーメッセージ} の形式にすると、値が未設定の場合にコンテナが起動せずエラーで止まる。接続先DBのパスワードやAPIキーなど、欠けると致命的な設定には :? を付けておくことを推奨する。

「profilesを指定してもサービスが起動しない」
profilesキーの値と --profile オプションの文字列が一致しているか確認する。大文字・小文字が区別されるため、docker-compose.ymlに Monitoring と書いて --profile monitoring と指定しても一致しない。次のコマンドで起動対象サービスを事前に検証する。

# プロファイルなしで起動されるサービスを確認 $ docker compose config --services # monitoringプロファイル指定時に起動されるサービスを確認 $ docker compose --profile monitoring config --services # COMPOSE_PROFILESが意図しない値になっていないか確認する $ echo $COMPOSE_PROFILES $ cat .env | grep COMPOSE_PROFILES

「docker compose config --quietをCIに組み込んでも設定ミスが検出されない」
config --quiet オプションはYAML構文エラーと :? 形式の必須変数欠落を検出するが、設定値の論理的な正当性(ポート番号の重複・存在しないイメージ名など)までは確認しない。デプロイ前のゲートとして有効だが、config(quietなし)で出力されたYAMLを目視確認する手順もあわせて運用に組み込むことを推奨する。

「override.ymlで新しいボリュームを追加したのにエラーになる」
override.yml内のサービスで新規ボリューム名を参照するとき、トップレベルのvolumes:セクションをoverride.yml内に定義していないと起動エラーになる。サービスのvolumes:エントリと同じファイル内にvolumes: { ボリューム名: }のトップレベル定義を追加して解消できる。

「COMPOSE_FILE変数が設定されていてoverride.ymlが意図せず除外される」
COMPOSE_FILE 環境変数が設定されていると、compose.override.yml の自動読み込みが無効になる。CI/CD環境の変数設定や他の開発者が残した設定が影響していることがある。echo $COMPOSE_FILE で変数の有無を確認し、開発環境では不要なら unset COMPOSE_FILE で解除する。

# COMPOSE_FILE変数の確認 $ echo $COMPOSE_FILE # 変数が設定されていれば解除してから再起動 $ unset COMPOSE_FILE $ docker compose up -d # override.ymlが正しく適用されているか確認 $ docker compose config | grep OLLAMA_DEBUG

「cAdvisorコンテナが起動直後にExitedになるか再起動を繰り返す」
cgroupv2環境(Ubuntu 22.04以降)でマウントのパーミッションが不足するケースがある。compose定義に privileged: true が設定されているか確認する。それでも解消しない場合はcAdvisorイメージのタグを最新版に更新する(古いcAdvisorはcgroupv2未対応のものがある)。ログは次のコマンドで確認できる。

# cAdvisorのエラーログを確認する $ docker compose --profile monitoring logs cadvisor

「PrometheusのTargetsページでcadvisorがDOWNと表示される」
prometheus.ymlの targets に指定したホスト名をPrometheusが解決できていない場合に発生する。targets: ['cadvisor:8080'] になっているか確認する。PrometheusコンテナとcAdvisorコンテナが同じDockerネットワークにいる必要がある。compose.ymlに独自の networks: を定義している場合は、両サービスが同じネットワークに所属しているか確認する。

「GrafanaでPrometheusをデータソースとして登録してもグラフが「No data」になる」
データソースのURLが http://localhost:9090 になっている場合に発生する。GrafanaコンテナからみたlocalhostはGrafana自身を指すため、Prometheusには届かない。DataSource設定のURLを http://prometheus:9090(Dockerのサービス名)に変更する。

まとめ

この記事では、OllamaをDockerコンテナで運用するための手順をステップ順に解説した。直接インストールよりも手順は増えるが、一度docker-compose.ymlを整えてしまえば環境の再現・チーム展開・バージョン管理が格段に楽になる。
ステップ やること 主要コマンド
事前準備 Docker Engine / NVIDIA Container Toolkit導入 sudo apt install nvidia-container-toolkit
最小起動 docker-compose.ymlでOllamaを定義・起動 docker compose up -d
モデル取得 コンテナ内でollama pullを実行 docker exec -it ollama ollama pull llama3.3:8b-instruct-q4_0
本番化 環境変数外部化・ヘルスチェック追加 docker compose up -d(compose修正後)
リソース制限 deploy.resources.limitsでCPU/メモリ上限を設定 docker stats --no-streamで実消費量を確認後に設定
設定分離 override.ymlで開発・本番設定を切り分ける docker compose -f docker-compose.yml -f compose.prod.yml up -d
本番環境変数 --env-fileで本番用.envを明示指定する docker compose --env-file .env.prod -f docker-compose.yml -f compose.prod.yml up -d
stg起動 ステージング環境を明示指定で起動する docker compose -f docker-compose.yml -f compose.stg.yml up -d
CI自動化 compose.ci.ymlでCIテスト実行を自動化する docker compose -f docker-compose.yml -f compose.ci.yml up --abort-on-container-exit
マージ確認 merge後の最終設定を事前に確認する docker compose config
COMPOSE_FILE CI/CDで使うファイルセットを環境変数で指定する export COMPOSE_FILE="docker-compose.yml:compose.prod.yml"
選択起動 profilesで監視・デバッグサービスを環境別に制御 docker compose --profile monitoring up -d
WebUI連携 Open WebUIをcomposeに追加 OLLAMA_BASE_URL=http://ollama:11434
日常運用 ログ確認・モデル更新・バックアップ docker compose logs -f ollama
OOM対処 コンテナの強制終了原因を調べる docker inspect ollama --format '{{.State.OOMKilled}}'
監視スタック起動 cAdvisor・Prometheus・GrafanaをmonitoringプロファイルでOllamaと同梱して起動する docker compose --profile monitoring up -d
Prometheusスクレイプ設定 prometheus.ymlでcAdvisorのエンドポイントを定義する targets: ['cadvisor:8080']
Grafanaデータソース追加 GrafanaにPrometheusを接続する(URLはDockerサービス名で指定) http://prometheus:9090

コンテナ化したOllamaをチームで活用する次のステップとして、業務特化AIアシスタントの構築がある。OllamaのModelfileでカスタムモデルを作る方法を参照して、部門ごとのプロンプト設定をチームで使い回す仕組みを整えてほしい。

Dockerによるコンテナ化は、ローカルLLMを「個人の試験環境」から「チームの業務基盤」へ格上げする実践的な手段だ。composeファイル1枚が、将来的な移行や展開のコストを大幅に下げてくれる。

Docker+OllamaのGPU構築を2日間のハンズオンで体験する

この記事で解説したdocker-compose構成やNVIDIA Container Toolkitの設定、Open WebUI連携を、実機GPU環境で手を動かしながら習得したい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。

>> ローカルAIマスターセミナーの詳細を確認する

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、DockerコンテナによるローカルLLM基盤の構築から本番運用まで体系的に学べる講座を用意しています。
>> Dockerマスター講座の詳細はこちら

<PR>手元に置いて学びを深める1冊

Docker実践ガイド 第3版(古賀 政純 著)

docker-compose.ymlの構成管理・GPU設定・リソース制限・本番デプロイまで体系的に学べる実践書。まず無料メルマガで学ぶのが第一歩、手元に1冊置いて運用スキルをさらに深めてほしい。

ローカルLLMの構築・運用に関する関連記事もあわせて参考にしてください。

・Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
・社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
・ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録

運営

リナックスマスター.JP(代表 宮崎智広)

株式会社イーネットマーキュリーが運営するLinux教育サイトです。代表の宮崎智広は現役のLinuxサーバー管理者として20年以上の実務経験を持ち、累計3,100名以上のエンジニアを指導してきました。実践型のLinuxセミナーや無料マニュアルの配布を通じてLinux人材の育成に取り組んでいます。