ollama (llama3) + docker + wsl2 + ubuntu24メモ

# はじめに
Windows11 + wsl2 + docker-desktop + rtx4090 で色々と試した結果、docker-desktopをインストールしてdockerを使うとdockerがGPUを認識しないという問題があったので、docker-desktopを使わないやりかたで進めることにした。

rtx4090の問題なのか、他のGPUが無いので試せないが、docker-desktopを使ってGPUを認識させる方法があれば教えてもらいたい。

Windowsでdocker-desktopを使いたかったけど残念。一応、wslを使って先にディストリビューションをインストールしてdocker-desktopをインストールして、その後、別のデフォルトにしないディストロビューションをいれて、それにdockerを直接インストールすれば動くが、個別に動く箇所と共通で動く箇所が混在した感じになっていてよくわからないので、それも一旦断念することに。

追加で、dockerでOllamaが扱えるようになったが、`ollama run [model]`コマンドの初回ロードが遅すぎで使い物にならなかったので、直接、ollamaはインストールしたほうがよいという結論になった。

## 検証の目的

* ollamaの設定やダウロードしたモデルを別ディスクの指定したボリュームに保存する
* イントラ内で他のPCからも接続する

## 環境

### 機器名
| コンポーネント      | 詳細                                       |
|---------------------|--------------------------------------------|
| オペレーティングシステム | Windows 11 Pro (HAV-00213)               |
| プロセッサ          | Intel Core i9-14900KF (BX8071514900KF)    |
| 冷却システム        | DeepCool LS720S ZERO DARK (R-LS720-BKNNMM-G-1) |
| マザーボード        | ASUS PROART Z790-CREATOR WIFI             |
| メモリ              | SK Hynix DDR5-5600 48GB x4 (SMD5-U96G28H-56B-D) |
| グラフィックスカード | GAINWARD NVIDIA GeForce RTX 4090 (NED4090019SB-1020P) |
| ストレージ          | Kingston NVMe SSD 2TB x2 (SKC3000D/2048G) |
| 電源ユニット        | FSP Hydro G Pro 850W (CUT593PW)            |
| 電源ユニット        | Antec NE1000G M ATX3.0                    |

### トータルスペック情報
| スペック            | 詳細                                       |
|---------------------|--------------------------------------------|
| 合計メモリ容量      | 192GB (SK Hynix DDR5-5600 48GB x4)        |
| 合計ストレージ容量  | 4TB (Kingston NVMe SSD 2TB x2)            |
| GPU スペック        | NVIDIA GeForce RTX 4090                   |
| GPU メモリ容量      | 24GB GDDR6X                               |
| CUDA コア数         | 10,496                                    |
| ベースクロック      | 1.70 GHz                                  |
| ブーストクロック    | 2.23 GHz                                  |

### パソコンショップアーク提供

https://www.ark-pc.co.jp/bto/customizer/?pc_id=2610

この開発環境は、最新のプロセッサと強力なGPU、192GBの大容量メモリ、そして4TBの高速NVMeストレージを備えていて、特に、GPUを活用したAIモデルのトレーニングや、中規模のデータの処理に最適なハイエンドのシステム。

## LAN内の他のPCからアクセス
### Windows11のファイヤーウォール/セキュリティの設定
PowerShellを起動し、以下のコマンドを入力しておく
```PowerShell
# wsl2用にフォーワードするために許可するポート
netsh.exe advfirewall firewall add rule name='open port 22 for wsl2 port forwarding' dir=in action=allow protocol=TCP localport=22
netsh.exe advfirewall firewall add rule name="open port 8080 for wsl2 port forwarding" dir=in action=allow protocol=TCP localport=8080
netsh.exe advfirewall firewall add rule name="open port 3000 for wsl2 port forwarding" dir=in action=allow protocol=TCP localport=3000
netsh.exe advfirewall firewall add rule name="open port 11434 for wsl2 port forwarding" dir=in action=allow protocol=TCP localport=11434

# 許可したポートの削除
netsh advfirewall firewall delete rule name="名前"

# 該当するlistenportにリクエストをwslへ転送
netsh.exe interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=22 connectaddress=172.19.228.252 connectport=22
netsh.exe interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=8080 connectaddress=172.19.228.252 connectport=8080
netsh.exe interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=3000 connectaddress=172.19.228.252 connectport=3000
netsh.exe interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=11434 connectaddress=172.19.228.252 connectport=11434

# Ollamaを起動しているPCからアクセスする場合
netsh interface portproxy add v4tov4 listenport=11434 listenaddress=0.0.0.0 connectport=11434 connectaddress=127.0.0.1


# 設定の一覧
netsh.exe interface portproxy show v4tov4

# 追加したインターフェースの削除
netsh.exe interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8080
```

## WSLにUbuntuをインストール
インストールコマンド
```PowerShell
wsl.exe --install -d Ubuntu-24.04
```
インストール内容の確認
```PowerShell
wsl.exe -l -v
  NAME            STATE           VERSION
* Ubuntu-24.04    Running         2
```

## Ubuntuの下準備
```bash
$ sudo apt update
$ sudo apt upgrade

# sshサーバーを設定してLAN内の他のPCからアクセスできるようにしておく
$ sudo apt install openssh-server
$ sudo vi /etc/ssh/sshd_config
ListenAddress 0.0.0.0
Port 22
PasswordAuthentication yes
$ sudo systemctl restart ssh

# デフォルトエディターの変更
$ sudo update-alternatives --config editor
```

## Nividiaのツール設定
インストールの準備
```bash
$ 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 sed -i -e '/experimental/ s/^#//g' /etc/apt/sources.list.d/nvidia-container-toolkit.list
```

パッケージをインストール
```bash
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
```

`nvidia-ctk`コマンドを使用しコンテナのランタイムを設定
```bash
sudo nvidia-ctk runtime configure --runtime=docker
```

ドライバーのインストール状況を確認（windowsでインストール済ませている前提）
```bash
$ sudo apt install nvidia-utils-535

この`nvidia-ctk`コマンドは、ホストの`/etc/docker/daemon.json`ファイルを修正。DockerがNVIDIAコンテナランタイムを使用できるようになる。

## dockerの設定
### dockerのインストール
```bash
$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh

# dockerにroot以外のユーザー権限を付与
$ sudo usermod -aG docker ユーザー名

# docker.sockにグループ権限も付与
$ sudo chmod 666 /var/run/docker.sock

# docker restart
$ sudo systemctl restart docker
```

### dockerからGPUが認識できるか確認

```bash
$ docker run --rm -it --gpus=all nvcr.io/nvidia/k8s/cuda-sample:nbody nbody -gpu -benchmark

...

> Windowed mode
> Simulation data stored in video memory
> Single precision floating point simulation
> 1 Devices used for simulation
MapSMtoCores for SM 8.9 is undefined.  Default to use 128 Cores/SM
MapSMtoArchName for SM 8.9 is undefined.  Default to use Ampere
GPU Device 0: "Ampere" with compute capability 8.9

> Compute 8.9 CUDA device: [NVIDIA GeForce RTX 4090]
131072 bodies, total time for 10 iterations: 79.378 ms
= 2164.299 billion interactions per second
= 43285.987 single-precision GFLOP/s at 20 flops per interaction
```
## Ollamaの設定
### Ollamaをdockerでインストール
dドライブの`/mnt/d/docker/ollama/volumes/ollama`に`.ollama`が保存される内容でOllamaを起動
```bash
# -v 
$ docker run -d --gpus=all -v /mnt/d/docker/ollama/volumes/ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama
```
### llama3の確認
少し時間がかかる
```bash
$ docker exec -it ollama ollama run llama3
ｓｓ>>> Send a message (/? for help)
```


:::note alert
OllamaをWSL2のdockerで起動し、初回のollama runが遅すぎで使えないので、直接インストールしたほうがよい

### ollamaの初回ロードが遅い件
* WSL2のネットワークの問題を疑ったが、REPL時のレスポンスタイムに関わる話かと思った
* OLLAMA_KEEP_ALIVEの設定があり、それがOpen WebUIを見たところデフォルト5mだったので、`-1`に変更して常駐させることにした（以下ドキュメントリンク、FAQはちゃんと読んで見るもの）

~~*一応やってみたが、未だ遅い。開発環境なので一旦我慢。*~~
:::

```bash
# サンプルリクエスト
$ curl http://localhost:11434/api/generate -d '{"model": "llama3", "keep_alive": -1}'
```

https://github.com/ollama/ollama/blob/main/docs/faq.md#how-do-i-keep-a-model-loaded-in-memory-or-make-it-unload-immediately


## 別のクライアントPCからの接続の確認
次に、ollamaでmodelをダウンロードした後、動作の確認をしてみる。

```bash
jfk@dev:~$ curl http://[OllamaをインストールしたサーバーIP]:11434/api/chat -d '{
>   "model": "llama3",
>   "messages": [
>     { "role": "user", "content": "こんにちは" }
>   ]
> }'
{"model":"llama3","created_at":"2024-05-30T09:31:37.734535263Z","message":{"role":"assistant","content":"こんにちは"},"done":false}
{"model":"llama3","created_at":"2024-05-30T09:31:37.855039962Z","message":{"role":"assistant","content":"！"},"done":false}
{"model":"llama3","created_at":"2024-05-30T09:31:37.878854043Z","message":{"role":"assistant","content":"😊"},"done":false}
{"model":"llama3","created_at":"2024-05-30T09:31:37.890928651Z","message":{"role":"assistant","content":" How"},"done":false}
{"model":"llama3","created_at":"2024-05-30T09:31:37.902984332Z","message":{"role":"assistant","content":" are"},"done":false}
{"model":"llama3","created_at":"2024-05-30T09:31:37.91514455Z","message":{"role":"assistant","content":" you"},"done":false}
{"model":"llama3","created_at":"2024-05-30T09:31:37.926537548Z","message":{"role":"assistant","content":" today"},"done":false}
{"model":"llama3","created_at":"2024-05-30T09:31:37.938067368Z","message":{"role":"assistant","content":"?"},"done":false}
{"model":"llama3","created_at":"2024-05-30T09:31:37.949465237Z","message":{"role":"assistant","content":""},"done_reason":"stop","done":true,"total_duration":579628170,"load_duration":16230123,"prompt_eval_duration":178676000,"eval_count":10,"eval_duration":214961000}
```

## Open Webuiの設定
### Open Webuiをインストール
* `-v`の設定を必要に応じて修正
* `--env WEBUI_AUTH=Fales`で起動

https://docs.openwebui.com/getting-started/

```bash
$ docker run -d -p 3000:8080 --env WEBUI_AUTH=Fales --gpus all --add-host=host.docker.internal:host-gateway -v /mnt/d/docker/ollama/volumes/ollama-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
```

インストールができた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/7b00ee87-ea3e-86ce-4589-2015b700d354.png)


## まとめ
色々と手こずったが、Ollamaでインストールしたllama3をGPUを使って動作することが確認できた。LAN内のサーバーからもAPI経由で動作の確認ができた。このサーバーをベースにLLMと対話するためのOpenWebuiやdifyの検証をしたいと思う。

Ollamaがインストールされたサーバーで直接llmとやり取りする際、コンテキストなどが保持されなかったり、色々と使えない理由があるので、一つのナレッジベースのLLMコアエンジンの一つとして扱って行くことができるのかなと考えている。

基本、RAG、プロンプト、Fine tuningなどをうまいこと活用し、また、LLM Workflowを設計して個別具体の課題や問題に対して機能するお作法や手ほどきを考えて行くことにする。