「Open WebUIやNginxも一緒に立ち上げて、開発環境を一発で整えたい」
「開発専用ツールを本番では起動させたくない。1つのcompose.ymlを書き換えずに環境を切り替えたい」
そんな課題を抱えるインフラエンジニアやサーバー管理者は多い。OllamaはUbuntu Serverへの直接インストールが一般的だが、Docker Composeを使えばGPU対応コンテナとして起動でき、サービス間の連携や環境の再現性が大きく向上する。この記事では、GPUパススルーを含むcompose.ymlの書き方から、Open WebUI・Nginxを加えたマルチサービス構成、profilesを使った開発・本番のサービス切り替え、.envによる環境変数管理、ヘルスチェックと自動再起動の設定まで、実務に直結する内容をステップごとに解説する。
この記事のポイント
・deploy.resources.reservations.devicesブロックでNVIDIA GPUをコンテナへ割り当てる
・named volumeでモデルデータを永続化し、コンテナ削除後もモデルが消えない設計にする
・Open WebUI・Nginxをdepends_onとnetworkで連携させ、profilesで開発・本番のサービスを切り替えられる
・healthcheckとrestart: alwaysで障害時の自動復旧を仕組みとして組み込める
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
Docker ComposeでOllamaを動かすメリットと適用場面
OllamaはLinuxホストに直接インストールして運用するのが最もシンプルな構成だ。では、あえてDocker Composeを使うのはどんな場面か。4つの観点で整理する。1. 環境の再現性が上がる
compose.ymlと.envファイルさえあれば、別のUbuntuホストでも同じ構成を即座に再現できる。Ubuntu ServerへのOllama直接インストールは手軽だが、チームが増えると「あの設定どうやったっけ」という状況が起きやすい。Dockerならcompose.ymlがそのまま構成ドキュメントになる。2. 複数サービスの起動順序と依存を管理しやすい
OllamaとOpen WebUI、Nginxを組み合わせる場合、起動順序の管理が必要になる。Docker Composeのdepends_onとhealthcheckを組み合わせれば、Ollamaが完全に起動してからOpen WebUIを立ち上げる、という制御が宣言的に書ける。手動でsystemdユニットの起動順を管理するより確実だ。3. 将来のKubernetes移行への橋渡しになる
compose.ymlはKubernetes manifestに近い構造を持つ。コンテナ化して運用した実績があれば、本番スケールへ移行するときの障壁が下がる。開発・検証環境をDockerで動かし、本番はK8sで動かすという段階的な展開が現実的になる。4. サービスを開発・本番で安全に切り分けられる
Prometheus・GrafanaなどのモニタリングスタックはOllamaのGPU使用率や推論レイテンシを可視化したい場面で役立つが、開発・検証機では不要なことが多い。Docker Composeのprofiles機能を使えば、1つのcompose.ymlの中で「このサービスはmonitoringプロファイルのときだけ起動する」と宣言でき、起動コマンドだけで環境を切り替えられる。本番へのデプロイスクリプトをシンプルに保ちながら、開発時の柔軟性を確保できるのがこのアプローチの利点だ。適用場面としては、「開発・検証環境を素早く構築したい」「チームメンバーが同じ構成を手元で動かす必要がある」「将来的にコンテナ基盤への移行を見込んでいる」「本番と開発でサービスの構成を変えたい」といったケースが典型的だ。
前提環境を確認する
Docker ComposeでOllamaのGPU機能を使うには、Docker Engine本体に加えてNVIDIA Container Toolkitが必要だ。順番に確認する。1. Docker Engineのインストール確認
Dockerがすでに入っているか確認する。# Dockerバージョン確認 $ docker --version Docker version 26.1.4, build 5650f9b # Docker Composeバージョン確認(プラグイン形式) $ docker compose version Docker Compose version v2.27.1
2. NVIDIA Container Toolkitの導入
GPUを使う場合、NVIDIA Container Toolkitが必要だ。すでに導入済みの場合はスキップしてよい。# GPGキーとリポジトリを追加 $ 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-get update && sudo apt-get install -y nvidia-container-toolkit # DockerランタイムへNVIDIAを登録してデーモンを再起動 $ sudo nvidia-ctk runtime configure --runtime=docker $ sudo systemctl restart docker # コンテナ内でGPUが見えるか動作確認 $ docker run --rm --gpus all nvidia/cuda:12.0-base-ubuntu22.04 nvidia-smi
基本的なcompose.ymlを書いてOllamaを起動する
まずOllamaだけをDocker Composeで起動する最小構成から始める。動作を確認してからサービスを追加していく順番が失敗しにくい。1. 作業ディレクトリとcompose.ymlの準備
# 作業ディレクトリを作成して移動 $ mkdir ~/ollama-compose && cd ~/ollama-compose # compose.ymlを新規作成 $ vim compose.yml
2. GPUパススルーを含むcompose.ymlの書き方
以下が最小構成のcompose.ymlだ。services: ollama: image: ollama/ollama:latest container_name: ollama restart: always ports: - "11434:11434" volumes: - ollama_data:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] environment: - OLLAMA_HOST=0.0.0.0 volumes: ollama_data:
・`deploy.resources.reservations.devices`ブロックがGPUパススルーの核心部分。`driver: nvidia`と`capabilities: [gpu]`が必須
・`volumes`の`ollama_data`はnamed volume。コンテナを削除してもモデルデータが消えない
・`OLLAMA_HOST=0.0.0.0`でコンテナ外からのAPIアクセスを受け付ける設定にする
CPUのみで動かす場合は`deploy`ブロック全体を削除する。`docker compose up`はdeploy.resourcesをswarmモードなしでも処理できるが、toolkitが未導入の状態でGPUブロックを書くとエラーになるので注意が必要だ。
3. 起動と動作確認
# バックグラウンドで起動 $ docker compose up -d # コンテナのログを確認 $ docker compose logs -f ollama # APIが応答するか確認(modelsが空配列なら正常) $ curl http://localhost:11434/api/tags {"models":[]} # モデルをダウンロード(コンテナ内でollamaコマンドを実行) $ docker compose exec ollama ollama pull llama3.3:8b-instruct-q4_K_M # 推論テスト $ docker compose exec ollama ollama run llama3.3:8b-instruct-q4_K_M "Linuxとは何か一言で"
マルチサービス構成に拡張する
OllamaだけでなくOpen WebUIとNginxも追加し、チームで使えるマルチサービス構成を作る。サービス名がそのままDockerの内部DNS名になるため、IPアドレスを管理する必要がない点が大きな利点だ。1. Open WebUIをサービスとして追加する
compose.ymlのservicesブロックに追記する。Ollamaにhealthcheckとnetworkブロックも加えている。services: ollama: image: ollama/ollama:latest container_name: ollama restart: always volumes: - ollama_data:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] environment: - OLLAMA_HOST=0.0.0.0 networks: - llm_net healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] interval: 30s timeout: 10s retries: 3 start_period: 40s webui: image: ghcr.io/open-webui/open-webui:main container_name: open-webui restart: always ports: - "3000:8080" volumes: - webui_data:/app/backend/data environment: - OLLAMA_BASE_URL=http://ollama:11434 networks: - llm_net depends_on: ollama: condition: service_healthy networks: llm_net: volumes: ollama_data: webui_data:
`depends_on`の`condition: service_healthy`を使うと、OllamaのhealthcheckがOKになってからOpen WebUIを起動するという順序制御が確実になる。
2. Nginxでリバースプロキシを加える
チームに対してHTTPで提供するためにNginxを追加する。まずNginx設定ファイルを用意する。# Nginx設定ディレクトリを作成 $ mkdir -p nginx/conf.d # Nginx設定ファイルを作成 $ cat > nginx/conf.d/ollama.conf << 'EOF' server { listen 80; server_name _; location / { proxy_pass http://webui:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_read_timeout 300s; } location /api/ { proxy_pass http://ollama:11434; proxy_set_header Host $host; proxy_read_timeout 300s; } } EOF
nginx: image: nginx:alpine container_name: nginx restart: always ports: - "80:80" volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro networks: - llm_net depends_on: - webui
3. 全サービスを一括起動して確認する
# 全サービスを一括起動 $ docker compose up -d # 各コンテナのステータスを確認 $ docker compose ps NAME IMAGE STATUS nginx nginx:alpine Up open-webui ghcr.io/open-webui/open-webui:main Up ollama ollama/ollama:latest Up (healthy) # ブラウザで http://サーバーIP/ にアクセスしてOpen WebUIが表示されることを確認
profilesで開発・本番のサービス起動を切り替える
Ollamaを中心とした構成が育ってくると、「本番サーバーでは動かしたくないが、運用監視や分析のために手元では起動したい」というサービスが出てくる。Docker Compose 2.2以降で使えるprofiles機能を使えば、1つのcompose.ymlの中で起動条件をサービスごとに宣言でき、コマンドを変えるだけで環境を切り替えられる。1. profilesの基本的な書き方
サービス定義に`profiles:`キーを追加するだけだ。profilesを指定しないサービスは常時起動(デフォルトサービス)となり、`docker compose up`だけで立ち上がる。services: ollama: image: ollama/ollama:latest # profiles指定なし → 常時起動 webui: image: ghcr.io/open-webui/open-webui:main # profiles指定なし → 常時起動 nginx: image: nginx:alpine # profiles指定なし → 常時起動 prometheus: image: prom/prometheus:latest ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro networks: - llm_net profiles: - monitoring # profiles: [monitoring] → --profile monitoring のときだけ起動 grafana: image: grafana/grafana:latest ports: - "3001:3000" networks: - llm_net profiles: - monitoring # profiles: [monitoring] → --profile monitoring のときだけ起動
# 本番想定: ollama・webui・nginx だけ起動(監視スタックは起動しない) $ docker compose up -d # 監視スタックも含めて起動 $ docker compose --profile monitoring up -d # 有効なサービス名を一覧確認 $ docker compose --profile monitoring config --services grafana nginx ollama prometheus webui
2. profilesのルールと注意点
プロファイルを使うときに押さえておくべき動作ルールをまとめる。・profilesなし = デフォルトサービス: `docker compose up`だけで常に起動する
・profiles指定あり = 条件付きサービス: 指定したプロファイルを有効化したときだけ起動する
・1サービスに複数プロファイル: `profiles: [monitoring, debug]`のようにどちらかが有効なら起動する
・存在しないプロファイル名を指定してもエラーにならない: デフォルトサービスだけが起動するので、typoには注意する
depends_onと組み合わせるときの注意: profilesを持たないデフォルトサービスが、profilesを持つサービスを`depends_on`で参照すると、プロファイルが無効でもそのサービスが起動してしまう。Ollama構成では、prometheus・grafanaがollamaサービスを`depends_on`で参照するのはOKだが、ollamaサービスがprometheus・grafanaを参照するのは逆方向なので避けること。
3. COMPOSE_PROFILESで環境変数からプロファイルを制御する
`--profile`オプションを毎回コマンドに付けるのが面倒な場合、環境変数`COMPOSE_PROFILES`が使える。.envファイルに書いておけば、`docker compose up`を打つだけで対応するプロファイルが自動的に有効になる。# .env(監視も行う場合) COMPOSE_PROFILES=monitoring # .env.production(本番環境用 — デフォルトサービスのみ) COMPOSE_PROFILES= # 複数プロファイルをカンマ区切りで指定 COMPOSE_PROFILES=monitoring,debug
.envファイルで環境変数とモデルパスを管理する
チームで使う場合、設定値をcompose.yml内に直接書くのは避けた方がいい。.envファイルに切り出すことで、環境ごとに設定を切り替えやすくなる。1. .envファイルの書き方
# .env ファイル(compose.ymlと同じディレクトリに配置) WEBUI_PORT=3000 NGINX_PORT=80 WEBUI_SECRET_KEY=your-secret-key-here
services: webui: ports: - "${WEBUI_PORT}:8080" environment: - OLLAMA_BASE_URL=http://ollama:11434 - WEBUI_SECRET_KEY=${WEBUI_SECRET_KEY} nginx: ports: - "${NGINX_PORT}:80"
2. モデルストレージを外付けディスクへ切り替える
大容量モデルを扱う場合、named volumeではなくホスト側の特定ディレクトリをマウントする方法が柔軟だ。# .envに追記 OLLAMA_MODELS_PATH=/mnt/nvme/ollama # compose.ymlのollamaサービスvolumesを変更 services: ollama: volumes: - ${OLLAMA_MODELS_PATH}:/root/.ollama # volumesブロックのollama_data定義は削除してよい
3. COMPOSE_PROFILESをセットで管理する
前述のprofiles機能と組み合わせる場合、.envに`COMPOSE_PROFILES`も追記しておくと環境ごとの管理が一元化できる。# .env(本番環境用) WEBUI_PORT=3000 NGINX_PORT=80 WEBUI_SECRET_KEY=your-secret-key-here OLLAMA_MODELS_PATH=/mnt/nvme/ollama COMPOSE_PROFILES= # 本番はprofilesなし(デフォルトサービスのみ) # .env.dev(開発・監視あり) WEBUI_PORT=3000 NGINX_PORT=80 WEBUI_SECRET_KEY=dev-secret-key OLLAMA_MODELS_PATH=/home/user/ollama-models COMPOSE_PROFILES=monitoring # 開発時は監視スタックも起動
ヘルスチェックと自動再起動を設定する
本番に近い環境で運用するなら、障害時の自動復旧を仕組みとして組み込んでおきたい。1. healthcheckブロックの書き方と各パラメータの意味
Ollamaの場合、`/api/tags`エンドポイントへのGETリクエストが成功するかどうかをhealthcheckの判定に使う。services: ollama: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] interval: 30s # チェック間隔(デフォルト30s) timeout: 10s # タイムアウト(デフォルト30s) retries: 3 # 失敗許容回数(デフォルト3) start_period: 40s # 起動後の猫予期間(この間の失敗はretriesに含まれない)
2. restartポリシーの選択
`restart`ポリシーには4つの選択肢がある。・`no`(デフォルト): コンテナが停止しても再起動しない
・`always`: 停止理由に関わらず常に再起動する。Dockerデーモン再起動後も自動起動する
・`on-failure`: 終了コードが0以外の場合のみ再起動する
・`unless-stopped`: `docker compose stop`で明示的に停止した場合を除いて常に再起動する
常時起動が必要なサービスには`always`か`unless-stopped`を使う。`unless-stopped`は手動メンテナンス時に`docker compose stop`で一時停止できる点が`always`との違いだ。
注意点として、ホスト上のOllamaのsystemdサービスが動いていると11434番ポートが競合する。Docker Composeで運用するときはsystemd側のOllamaサービスを停止・無効化しておく必要がある。
よくあるトラブルと対処法
実際にDocker ComposeでOllamaを動かしていると、いくつかの典型的なトラブルに遇遇する。対処法をまとめる。GPUが認識されない(could not select device driver エラー)
このエラーはNVIDIA Container Toolkitが正しく設定されていないか、Dockerデーモンが再起動されていない場合に起きる。# Dockerデーモンを再起動してかGPUが見えるか確認 $ sudo systemctl restart docker $ docker run --rm --gpus all nvidia/cuda:12.0-base-ubuntu22.04 nvidia-smi # nvidia-container-toolkitがインストールされているか確認 $ dpkg -l | grep nvidia-container-toolkit ii nvidia-container-toolkit 1.15.0-1 ...
ポートが既に使用中(Bind for 0.0.0.0:11434 failed エラー)
ホスト上でOllamaのsystemdサービスが動いていると、11434番ポートが競合する。# 競合プロセスを確認 $ sudo ss -tlnp | grep 11434 LISTEN 0 4096 0.0.0.0:11434 0.0.0.0:* users:(("ollama",pid=1234,fd=7)) # OllamaのsystemdサービスをDockerと競合しないよう停止・無効化 $ sudo systemctl stop ollama $ sudo systemctl disable ollama # その後 docker compose up -d を再実行 $ docker compose up -d
Open WebUIがOllamaに接続できない(Connection refused)
`OLLAMA_BASE_URL`に`localhost`や`127.0.0.1`を指定しているケースで起きる。コンテナ間通信ではサービス名を使う必要がある。# 誤った設定(localhostはOpen WebUIコンテナ自身を指す) # OLLAMA_BASE_URL=http://localhost:11434 ← NG # 正しい設定(サービス名で指定する) OLLAMA_BASE_URL=http://ollama:11434 # コンテナ内からollamaコンテナへの疏通確認 $ docker compose exec webui curl -f http://ollama:11434/api/tags {"models":[...]}
profilesを指定してもサービスが起動しない・意図しないサービスが起動する
profiles付きサービスが期待通りに動作しない場合、まず`docker compose config`でprofile解決後の設定を確認する。# monitoringプロファイル有効時の最終的な設定を確認 $ docker compose --profile monitoring config # 有効になるサービス名だけを一覧表示 $ docker compose --profile monitoring config --services # profiles付きサービスの状態も含めて確認(-aで停止中も表示) $ docker compose --profile monitoring ps -a
社内での活用シナリオについては社内でChatGPTが使えないときのローカルLLM選択肢も参考になる。コンテナで構築したOllamaを社内ネットワークにどう組み込むか、導入の背景を整理したい場合はそちらを読んでほしい。
まとめ
Docker ComposeでOllamaを起動する方法を、GPUパススルー・マルチサービス構成・profiles・環境変数管理・ヘルスチェックの順に解説した。ベアメタルへの直接インストールと比べると初期設定の手間は増えるが、チームでの環境共有・設定の再現性・開発と本番の安全な分離という面で明確なメリットがある。compose.ymlという単一ファイルに構成が集約されるので、構成変更の追跡やレビューもしやすくなる。| 項目 | コマンド・設定例 | ポイント |
|---|---|---|
| 起動 | docker compose up -d | バックグラウンドで全サービス一括起動 |
| GPUパススルー | deploy.resources.reservations.devices | driver: nvidia、capabilities: [gpu]が必須 |
| モデル取得 | docker compose exec ollama ollama pull llama3.3:8b-instruct-q4_K_M | コンテナ内でollamaコマンドを実行する |
| コンテナ間通信 | OLLAMA_BASE_URL=http://ollama:11434 | サービス名がDNS名として使える |
| データ永続化 | ollama_data:/root/.ollama(named volume) | コンテナ削除後もモデルが保持される |
| profiles指定で起動 | docker compose --profile monitoring up -d | monitoringプロファイルのサービスも起動する |
| 環境変数でプロファイル指定 | COMPOSE_PROFILES=monitoring(.env) | docker compose upだけで自動有効化される |
| ヘルスチェック | test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] | start_period: 40sで起動猫予を設ける |
| 自動再起動 | restart: always | unless-stoppedなら手動停止が可能 |
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Dockerの実践的なCompose設計を学ぶ最短ルートとしてDocker実践講座(linuxmaster.jp)をご活用ください。現役エンジニアが教える、本番運用で使える技術を体系的に習得できます。
・Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
・社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
・ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント
<PR>手元に置いて学びを深める1冊
Docker/Kubernetes実践コンテナ開発入門 改訂新版
Dockerの基礎からComposeの実践的な設計まで体系的に身につけたい方への一冊で、まず無料メルマガで学ぶのが第一歩、加えて手元に置くなら本書。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 次のページへ:OllamaとTelegramボットを連携させる方法|ローカルLLMをスマートフォンからチームで安全に使う手順
- 前のページへ:Ollamaのトラブルシューティングガイド|接続エラー・モデル読み込み失敗・GPU認識問題をLinuxで解決する手順
- この記事の属するカテゴリ:ローカルLLMへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます