Deploy with the Operator#

The Holoscan for Media operator for VSR NIM manages the VSR NIM media function through a Kubernetes custom resource.

Use the operator when you want a CR-driven deployment model that reconciles the VSR NIM deployment, ConfigMaps, SDP data, Rivermax configuration, Multus networking, and NMOS settings.

What the Operator Creates#

When you apply a NvidiaVsrNimMediaFunction custom resource, the operator creates and manages the following components:

Component

Description

Deployment

Runs the VSR NIM media function container with GPU, Multus networking, Rivermax, NMOS, and ST 2110 configuration.

<cr-name>-config ConfigMap

Contains config.json, input.sdp, and output.sdp consumed by the VSR service.

<cr-name>-sdp ConfigMap

Exposes generated SDP payloads by endpoint name for inspection and downstream tooling.

Status updates

Tracks provisioning, configuration, NMOS registration, NMOS connection state, and managed resources.

The operator manages only the VSR NIM media function. Source and receiver endpoints must be provided by existing ST 2110 equipment, platform services, or the sample Helm chart with its VSR service disabled.

Provide Source and Receiver Endpoints#

The operator does not create a test-pattern source or output-file receiver. Use existing ST 2110/NMOS equipment, platform services, or the packaged sample chart for the endpoints around the operator-managed VSR NIM pod.

For local validation with the sample chart, complete the operator installation workflow to create the operator-managed VSR NIM deployment. After the NvidiaVsrNimMediaFunction CR creates the VSR NIM pod, deploy the sample receiver from the sample chart archive in the same namespace as the custom resource. The following sample chart command intentionally disables its own VSR service and sample sender. Set NAMESPACE, SECRET_NAME, and NODE_HOSTNAME for your cluster before running the command:

helm upgrade --install vsr-nim-io \
  nvidia-vsr-nim-h4m-sample-1.0.10.tgz \
  -n "${NAMESPACE}" \
  --create-namespace \
  --set nvidia-vsr-nim-h4m-service.enabled=false \
  --set receiver.enabled=true \
  --set sender.enabled=false \
  --set receiver.image.secret="${SECRET_NAME}" \
  --set receiver.nodeSelector.hostname="${NODE_HOSTNAME}"

Wait for the sample receiver and the CR-created VSR NIM pod to be ready, and then enable the sample sender:

helm upgrade --install vsr-nim-io \
  nvidia-vsr-nim-h4m-sample-1.0.10.tgz \
  -n "${NAMESPACE}" \
  --reuse-values \
  --set sender.enabled=true \
  --set nvidia-vsr-nim-h4m-service.enabled=false \
  --set sender.image.secret="${SECRET_NAME}" \
  --set receiver.image.secret="${SECRET_NAME}" \
  --set sender.nodeSelector.hostname="${NODE_HOSTNAME}" \
  --set receiver.nodeSelector.hostname="${NODE_HOSTNAME}"

If the cluster does not run topo-aware-scheduler, add --set h4m.schedulerName="" to both sample chart commands. For static ST 2110 validation, pass the sample chart values-st2110.yaml overlay and keep the sample chart transport values aligned with the operator CR.

In NMOS mode, enabling the sample sender does not start media flow by itself. Use the NMOS controller to connect the sample sender to the operator-managed VSR input, and then connect the VSR output to the sample receiver.

Pull the Operator Chart#

ngc config set
ngc registry chart pull nim/nvidia/nvidia-vsr-nim-h4m-operator:1.0.10

Install the Operator#

helm upgrade --install vsr-nim-operator \
  nvidia-vsr-nim-h4m-operator-1.0.10.tgz \
  -n <operator-namespace> \
  --create-namespace

If the operator image requires a pull secret, set it in the operator chart values:

helm upgrade --install vsr-nim-operator \
  nvidia-vsr-nim-h4m-operator-1.0.10.tgz \
  -n <operator-namespace> \
  --create-namespace \
  --set imagePullSecrets[0].name=<secret-name>

If generated media function pods should use a default pull secret when the CR omits spec.parameters.imagePullSecrets, set it in the operator chart values:

helm upgrade --install vsr-nim-operator \
  nvidia-vsr-nim-h4m-operator-1.0.10.tgz \
  -n <operator-namespace> \
  --create-namespace \
  --set mediaFunction.imagePullSecrets[0].name=<secret-name>

The pull secret for the operator image and the pull secret for generated VSR NIM media function pods are separate settings. A CR-level spec.parameters.imagePullSecrets value overrides the chart-level media function default for that CR.

Wait for the operator:

kubectl rollout status deployment \
  -n <operator-namespace> \
  -l app.kubernetes.io/instance=vsr-nim-operator \
  --timeout=180s

Create a Media Function#

Create a NvidiaVsrNimMediaFunction custom resource. The CR defines:

  • One ST 2110-20 video input.

  • One ST 2110-20 video output.

  • NMOS or inline SDP control.

  • VSR processing parameters.

  • GPU, network, Rivermax, logging, security, resources, and scheduler settings.

Example CR for NMOS mode:

apiVersion: nvidia.com/v1alpha1
kind: NvidiaVsrNimMediaFunction
metadata:
  name: vsr-nim-nmos
  namespace: <namespace>
  labels:
    nvidia.com/holoscan-for-media.production: <production-name>
    nvidia.com/holoscan-for-media.pipeline: 720-to-4K
spec:
  schedulerName: topo-aware-scheduler
  nodeSelector:
    kubernetes.io/hostname: <gpu-node-name>
  inputs:
    video_input:
      control:
        nmos: {}
      transport:
        rtp: {}
      format:
        video:
          media_type: video/raw
          frame_width: 1280
          frame_height: 720
          frame_rate: "30"
          interlace_mode: progressive
          color_sampling: "YCbCr-4:2:2"
          component_depth: 10
          colorspace: BT709
          transfer_characteristic: SDR
      parameters:
        localInterfaceName: net1
        udp:
          headerSize: 20
          payloadSize: 800
          useRtpTimestamp: true
          ptpSrc: set
  outputs:
    video_output:
      control:
        nmos: {}
      transport:
        rtp: {}
      format:
        video:
          media_type: video/raw
          frame_width: 3840
          frame_height: 2160
          frame_rate: "30"
          interlace_mode: progressive
          color_sampling: "YCbCr-4:2:2"
          component_depth: 10
          colorspace: BT709
          transfer_characteristic: SDR
      parameters:
        localInterfaceName: net2
        udp:
          payloadSize: 1220
          packetsPerLine: 8
          outputQueueMaxBuffers: 0
          sync: false
          async: false
          passRtpTimestamp: true
          rtpTimestampOffset: 2000000
          ptpSrc: set
  parameters:
    nmosHttpPort: 8980
    nmosLabel: "VSR NIM"
    nmosDescription: "ST2110-20 video sender and receiver with 720p-to-4K upscaling"
    nmosDomain: local
    nmosSystemUrl: ""
    nmosSeed: vsr-nim-sample
    gstDebug: "2,nvdsnmosbin:8,nvnmos:2,nvdssdp*:8"
    gpuId: "0"
    glogVerbosity: "1"
    rivermaxTxAdaptiveSchedulingFactor: "1.005"
    rivermaxBurst: 4
    imagePullSecrets:
      - name: <secret-name>
    rivermaxLicenseSecret: rivermax-license
    highSpeedNetwork:
      - name: media-a-rx-net
      - name: media-a-tx-net
    vsr:
      srEnable: true
      hqsr: true
      srLevel: ultra
      denoiseEnable: false
      denoiseLevel: ultra
      deblurEnable: false
      deblurLevel: ultra
      noiseInjectEnable: false
    securityContext:
      runAsUser: 1000
      runAsGroup: 1000
      runAsNonRoot: true
      privileged: false
      allowPrivilegeEscalation: true
      capabilities:
        add:
          - IPC_LOCK
          - NET_RAW
          - SYS_NICE
          - DAC_READ_SEARCH
        drop:
          - ALL
    resources:
      limits:
        cpu: "4"
        memory: 8Gi
        hugepages-2Mi: 4Gi
        nvidia.com/gpu: "1"
      requests:
        cpu: "4"
        memory: 8Gi
        hugepages-2Mi: 4Gi
        nvidia.com/gpu: "1"

VSR NIM ST 2110 SDP generation supports SDR transfer characteristics in this release. Use transfer_characteristic: SDR.

The operator chart uses global.h4m.pipeline: "720-to-4K" as the default nvidia.com/holoscan-for-media.pipeline label for generated VSR NIM pods. To override labels for a specific media function, set these labels on the NvidiaVsrNimMediaFunction metadata:

metadata:
  labels:
    nvidia.com/holoscan-for-media.production: <production-name>
    nvidia.com/holoscan-for-media.pipeline: <pipeline-name>

Apply the CR:

kubectl apply -f vsr-nim-media-function.yaml

On Red Hat OpenShift, replace kubectl with oc.

High-Speed Network Resource Pools#

The operator configures Multus network attachments for ST 2110 media transport through spec.parameters.highSpeedNetwork.

If highSpeedNetwork is omitted, the operator uses the following values:

parameters:
  highSpeedNetwork:
    - name: media-a-rx-net
    - name: media-a-tx-net

The first attachment becomes the first secondary interface in the pod, typically net1, and the second attachment becomes net2. Keep spec.inputs.<name>.parameters.localInterfaceName and spec.outputs.<name>.parameters.localInterfaceName aligned with that order.

Set resourceName when the cluster exposes named SR-IOV device-plugin resources. If an attachment needs more than one virtual function, set resourceCount; it defaults to 1 when resourceName is present.

On clusters with single-numa-node topology requirements, configure highSpeedNetwork[].resourceName and resourceCount so the VSR pod can allocate the GPU, hugepages, and SR-IOV virtual functions from a compatible NUMA zone.

On clusters in which both VSR interfaces must use the same NUMA-local SR-IOV pool, list the same NetworkAttachmentDefinition twice and set the same device-plugin resource on each attachment:

spec:
  inputs:
    video_input:
      parameters:
        localInterfaceName: net1
  outputs:
    video_output:
      parameters:
        localInterfaceName: net2
  parameters:
    highSpeedNetwork:
      - name: media-b-rx-net
        resourceName: openshift.io/media_b_rx_pool
      - name: media-b-rx-net
        resourceName: openshift.io/media_b_rx_pool

The generated VSR pod still receives two in-pod interfaces. Use the repeated-entry form when you need two distinct interfaces. Use a single entry with resourceCount: 2 only when your media function and CNI setup intentionally use one in-pod interface:

spec:
  parameters:
    highSpeedNetwork:
      - name: media-b-rx-net
        resourceName: openshift.io/media_b_rx_pool
        resourceCount: 2

Do not collapse separate RX and TX pools into one logical resource unless the cluster exposes one shared pool. On single-numa-node clusters, hiding the resource split can cause scheduler or kubelet topology placement failures.

Verify#

Check the custom resource:

kubectl get nvidiavsrnimmediafunction -n <namespace>
kubectl describe nvidiavsrnimmediafunction <cr-name> -n <namespace>

Check the generated deployment:

kubectl rollout status deployment/<cr-name> -n <namespace> --timeout=180s
kubectl logs -n <namespace> -l app.kubernetes.io/instance=<cr-name> -f

Check operator logs:

kubectl logs -n <operator-namespace> \
  -l control-plane=controller-manager

Useful status fields include the following:

  • status.conditions

  • status.inputs.video_input.control

  • status.outputs.video_output.control

  • status.managed_resources

If the generated VSR NIM pod stays Pending, inspect pod events:

oc describe pod -n <namespace> -l app.kubernetes.io/instance=<cr-name>

Common causes include a missing NetworkAttachmentDefinition, an unavailable spec.schedulerName, insufficient GPU or hugepage capacity, unavailable SR-IOV device resources, or GPU and SR-IOV pool resources that cannot be placed on the same NUMA node.

Metrics and Health#

The operator chart can expose controller-runtime metrics and health endpoints for the operator controller. Media function metrics are separate. The VSR NIM media function image in this release does not currently expose /metrics; the media function metricsEnabled setting only adds Prometheus scrape annotations.

Operator Chart Settings#

The following are common operator chart settings:

Setting

Description

image.repository and image.tag

Operator controller image.

imagePullSecrets

Pull secrets for the operator controller image.

mediaFunction.image

Default VSR NIM image for generated media function pods.

mediaFunction.imagePullSecrets

Default pull secrets for generated media function pods when the CR omits spec.parameters.imagePullSecrets.

mediaFunction.schedulerName

Default scheduler for generated media function pods when the CR omits spec.schedulerName.

mediaFunctionImage

Backward-compatible alias for mediaFunction.image.

global.h4m.production and global.h4m.pipeline

Default Holoscan for Media labels for generated media function pods.

Per-CR fields such as spec.parameters.imagePullSecrets, spec.schedulerName, and Holoscan for Media metadata labels override the corresponding chart-level media function defaults.

Uninstall#

Delete the media function CR:

kubectl delete -f vsr-nim-media-function.yaml

Uninstall the operator:

helm uninstall vsr-nim-operator -n <operator-namespace>