diff --git a/.env.example b/.env.example index 367b946..601b695 100644 --- a/.env.example +++ b/.env.example @@ -25,10 +25,10 @@ PYXIS_SITE_ADDRESS=:80 PYXIS_HTTP_PORT=80 PYXIS_HTTPS_PORT=443 -# 録画をあとからエンコードするときの変換器。Software か Vaapi (GPU を渡したとき) +# 録画をあとからエンコードするときの変換器。Software、Vaapi、Nvenc のどれか (GPU を渡したとき) CARINA_ENCODINGS_PREFER=Software -# ライブと録画再生をその場で変換するときの変換器。Software か Vaapi (GPU を渡したとき) +# ライブと録画再生をその場で変換するときの変換器。Software、Vaapi、Nvenc のどれか (GPU を渡したとき) CARINA_TRANSCODING_PREFER=Software # VAAPI で使う GPU の描画ノード diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0e686df..e9316fb 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -34,7 +34,7 @@ jobs: - name: compose.yml on its own run: docker compose config -q - name: compose.yml with every device file laid over it - run: docker compose -f compose.yml -f examples/tuner-dvb.yml -f examples/tuner-usb.yml -f examples/gpu-intel.yml config -q + run: docker compose -f compose.yml -f examples/tuner-dvb.yml -f examples/tuner-usb.yml -f examples/gpu-intel.yml -f examples/gpu-nvidia.yml config -q compose-up: runs-on: ubuntu-latest diff --git a/README.md b/README.md index b52cecc..de5fa42 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ B-CAS カードを 1 枚しか持っていなくても、別の機械のチュ - 録画用のディスク。地上波の録画は 1 時間あたり約 7 GB - チューナー。Linux DVB で `/dev/dvb/adapterN` として見える PCIe・USB のカード、または USB チューナーの CECH-ZD1 - B-CAS カードとカードリーダー。ホストで pcscd を動かしておきます -- Intel の GPU(任意)。H.265 と AV1 のエンコード、ライブと再生の変換に使います +- Intel の GPU か NVIDIA の GPU(任意)。NVIDIA は NVIDIA Container Toolkit とドライバ 530.41.03 以上が要ります。H.265 と AV1 のエンコード、ライブと再生の変換に使います チューナーとカードが無い機械でも、合成チューナーで画面を開くところまでは試せます。 @@ -36,7 +36,7 @@ cp driver/examples/driver-dvb.json driver/driver.json docker compose -f compose.yml -f examples/tuner-dvb.yml up -d ``` -`examples/` のファイルはホストのデバイスをコンテナに渡すもので、USB チューナーなら `tuner-usb.yml`、Intel の GPU なら `gpu-intel.yml` を重ねます。\ +`examples/` のファイルはホストのデバイスをコンテナに渡すもので、USB チューナーなら `tuner-usb.yml`、Intel の GPU なら `gpu-intel.yml`、NVIDIA の GPU なら `gpu-nvidia.yml` を重ねます。\ `.env` に `COMPOSE_FILE=compose.yml:examples/tuner-dvb.yml` と書いておくと、以後は `docker compose up -d` だけで起動します。 起動したら、ブラウザで `http://<サーバのアドレス>/` を開きます。\ @@ -62,8 +62,8 @@ docker compose logs app | grep 'Sign in as' | `CARINA_PUBLIC_ORIGIN` | ブラウザから見たサーバのアドレス。OIDC でサインインするときに必要です | 空 | | `PYXIS_SITE_ADDRESS` | Caddy が待ち受けるアドレス。ドメインを書くと証明書を取得して https で開きます | `:80` | | `PYXIS_HTTP_PORT` / `PYXIS_HTTPS_PORT` | ホスト側で開くポート | `80` / `443` | -| `CARINA_ENCODINGS_PREFER` | エンコードに使うエンコーダー。`Software` か `Vaapi` | `Software` | -| `CARINA_TRANSCODING_PREFER` | ライブと再生の変換に使うエンコーダー。`Software` か `Vaapi` | `Software` | +| `CARINA_ENCODINGS_PREFER` | エンコードに使うエンコーダー。`Software`・`Vaapi`・`Nvenc` のどれか | `Software` | +| `CARINA_TRANSCODING_PREFER` | ライブと再生の変換に使うエンコーダー。`Software`・`Vaapi`・`Nvenc` のどれか | `Software` | | `CARINA_RENDER_NODE` | VAAPI で使う GPU のデバイス | `/dev/dri/renderD128` | 番組表の収集間隔や品質の閾値などの細かい設定は Carina の README にあります。\ diff --git a/charts/pyxis/ci/nvidia-values.yaml b/charts/pyxis/ci/nvidia-values.yaml new file mode 100644 index 0000000..5278380 --- /dev/null +++ b/charts/pyxis/ci/nvidia-values.yaml @@ -0,0 +1,9 @@ +# NVIDIA の GPU を RuntimeClass と device plugin で渡し、エンコードを Nvenc にする +app: + encodingsPrefer: Nvenc + transcodingPrefer: Nvenc + gpu: + mode: nvidia +postgres: + auth: + password: check diff --git a/charts/pyxis/templates/app-deployment.yaml b/charts/pyxis/templates/app-deployment.yaml index 91ad39e..d99354f 100644 --- a/charts/pyxis/templates/app-deployment.yaml +++ b/charts/pyxis/templates/app-deployment.yaml @@ -23,6 +23,10 @@ spec: spec: {{- with include "pyxis.imagePullSecrets" . }}{{ . | trim | nindent 6 }}{{- end }} {{- with include "pyxis.nodeSelector" (dict "root" . "own" $app.nodeSelector) }}{{ . | trim | nindent 6 }}{{- end }} + {{- if eq $app.gpu.mode "nvidia" }} + # NVIDIA Container Toolkit の runtime が、ドライバのライブラリと装置をコンテナに差し込む + runtimeClassName: {{ $app.gpu.runtimeClassName }} + {{- end }} securityContext: fsGroup: {{ $gid }} {{- if eq $app.gpu.mode "none" }} @@ -104,8 +108,14 @@ spec: value: {{ $app.encodingsPrefer }} - name: Transcoding__Prefer value: {{ $app.transcodingPrefer }} + {{- if or (eq $app.gpu.mode "devicePlugin") (eq $app.gpu.mode "hostPath") }} - name: Machine__RenderNode value: {{ $app.gpu.renderNode }} + {{- end }} + {{- if eq $app.gpu.mode "nvidia" }} + - name: NVIDIA_DRIVER_CAPABILITIES + value: video,compute,utility + {{- end }} {{- with $app.extraEnv }} {{- toYaml . | nindent 12 }} {{- end }} @@ -148,6 +158,9 @@ spec: {{- $_ := set $resources "requests" (merge (dict $app.gpu.resource "1") ($resources.requests | default dict)) }} {{- $_ := set $resources "limits" (merge (dict $app.gpu.resource "1") ($resources.limits | default dict)) }} {{- end }} + {{- if eq $app.gpu.mode "nvidia" }} + {{- $_ := set $resources "limits" (merge (dict $app.gpu.nvidiaResource (toString $app.gpu.nvidiaCount)) ($resources.limits | default dict)) }} + {{- end }} {{- with $resources }} resources: {{- toYaml . | nindent 12 }} diff --git a/charts/pyxis/values.schema.json b/charts/pyxis/values.schema.json index 2de843c..ee7a03c 100644 --- a/charts/pyxis/values.schema.json +++ b/charts/pyxis/values.schema.json @@ -105,10 +105,13 @@ "gpu": { "type": "object", "additionalProperties": false, - "required": ["mode", "resource", "renderNode", "hostPath"], + "required": ["mode", "resource", "runtimeClassName", "nvidiaResource", "nvidiaCount", "renderNode", "hostPath"], "properties": { - "mode": { "type": "string", "enum": ["none", "devicePlugin", "hostPath"] }, + "mode": { "type": "string", "enum": ["none", "devicePlugin", "hostPath", "nvidia"] }, "resource": { "type": "string", "minLength": 1 }, + "runtimeClassName": { "type": "string", "minLength": 1 }, + "nvidiaResource": { "type": "string", "minLength": 1 }, + "nvidiaCount": { "type": "integer", "minimum": 1 }, "renderNode": { "$ref": "#/$defs/absolutePath" }, "hostPath": { "$ref": "#/$defs/absolutePath" } } @@ -232,7 +235,7 @@ "$defs": { "absolutePath": { "type": "string", "pattern": "^/" }, "stringMap": { "type": "object", "additionalProperties": { "type": "string" } }, - "prefer": { "type": "string", "enum": ["Software", "Vaapi"] }, + "prefer": { "type": "string", "enum": ["Software", "Vaapi", "Nvenc"] }, "resources": { "type": "object", "additionalProperties": false, diff --git a/charts/pyxis/values.yaml b/charts/pyxis/values.yaml index 2b97ac8..736c38a 100644 --- a/charts/pyxis/values.yaml +++ b/charts/pyxis/values.yaml @@ -74,16 +74,23 @@ app: publicOrigin: "" # X-Forwarded-* を信じる前段の網の一覧 (10.42.0.0/16 など)。Ingress のコントローラの Pod がいる網を書く knownNetworks: [] - # 録画をあとからエンコードするときの変換器。Software か Vaapi + # 録画をあとからエンコードするときの変換器。Software、Vaapi、Nvenc のどれか encodingsPrefer: Software - # ライブと録画再生をその場で変換するときの変換器。Software か Vaapi + # ライブと録画再生をその場で変換するときの変換器。Software、Vaapi、Nvenc のどれか transcodingPrefer: Software gpu: - # GPU の渡し方。none、devicePlugin (Intel の device plugin)、hostPath (/dev/dri を渡し、app を特権にする) + # GPU の渡し方。none、devicePlugin (Intel の device plugin)、hostPath (/dev/dri を渡し、app を特権にする)、 + # nvidia (NVIDIA Container Toolkit と device plugin。Nvenc で使う。ホストのドライバは 530.41.03 以上) mode: none # devicePlugin のときに要求する資源の名前 resource: gpu.intel.com/i915 - # VAAPI で使う GPU の描画ノード + # nvidia のときに app に付ける RuntimeClass の名前 + runtimeClassName: nvidia + # nvidia のときに要求する資源の名前 + nvidiaResource: nvidia.com/gpu + # nvidia のときに要求する GPU の数 + nvidiaCount: 1 + # VAAPI (devicePlugin と hostPath) で使う GPU の描画ノード。nvidia では使わない renderNode: /dev/dri/renderD128 # hostPath のときにホストから渡す装置のディレクトリ hostPath: /dev/dri @@ -94,7 +101,7 @@ app: extraEnv: [] # app だけに当てる nodeSelector。空なら上の nodeSelector を使う nodeSelector: {} - # app の resources。devicePlugin のときは GPU の資源をチャートが足す + # app の resources。devicePlugin と nvidia のときは GPU の資源をチャートが足す resources: {} postgres: diff --git a/examples/gpu-nvidia.yml b/examples/gpu-nvidia.yml new file mode 100644 index 0000000..63d1d55 --- /dev/null +++ b/examples/gpu-nvidia.yml @@ -0,0 +1,14 @@ +# NVIDIA の GPU (NVENC) を app に渡す。ホストに NVIDIA Container Toolkit と 530.41.03 以上のドライバが要る。 +# ドライバのライブラリはランタイムがホストから差し込む。video が無いと libnvidia-encode が入らない。 +# 渡しただけでは変換はソフトウェアのままなので、.env で CARINA_ENCODINGS_PREFER と CARINA_TRANSCODING_PREFER を Nvenc にする +services: + app: + environment: + NVIDIA_DRIVER_CAPABILITIES: video,compute,utility + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu, video]