【第3回】Ollamaを使ったDockerライクなLLM導入と管理:AlmaLinux上で構築するセキュアなAI API基盤

前回の連載第2回では、AlmaLinux 9/10環境においてNVIDIA GPUドライバとCUDA Toolkitをクリーンインストールし、nouveauの無効化やContainer Toolkitのセットアップといった「インフラの土台作り」を完了させました。GPUという強力なハードウェアリソースを、OSとコンテナから安全に利用できる状態が整っています。

今回はいよいよ、この基盤の上にローカルLLMの実行エンジンをデプロイします。数あるLLMエンジンの中でも、現在世界中のエンジニアから最も高い支持を集めている「Ollama(オラマ)」を採用し、エンタープライズの現場で通用するセキュアなAPI基盤を構築していきます。

コウ君

リナックス先生、Ollamaって公式サイトに行くと「Download for Linux」っていうボタンがあって、1行のcurlコマンドが書いてありますよね。これをコピペして実行するだけでサクッと構築できるんじゃないですか?

リナックス先生

コウ君、個人のMacや検証用の使い捨てVMならそれでも構いません。しかし、企業のインフラとして長期運用するサーバーにおいて、外部のシェルスクリプトをroot権限で直接実行(curl ... | sh)するのは、構成管理の観点から絶対に避けるべきアンチパターンです。今回はプロのインフラエンジニアとして、ホストOSを汚さずにPodmanコンテナでOllamaを運用し、さらにNginxを用いたアクセス制御まで組み込む本格的なアーキテクチャを設計します。

本記事では、ただOllamaを動かすだけでなく、インフラエンジニアの視点から「プロセス管理」「ストレージ永続化」「セキュリティ(認証とTLS)」に焦点を当てて、本番環境への導入を想定した手順を徹底解説します。

📚 本連載のカリキュラム(全8回)


1. Ollamaとは何か?インフラエンジニア視点のアーキテクチャ解説

Ollamaは、ローカル環境でLLMを稼働させるためのプラットフォームとして急速にデファクトスタンダードの地位を確立しました。その理由は、AI開発者だけでなく、インフラエンジニアやDevOpsエンジニアにとっても「非常に直感的で扱いやすい設計」になっているからです。

1.1. DockerにインスパイアされたUX(ユーザー体験)

Ollamaの最大の革新性は、Dockerのコマンド体系をAIモデルの管理にそのまま持ち込んだことです。
コンテナの世界では docker pull ubuntu でイメージを取得し、docker run で起動しますが、Ollamaの世界では ollama pull llama3 でモデルをダウンロードし、ollama run で推論を開始します。また、Dockerfileに相当する 「Modelfile」 を記述することで、独自のシステムプロンプトや推論パラメーター(Temperatureなど)を組み込んだカスタムモデルをビルド(ollama create)することができます。

この「インフラエンジニアが慣れ親しんだパラダイム」が、Ollamaの運用ハードルを劇的に下げています。

1.2. バックエンドアーキテクチャ:Go言語とllama.cppの融合

インフラエンジニアとして、Ollamaの内部構造(アーキテクチャ)を理解しておくことは、トラブルシューティングにおいて極めて重要です。

  • Ollamaサーバー本体(Go言語): OllamaのデーモンはGo言語で記述されており、HTTP REST APIサーバー(デフォルトポート:11434)として機能します。メモリ管理、モデルのダウンロード、クライアントからのリクエスト受け付けを担います。
  • 推論エンジン(llama.cpp): 実際にGPUやCPUを使用して行列計算を行う心臓部には、第4回で詳しく解説する「llama.cpp」のバイナリが内包されています。Ollamaはリクエストを受け取ると、モデルの量子化形式(GGUFなど)を読み取り、バックグラウンドでllama.cppのプロセスを動的に制御して推論を行います。

さらにOllamaは、「一定時間(デフォルト5分間)アクセスがないと、自動的にGPUのVRAMからモデルをアンロード(解放)する」というTTL(Time To Live)機能を持っています。これにより、複数の異なるモデルを1台のGPUサーバーで交互に利用するようなケースでも、VRAMの枯渇(OOM)を自律的に防いでくれる賢い設計となっています。

コウ君

なるほど、Ollama自体が推論をしているわけではなくて、APIサーバーとしてうまく裏側の計算エンジン(llama.cpp)をコントロールしているんですね!

2. AlmaLinuxでのOllama構築:PodmanとQuadletを用いたモダンなコンテナ運用

それでは実際にAlmaLinux上にOllamaを構築します。前述の通り、公式のインストールスクリプトを利用してホストOSに直接インストールすることは避け、AlmaLinux 9で標準採用されているPodmanを用いたコンテナ運用を行います。

2.1. コンテナ運用のメリット

Ollamaをコンテナで稼働させる最大のメリットは「ホストOSのクリーン化」と「構成のコード化」です。OllamaのバージョンアップはコンテナイメージのPullと再起動だけで完了し、万が一システムがおかしくなった場合でも、コンテナを破棄して再作成するだけで済みます。

2.2. Quadletによるsystemdの統合(RHEL 9系のベストプラクティス)

AlmaLinux 9(およびRHEL 9)における最新のコンテナデーモン化のベストプラクティスは、podman generate systemdコマンド(非推奨へ移行中)ではなく、「Quadlet(クオドレット)」を利用することです。
Quadletは、systemdのユニットファイル形式(.containerなど)でコンテナの定義を記述すると、systemdが自動的にPodmanの起動・停止を管理してくれる非常に強力な機能です。

まず、システム全体で稼働させるためのQuadlet定義ファイルを配置するディレクトリを作成します。

sudo mkdir -p /etc/containers/systemd

次に、Ollamaコンテナの定義ファイル(ollama.container)を作成します。

cat << 'EOF' | sudo tee /etc/containers/systemd/ollama.container
[Unit]
Description=Ollama LLM Server Container
After=network-online.target

[Container]
Image=docker.io/ollama/ollama:latest
ContainerName=ollama
# NVIDIA GPUをコンテナにパススルーする
AddDevice=nvidia.com/gpu=all
# コンテナ内の11434ポートをホストの127.0.0.1(ローカル)にバインド
PublishPort=127.0.0.1:11434:11434
# モデルデータを永続化するためのボリュームマウント
Volume=ollama_data:/root/.ollama
# タイムゾーンをホストと同期
Environment=TZ=Asia/Tokyo
# モデルのVRAMアンロード時間を無効化(常にVRAMに常駐させたい場合)
# Environment=OLLAMA_KEEP_ALIVE=-1

[Install]
WantedBy=multi-user.target
EOF

⚠️ セキュリティ設計のポイント:PublishPortの指定
ここで非常に重要なのが、PublishPort=127.0.0.1:11434:11434 と指定している点です。もし 11434:11434 とだけ書いた場合、コンテナはホストのすべてのインターフェース(0.0.0.0)でListenしてしまい、社内ネットワークから認証なしでAI APIが叩き放題になってしまいます。これを防ぐため、必ずlocalhost(127.0.0.1)のみにバインドし、外部からのアクセスは後述のNginxを経由させるアーキテクチャとします。

2.3. systemdの再ロードとコンテナの起動

Quadletファイルを配置したら、systemdのデーモンをリロードします。これにより、Quadletが自動的にコンテナ起動用のユニットファイル(ollama.service)を生成します。

# systemdのデーモンリロード(Quadletジェネレーターの実行)
sudo systemctl daemon-reload

# サービスの自動起動有効化と起動
sudo systemctl enable --now ollama.service

# ステータスの確認
sudo systemctl status ollama.service

ステータスが active (running) になっていれば成功です。Ollamaの初期イメージのダウンロードがバックグラウンドで行われているため、しばらく待ってから以下のコマンドでPodmanのコンテナ状態を確認します。

sudo podman ps
# ollamaコンテナが稼働しており、127.0.0.1:11434にポートフォワードされていることを確認

3. Modelfileを活用したLLMのチューニングとパラメーター制御

Ollamaサーバーが立ち上がったら、実際にAIモデルをPull(ダウンロード)して動かしてみましょう。今回はMeta社が公開している高性能オープンモデル「Llama 3 (8B)」を利用します。

コウ君

Podmanの中で動いているOllamaに、どうやってコマンドを送るんですか?

リナックス先生

ホストOSから podman exec コマンドを使って、コンテナ内の ollama バイナリを直接叩くのが一番スマートです。もちろん、OllamaはHTTP APIを持っているので curl でリクエストを送ることも可能ですが、CLIのチャットUIを使うにはexecが便利ですよ。

3.1. モデルのPullと動作確認

まずは標準のLlama 3モデルをダウンロードし、そのままインタラクティブなチャット画面に入ります。(初回は数GBのダウンロードが発生します)

# コンテナ内のollamaコマンドを実行してLlama 3を起動
sudo podman exec -it ollama ollama run llama3

>>> こんにちは、あなたは誰ですか?
(AIの応答が返ってくれば成功です。終了するには /bye を入力します)

3.2. インフラエンジニアが知るべき「Modelfile」の制御

標準モデルをそのまま動かすだけでは、AIは英語で返答してしまったり、システムの目的に合わない回答をしてしまうことがあります。実務では、システムプロンプト(AIの基本人格やルール)を固定し、メモリリソースを最適化するために「Modelfile」を記述してカスタムモデルをビルドします。

ホストOS上の適当なディレクトリに、以下のような Modelfile を作成します。

# my-llama3-Modelfile という名前で保存
FROM llama3

# Temperature(回答のランダム性)。0に近づけるほど決定的・論理的になる
PARAMETER temperature 0.3

# コンテキストウィンドウサイズ(トークン数)。大きくすると過去の記憶を長く保持できるが、VRAM消費が激増する
PARAMETER num_ctx 4096

# システムプロンプト(AIの絶対的なルール)
SYSTEM """
あなたはプロのLinuxインフラエンジニアです。
ユーザーからの質問には、必ず日本語で、論理的かつ簡潔に答えてください。
推測で回答せず、正確な技術的根拠を提示してください。
"""

作成した Modelfile を用いて、独自のモデル(例:infra-llama3)をビルドします。この際、ホスト側のファイルをコンテナ内に読み込ませる必要があります。

# ホストのModelfileをコンテナ内に渡し、カスタムモデルをビルドする
sudo podman exec -i ollama ollama create infra-llama3 -f - < my-llama3-Modelfile

# 作成されたモデルのリストを確認
sudo podman exec -it ollama ollama list

# カスタムモデルでチャットを起動
sudo podman exec -it ollama ollama run infra-llama3

インフラ視点でのポイントは PARAMETER num_ctx 4096 です。このコンテキストサイズをデフォルト(通常2048〜4096)から、例えば 128000 などに無闇に増やすと、モデル自身のVRAM容量(Weight)に加えて、KVキャッシュ用のVRAMが爆発的に増加し、一発で CUDA Out of Memory を引き起こします。ハードウェアのVRAM容量(前回の第2回で解説)と照らし合わせ、適切な上限値をModelfileで強制(ハードコード)しておくことは、サーバーダウンを防ぐための重要なインフラ設計です。

4. エンタープライズ必須:Nginxを用いたAPIエンドポイントのセキュア化

ここまでで、ローカルループバック(127.0.0.1:11434)にてOllamaが安全に稼働するようになりました。しかし、このAPIを社内の他のアプリケーション(例えば社内チャットツールや、別のWebサーバー)から呼び出すためには、外部に公開する必要があります。

4.1. 直接公開の危険性とリバースプロキシの役割

Ollamaには、デフォルトで認証機能(パスワードなど)やHTTPSによる暗号化通信機能が備わっていません。環境変数 OLLAMA_HOST=0.0.0.0 を設定してポートを直接開けてしまうと、ネットワークにアクセスできる人間なら誰でも、高価なGPUリソースを使い放題になってしまいます。

そこで、WebサーバーのデファクトスタンダードであるNginx(エンジンエックス)をリバースプロキシとして前段に配置し、以下の機能を担わせます。

  1. TLS/SSL暗号化: 通信の盗聴を防止(今回は社内向けを想定し自己署名証明書、またはLet’s Encryptを利用)。
  2. Basic認証 / アクセス制御: 許可されたシステムやユーザーのみがAPIを叩けるようにする。
  3. レートリミット(リクエスト制限): 短時間に大量のAPIリクエストを投げられ、GPUが過負荷でダウンするのを防ぐ。

4.2. NginxのインストールとBasic認証の準備

AlmaLinuxにNginxをインストールし、Basic認証用のパスワードファイルを生成します。

# Nginxとhttpd-tools(htpasswdコマンド用)のインストール
sudo dnf install -y nginx httpd-tools

# Basic認証用ユーザーの作成(例としてユーザー名:ai-client)
sudo htpasswd -c /etc/nginx/.htpasswd ai-client
# (プロンプトでパスワードを2回入力します)

4.3. Nginxのリバースプロキシ設定

Nginxの設定ファイルを作成し、443ポート(HTTPS)で受けた通信を、Ollamaコンテナの 127.0.0.1:11434 へプロキシ(転送)するように構成します。※SSL証明書(サーバー証明書と秘密鍵)は既に /etc/pki/tls/ 等に配置済みであると仮定します。

cat << 'EOF' | sudo tee /etc/nginx/conf.d/ollama.conf
server {
    listen 443 ssl;
    server_name ai-api.yourcompany.local;

    # SSL証明書の設定(実環境に合わせてパスを変更)
    ssl_certificate     /etc/pki/tls/certs/server.crt;
    ssl_certificate_key /etc/pki/tls/private/server.key;
    ssl_protocols       TLSv1.2 TLSv1.3;

    # LLMのレスポンスはタイムアウトになりやすいため長めに設定
    proxy_read_timeout 300;
    proxy_connect_timeout 300;
    proxy_send_timeout 300;

    location / {
        # Basic認証の有効化
        auth_basic "Restricted AI API";
        auth_basic_user_file /etc/nginx/.htpasswd;

        # Ollamaコンテナへのプロキシ
        proxy_pass http://127.0.0.1:11434;
        
        # ヘッダーの転送
        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_set_header X-Forwarded-Proto $scheme;

        # Ollama APIのストリーミング応答(Server-Sent Events)をバッファリングせずに通す
        proxy_buffering off;
    }
}
EOF

⚠️ proxy_buffering off; の重要性
ChatGPTのような生成AIのUIは、文字が1文字ずつパラパラと表示される「ストリーミング応答」を利用しています。Nginxの proxy_buffering がデフォルト(on)のままだと、NginxがOllamaからのレスポンスを一定サイズになるまで内部に溜め込んでしまうため、ユーザー画面では「数十秒間何も表示されず、突然全ての文章が表示される」という非常に悪いUXを引き起こします。AI APIのリバースプロキシ設計における絶対の定石です。

4.4. ファイアウォールの開放とNginxの起動

設定が完了したら、Nginxを起動し、firewalldでHTTPS(443番ポート)の通信を許可します。

# Nginxの構文チェック
sudo nginx -t

# Nginxの起動と自動起動化
sudo systemctl enable --now nginx

# firewalldでHTTPSを開放
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

これで、社内の別サーバーから curl -u ai-client:パスワード https://ai-api.yourcompany.local/api/generate ... のように、安全かつ暗号化された状態でOllamaのAPIを叩くことができるようになりました。まさにエンタープライズに相応しいセキュアなAI基盤の完成です。

5. まとめと次回の予告

本記事「【第3回】Ollamaを使ったDockerライクなLLM導入と管理」では、インフラエンジニアの視点から以下のシステムアーキテクチャを構築しました。

  • アーキテクチャの理解: OllamaがGo言語のAPIサーバーとllama.cppの推論エンジンを統合し、VRAMの動的アンロード機能(TTL)を備えていることを学んだ。
  • Quadletによるモダンなコンテナ運用: ホストOSを汚染しないよう、PodmanとQuadletを用いてOllamaをsystemdデーモンとして堅牢にデプロイした。
  • Modelfileによるリソースと品質の統制: コンテキストサイズ(num_ctx)を制限し、システムプロンプトを埋め込んだカスタムモデルを作成することで、OOMエラーを未然に防ぐインフラ設計を行った。
  • NginxによるセキュアなAPI公開: Ollama自体をlocalhostに隔離し、NginxリバースプロキシによるTLS暗号化、Basic認証、およびストリーミング応答(proxy_buffering off)の最適化を実施した。

ここまでの第1回〜第3回の連載で、GPUを搭載した強力なサーバー上で、Ollamaを用いた「標準的なローカルLLM環境」が完成しました。社内のPoC(概念実証)や小規模な運用であれば、このアーキテクチャで十分に戦うことができます。

しかし、エンタープライズの現場では「高価なGPUサーバーを用意できない(CPU環境しかない)」「VRAMが少なすぎる」といった厳しいハードウェア制約に直面することが多々あります。
そこで次回、【第4回】llama.cppによるCPU/低VRAM環境でのモデル推論では、Ollamaの裏側でも動いていた「llama.cpp」をあえて単体で直接操作し、量子化(GGUF)技術とCPUオフロードを駆使して、低スペックなサーバーでもAIを稼働させる「職人技」のチューニングに迫ります。ご期待ください!

▼ 【インフラ環境を構築しよう】 ▼

Podman/DockerでAIを動かすなら!
「高コスパおすすめVPS・専用サーバー」

VPSランキングを見る

AI時代のインフラ設計スキルを活かす
「ITエンジニア専門転職」

転職エージェントを見る

コメント