「新しいモデルを追加するたびに全台へSSHログインして同じコマンドを打ち込む手作業が積み重なり、ミスが出始めた」
そんな悩みを持つインフラエンジニアは多い。Ollamaは1台のセットアップには十分使いやすいが、2台・3台と増えると構成のばらつきや作業ミスが避けられなくなってくる。Ansibleを活用すれば、Playbook1本で全サーバーへ同じ手順を冪等(べきとう)に実行でき、構成のばらつきを根本からなくせる。この記事では、AnsibleでOllamaを複数のLinuxサーバーに一括デプロイする手順を、inventoryファイルの作成からOllamaのインストール・systemdサービス設定の配布・モデルの自動取得まで、ステップ別に解説する。
この記事のポイント
・ansible-playbookコマンド一発でOllamaを全サーバーに一括インストールできる
・ollama pullをAnsibleタスク化することで指定モデルを全台に自動展開できる
・--limitや--tagsオプションで特定ホストや特定タスクだけを安全に再実行できる
・Playbookをidempotent設計にすることで何度実行しても副作用が発生しない
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
AnsibleでOllamaを複数台管理する利点
ローカルLLMをチームで活用する場面では、負荷分散や冗長化のために複数台のサーバーにOllamaを展開するケースが増えてくる。手作業でのセットアップは最初の1台こそ問題ないが、台数が増えると構成のばらつきが蓄積していく。現場で聞いた話だと、5台のUbuntuサーバーへ手作業でOllamaを展開したインフラチームが、インストールタイミングのずれでバージョンが2種類混在する状態になってしまったという。モデルの推論結果が台によって微妙に異なり、原因特定に丸1日を要したとのことだった。
Ansibleを使えばこの問題をPlaybook1本で解決できる。最大の強みは冪等性(idempotency)だ。Playbookを何度実行しても同じ最終状態が保証される。サーバーを追加したときも、inventoryに1行追記すれば次のPlaybook実行で自動的に同一構成になる。社内でChatGPTが制限されていてローカルLLMを複数部署向けに展開する場合(社内でChatGPTが使えないときの代替手段参照)、複数台を一貫して管理できるAnsibleの価値はさらに高まる。
前提環境の確認とSSHの設定
AnsibleはコントロールノードからSSHで対象サーバーを操作する構成だ。事前に環境を整えておこう。1. コントロールノードの要件
Ansibleを実行するコントロールノードに必要な環境:・Ubuntu 22.04 以降(または RHEL/AlmaLinux 8 以降)
・Python 3.8 以降
・Ansible 2.15 以降(pip install ansible でインストール)
2. 管理対象サーバーの要件
Ollamaをデプロイする先のサーバーに必要な環境:・Ubuntu 22.04 または 24.04 LTS(本記事の対象)
・Python 3(Ansibleモジュールの実行に必要)
・SSHサーバー稼働済み
・コントロールノードからのSSH鍵認証設定済み
3. SSH鍵認証の設定
SSH鍵認証がまだの場合は、コントロールノードから以下を実行してパスワードなしで接続できるようにする。# コントロールノードで実行 $ ssh-keygen -t ed25519 -f ~/.ssh/ansible_key -N "" $ ssh-copy-id -i ~/.ssh/ansible_key.pub ubuntu@192.168.1.101 $ ssh-copy-id -i ~/.ssh/ansible_key.pub ubuntu@192.168.1.102 $ ssh-copy-id -i ~/.ssh/ansible_key.pub ubuntu@192.168.1.103 # 接続確認 $ ssh -i ~/.ssh/ansible_key ubuntu@192.168.1.101 hostname server-01
inventoryファイルを作成する
inventoryファイルでAnsibleがどのサーバーを対象にするかを定義する。今回は`~/ansible/ollama/`を作業ディレクトリにする。# ~/ansible/ollama/inventory.ini [ollama_servers] server-01 ansible_host=192.168.1.101 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/ansible_key server-02 ansible_host=192.168.1.102 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/ansible_key server-03 ansible_host=192.168.1.103 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/ansible_key [ollama_servers:vars] ansible_python_interpreter=/usr/bin/python3
inventoryが正しく認識されているかをpingモジュールで確認する。
$ ansible -i inventory.ini all -m ping server-01 | SUCCESS => { "changed": false, "ping": "pong" } server-02 | SUCCESS => { "changed": false, "ping": "pong" } server-03 | SUCCESS => { "changed": false, "ping": "pong" }
OllamaのインストールPlaybookを実装する
Playbookファイル`ollama-deploy.yml`を作成する。Ollamaの公式インストーラは`curl -fsSL https://ollama.com/install.sh | sh`だが、シェルスクリプトをパイプで直接実行するとPlaybookを再実行するたびにインストーラが走ってしまいidempotencyが崩れる。そこでバイナリの存在確認をしてから条件付きで実行する設計にする。# ~/ansible/ollama/ollama-deploy.yml --- - name: Deploy Ollama to all LLM servers hosts: ollama_servers become: true vars: ollama_user: ollama ollama_models: - mistral - llama3.3:8b-instruct-q4_0 tasks: - name: Check if ollama binary exists stat: path: /usr/local/bin/ollama register: ollama_bin - name: Install Ollama via official installer shell: curl -fsSL https://ollama.com/install.sh | sh when: not ollama_bin.stat.exists args: executable: /bin/bash - name: Ensure ollama service is enabled and started systemd: name: ollama enabled: true state: started - name: Wait for Ollama API to be ready uri: url: http://localhost:11434/api/tags status_code: 200 retries: 15 delay: 6 register: api_check until: api_check.status == 200
`uri`モジュールでAPIが応答するまで最大90秒待機する設定にしている(retries: 15、delay: 6秒 = 最大90秒)。インストーラ実行直後はsystemdが起動するまで数秒かかるため、この待機処理が重要だ。
systemdサービス設定をPlaybookで配布する
Ollamaの公式インストーラはsystemdユニットを自動生成するが、チーム環境では追加設定が必要なことが多い。たとえばリッスンアドレスを0.0.0.0に変更して社内LAN全体から使えるようにしたり、並列処理数を増やしたりするケースが典型的だ。こういった設定は`/etc/systemd/system/ollama.service.d/override.conf`に上書き記述するのが定石で、この配布もPlaybookに組み込める。
# ollama-deploy.yml への追記(tasksセクション内) - name: Create systemd override directory for ollama file: path: /etc/systemd/system/ollama.service.d state: directory mode: '0755' - name: Deploy systemd override.conf copy: dest: /etc/systemd/system/ollama.service.d/override.conf content: | [Service] Environment="OLLAMA_HOST=0.0.0.0:11434" Environment="OLLAMA_NUM_PARALLEL=4" Environment="OLLAMA_KEEP_ALIVE=30m" mode: '0644' notify: Reload and restart ollama handlers: - name: Reload and restart ollama systemd: name: ollama daemon_reload: true state: restarted
サーバーごとにVRAMやCPUコア数が異なる場合は、`host_vars/server-01.yml`に`ollama_num_parallel: 2`のような変数を書き、`templates/override.conf.j2`でJinja2展開する方法を選ぶとよい。
モデルの一括取得タスクを追加する
OllamaはAPIが稼働していないと`ollama pull`が実行できない。前のステップで`uri`モジュールによる起動待機を入れた理由はここにある。`vars`で定義したモデルリストをloopで回してモデルを取得するタスクを追加する。# ollama-deploy.yml への追記(api_check待機タスクの直後に追加) - name: Pull specified Ollama models command: ollama pull {{ item }} loop: "{{ ollama_models }}" become: true become_user: "{{ ollama_user }}" register: pull_result changed_when: "'pulling manifest' in pull_result.stdout" timeout: 600
どのモデルを採用すべきかは用途とVRAM容量によって変わってくる。VRAMが4GBのサーバーには`-q4_0`量子化タグのモデルを、8GB以上なら`-q8_0`を選ぶのが基本方針だ。詳細はローカルLLMのモデルを比較する方法を参照してほしい。
最終的なPlaybookのディレクトリ構成は次のようになる。
~/ansible/ollama/ ├── inventory.ini # サーバーグループと接続情報 ├── ollama-deploy.yml # メインPlaybook ├── health-check.yml # ヘルスチェック用(後述) ├── templates/ │ └── override.conf.j2 # サーバー別パラメータをJinja2展開する場合 └── host_vars/ ├── server-01.yml # server-01固有の変数 ├── server-02.yml └── server-03.yml
Playbookを実行して動作を確認する
実行前に`--check`フラグでドライランを行い、差分を確認する。実際の変更は加えない。# ドライラン(変更は実行しない) $ ansible-playbook -i inventory.ini ollama-deploy.yml --check # 本番実行 $ ansible-playbook -i inventory.ini ollama-deploy.yml # 特定サーバーのみ対象にする $ ansible-playbook -i inventory.ini ollama-deploy.yml --limit server-01 # モデル取得タスクのみ再実行(tagsを事前にタスクへ付与している場合) $ ansible-playbook -i inventory.ini ollama-deploy.yml --tags models
# 全台のモデル取得状況を一括確認 $ for host in 192.168.1.101 192.168.1.102 192.168.1.103; do echo -n "$host: " curl -s http://$host:11434/api/tags \ | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d['models']),'models')" done # 期待する出力 192.168.1.101: 2 models 192.168.1.102: 2 models 192.168.1.103: 2 models
運用時の拡張とよくあるトラブル対処
本番環境でAnsible管理を続けるうえで役立つ拡張Playbookと、現場でよく踏むエラーの対処をまとめる。1. 定期ヘルスチェックPlaybook
稼働中のOllamaサービスと読み込まれているモデル数を全台で確認する軽量Playbookを別ファイルで用意しておくと便利だ。# ~/ansible/ollama/health-check.yml --- - name: Health check Ollama on all servers hosts: ollama_servers tasks: - name: Check Ollama API status uri: url: http://localhost:11434/api/tags status_code: 200 register: health - name: Show model count per server debug: msg: "{{ inventory_hostname }}: {{ health.json.models | length }} models loaded"
2. Ollamaのバージョンアップ手順
バージョンアップは`when`条件を変更してインストーラを強制再実行するタスクを追加するか、shellモジュールで`ollama --version`を取得して期待バージョンと比較する設計が実用的だ。アップデート専用のPlaybook(`ollama-upgrade.yml`)として分けておくと誤操作を防げる。3. よくあるエラーと対処
UNREACHABLE! ssh: connect to host ... Connection refused対象サーバーのSSHサービスが停止しているか、ファイアウォールでポート22がブロックされている。`systemctl status ssh`とufwのルールを確認する。
ollama pullがタイムアウトで失敗する
`timeout: 600`の値を増やすか、モデルを小さい量子化タグ(`-q4_0`)に切り替える。70Bクラスはネット環境によって30分以上かかることがある。注意: ネットワーク帯域が細い環境で70Bモデルを全台に一括pullすると、1台あたり60分以上かかるケースがある。タイムアウト値は環境に合わせて設定すること。
インストール直後にAPIが応答しない
`uri`モジュールの`retries`と`delay`を増やして待機時間を延ばす。`retries: 20` `delay: 10`(最大200秒待機)を目安にする。
毎回「changed」になって冪等性が崩れる
`ollama pull`はコマンドの性質上、実行のたびにAnsibleがchangedと判断する。`changed_when`で標準出力のキーフレーズ(例: `'pulling manifest' in pull_result.stdout`)を条件にして誤検知を抑える。
まとめ
AnsibleでOllamaを複数のLinuxサーバーに一括デプロイする手順を解説した。要点を整理する。| 作業 | 主なコマンド/ファイル | ポイント |
|---|---|---|
| inventory作成 | inventory.ini | グループ変数でPythonパスを明示する |
| 疎通確認 | ansible -i inventory.ini all -m ping | 全台pong返却を確認してから進む |
| ドライラン | ansible-playbook ollama-deploy.yml --check | 本番前に必ず差分を確認する |
| 一括デプロイ | ansible-playbook -i inventory.ini ollama-deploy.yml | 冪等設計で再実行しても安全 |
| モデル追加 | ansible-playbook ... --tags models | varsのollama_modelsを更新後にタグ実行 |
| ヘルスチェック | ansible-playbook -i inventory.ini health-check.yml | 全台のAPI稼働とモデル数を一括確認 |
まずはテスト環境の2台でinventoryとPlaybookを試してみてほしい。冪等性を体感すると手作業には戻れなくなる。
OllamaクラスターのAnsible管理を実機で体験する
Ansible+Ollamaの複数台デプロイは、頭で理解するより手を動かすほうがはるかに速く習得できる。実機GPU環境で手を動かしながら習得したい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。
・Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
・社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
・ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

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