使用場景描述#
原先 jellyfin 部署在伺服器的 k8s 環境內,沒有獨立顯卡,光靠 CPU 難以實現服務端硬體解碼,表現形式為任意平台透過瀏覽器觀看媒體過程中會提示 "該客戶端與媒體不兼容,伺服器未發送兼容的媒體格式"。
將家中的桌上型電腦安裝了 ubuntu 之後突發奇想將其作為伺服端,完全脫離工作娛樂環境。於是在安裝 docker 以及透過 docker 部署了 jellyfin 之後,想透過 pci 硬體使得 jellyfin 獲得硬解的能力。
萬萬沒想到,我還沒裝顯卡驅動,也沒有將顯卡分配給容器。這才有了此篇以記錄折騰過程。
情況分析#
客戶端會提示” 該客戶端與媒體不兼容,伺服器未發送兼容的媒體格式 “,猜測原因是伺服器自身條件受限,需求客戶端進行硬體解碼以支持視頻播放,而如果瀏覽器沒有相應視頻格式的解碼能力就會出現該提示。
或許可以嘗試安裝瀏覽器擴展以支持客戶端解碼(可行性未經驗證)
推測依據個人體驗,原有 k8s 環境下的 jellyfin 在 pc 的瀏覽器上播放任意視頻均會出現上述提示。而透過如 potplayer、jellyfin 客戶端、ios 端的 fileball 等 app 進行解碼是可以正常播放的。該情況同樣出現在 emby 上。
因此推測造成瀏覽器無法播放的原因。歸根結底還是伺服端缺少解碼能力造成的。
解決方案#
適用場景:linux 伺服器(我用的是 ubuntu22.04)、k8s 環境(非 unraid、群暉)
顯卡驅動安裝 —— 以英偉達 GTX1660TI 為例#
amd 方案如何安裝驅動請自行谷歌、百度。方式方法相同
方式一(離線安裝):
官网下载驅動安裝包,上傳到伺服器,透過 dpkg -i 的方式安裝,需求純命令行的方式安裝,如果開啟了 lightdm 桌面環境,需要手動關閉
# 注意使用root用戶登錄
> systemctl stop lightdm
# 進入純命令行模式
> init 3
> dpkg -i <官网下载的nvidia驱动包,deb后缀>
# 安裝結束重啟可以恢復,如果沒能恢復請執行下述命令後重啟
> init 5
> systemctl set-default graphical.target
方式二(聯網安裝、推薦):
1、驅動
# 先看電腦是否能識別到pci顯卡
> lspci | grep -i nvidia
26:00.0 VGA compatible controller: NVIDIA Corporation TU116 [GeForce GTX 1660 Ti] (rev a1)
26:00.1 Audio device: NVIDIA Corporation TU116 High Definition Audio Controller (rev a1)
26:00.2 USB controller: NVIDIA Corporation TU116 USB 3.1 Host Controller (rev a1)
26:00.3 Serial bus controller: NVIDIA Corporation TU116 USB Type-C UCSI Controller (rev a1)
# 查看當前系統支持的驅動
> ubuntu-drivers devices
== /sys/devices/pci0000:00/0000:00:03.1/0000:26:00.0 ==
modalias : pci:v000010DEd00002182sv000019DAsd00003539bc03sc00i00
vendor : NVIDIA Corporation
model : TU116 [GeForce GTX 1660 Ti]
driver : nvidia-driver-525 - distro non-free
driver : nvidia-driver-470-server - distro non-free
driver : nvidia-driver-535-open - distro non-free
driver : nvidia-driver-418-server - distro non-free
driver : nvidia-driver-525-open - distro non-free
driver : nvidia-driver-525-server - distro non-free
driver : nvidia-driver-450-server - distro non-free
driver : nvidia-driver-535 - distro non-free recommended
driver : nvidia-driver-470 - distro non-free
driver : xserver-xorg-video-nouveau - distro free builtin
## 安裝最新的驅動支持
> apt-get install nvidia-driver-535.54.03
## 重啟後執行,查看顯卡信息
> nvidia-smi
Mon Jul 3 00:05:19 2023
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.54.03 Driver Version: 535.54.03 CUDA Version: 12.2 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 NVIDIA GeForce GTX 1660 Ti Off | 00000000:26:00.0 Off | N/A |
| 46% 41C P8 13W / 120W | 29MiB / 6144MiB | 0% Default |
| | | N/A |
+-----------------------------------------+----------------------+----------------------+
+---------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
| 0 N/A N/A 3283 G /usr/lib/xorg/Xorg 25MiB |
| 0 N/A N/A 26860 G xfwm4 1MiB |
+---------------------------------------------------------------------------------------+
2、CUDA
上述 CUDA Version 為可安裝版本信息,不代表已經安裝,安裝方式如下(命令來自英偉達官方):
> wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
> dpkg -i cuda-keyring_1.1-1_all.deb
> apt-get update
> apt-get -y install cuda
執行完成後設置變量環境,在~/.bashrc 文件末尾添加
> vim ~/.bashrc
#添加下述內容,注意版本號
export PATH=/usr/local/cuda-12.2/bin${PATH:+:${PATH}}
#確認nvidia-persistenced守護進程是否開啟
> systemctl status nvidia-persistenced
● nvidia-persistenced.service - NVIDIA Persistence Daemon
Loaded: loaded (/lib/systemd/system/nvidia-persistenced.service; static)
Active: active (running) since Sun 2023-07-02 05:43:54 CST; 18h ago
Process: 1937 ExecStart=/usr/bin/nvidia-persistenced --user nvidia-persistenced --no-persistence-mode --verbose (code=exited, status=0/SUCCESS)
Main PID: 1947 (nvidia-persiste)
Tasks: 1 (limit: 47904)
Memory: 568.0K
CPU: 3ms
CGroup: /system.slice/nvidia-persistenced.service
└─1947 /usr/bin/nvidia-persistenced --user nvidia-persistenced --no-persistence-mode --verbose
不論哪種方式安裝的顯卡驅動,裝完之後需要重啟
docker 直通#
1、安裝 nvidia-docker2 和 nvidia-container-runtime
將顯卡掛載給 docker 時會報錯導致容器一直處於 create 狀態
# 添加apt源
> distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
&& 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/$distribution/libnvidia-container.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
> apt update
> apt-get install -y nvidia-docker2 nvidia-container-runtime
2、運行容器以掛載顯卡驅動
以 docker-compose 為例
version: "3.7"
services:
jellyfin:
container_name: jellyfin
image: "jellyfin/jellyfin:latest"
environment:
- PUID=0
- GUID=0
- NVIDIA_DRIVER_CAPABILITIES=all
- NVIDIA_VISIBLE_DEVICES=all
ports:
- "10029:8096"
volumes:
- "/root/jellyfin/config:/config"
- "/mnt/media:/media"
restart: always
user: root
devices:
- "/dev/dri:/dev/dri"
deploy:
resources:
reservations:
devices:
- capabilities: ["gpu"]
jellyfin 硬解設置#
這裡就沒啥好說的,有條件了就全勾上。
結語#
到此為止算是完成了 jellyfin 的硬體直通,實測原本不支持播放視頻的瀏覽器也可以進行媒體播放。
並且,當有用戶在播放媒體時,能明顯觀察到顯卡實際顯存佔用的變化
Mon Jul 3 00:47:21 2023
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.54.03 Driver Version: 535.54.03 CUDA Version: 12.2 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 NVIDIA GeForce GTX 1660 Ti Off | 00000000:26:00.0 Off | N/A |
| 46% 44C P2 31W / 120W | 257MiB / 6144MiB | 3% Default |
| | | N/A |
+-----------------------------------------+----------------------+----------------------+
+---------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
| 0 N/A N/A 3725 G /usr/lib/xorg/Xorg 13MiB |
| 0 N/A N/A 6735 C /usr/lib/jellyfin-ffmpeg/ffmpeg 238MiB |
+---------------------------------------------------------------------------------------+
對比發現當用戶在 web 客戶端進行播放時,jellyfin 伺服端正在用顯卡進行解碼,顯卡內存佔用由 29MiB 變為 257MiB,其中運行的進程為 ffmpeg
故,可以總結為本文推論相對正確。可以透過硬體解碼的方式消除 jellyfin 客戶端出現的 "該客戶端與媒體不兼容,伺服器未發送兼容的媒體格式" 的提示。
也從側面說明了,在無顯卡的情況下,jellyfin 伺服端不能進行解碼,視頻解碼的方式透過客戶端本地進行,這才有了 web 無法播放但客戶端 app 可以的情況。這也可以推出,此情況下,無論 jellyfin 上是否設置第三方 ffmpeg 客戶端不影響客戶端本地解碼,會出現報錯提示僅僅是因為伺服端解碼能力不足而已。
題外話
nvidia-docker2 是 nvidia 對 docker 容器的支持組件,如果不採用 docker 方式部署服務,可以不裝。
同樣的方式可以應用在 stable diffution 的 docker 項目上。實現遠程煉丹🫠
參考資料#
1、Pop!_OS 22.04(Ubuntu 22.04)安裝 Nvidia GPU 驅動、CUDA、cuDNN 以及 Docker GPU 支持(nvidia-docker2)
2、CUDA Toolkit 12.1 Downloads