From afd4793dd74a1e34c521391380606e31fa64e8e9 Mon Sep 17 00:00:00 2001 From: Shreejit C Date: Fri, 26 Jun 2026 00:07:54 +0530 Subject: [PATCH] Add guide for running NILRT in containers Add docs/source/nilrt_containers/nilrt_containers.rst, a tutorial for building and running NILRT as an OCI/Docker container image, and link it into the Tutorials toctree in index.rst. The guide covers an overview of the runmode and slim container variants and their intended use, the loss of real-time determinism when running on the host kernel, why driver installation is not sensible in a container, prerequisites for building and running, building the images and loading the artifacts, creating the macvlan network and launching containers with the docker/ helper scripts, installing LabVIEW RT and the VeriStand engine via opkg, configurable run options (network, storage, memory, CPU, etc.), and supported host operating systems. Signed-off-by: Shreejit C --- docs/source/index.rst | 1 + .../nilrt_containers/nilrt_containers.rst | 413 ++++++++++++++++++ 2 files changed, 414 insertions(+) create mode 100644 docs/source/nilrt_containers/nilrt_containers.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index fbf7040..1aa6834 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -18,6 +18,7 @@ NI Linux Real-Time Documentation and Tutorials opkg/opkg_tutorials_index opkg-keyrings/opkg-keyrings_index docker/docker + nilrt_containers/nilrt_containers troubleshooting/troubleshooting_index system_replication/system_replication eapol/eapol diff --git a/docs/source/nilrt_containers/nilrt_containers.rst b/docs/source/nilrt_containers/nilrt_containers.rst new file mode 100644 index 0000000..bf36c7b --- /dev/null +++ b/docs/source/nilrt_containers/nilrt_containers.rst @@ -0,0 +1,413 @@ +================================================== +Running NI Linux Real-Time in Containers +================================================== + +.. contents:: Table of Contents + :depth: 2 + :local: + +Overview +======== + +NI Linux Real-Time (NILRT) can be built and run as an OCI/Docker +container image. Instead of running NILRT on dedicated NI hardware, a +container image packages the NILRT runmode userspace -- including SSH, +the NI System Web Server, mDNS-based discovery, and the ``opkg`` package +manager -- so that it runs as a container on a regular Linux host. + +Two container image variants are produced from the +`nilrt `_ build project: + +* **nilrt-runmode-container** -- the full Base System Image, including + DKMS and the proprietary NI software stack. +* **nilrt-slim-container** -- a minimal Base System Image with just the + core runmode userspace: no desktop packages and none of the + proprietary NI software. It is smaller and faster to start; install + only the NI software you need via ``opkg``. + +The images are managed with helper scripts in the ``docker/`` directory +of the nilrt project: + +* ``docker/create-build-nilrt.sh`` -- builds the pyrex build container. +* ``docker/setup-nilrt-network.sh`` -- creates a macvlan network so + containers get their own IP addresses on the LAN. +* ``docker/nilrt-ctr.sh`` -- launches and manages NILRT containers. +* ``docker/docker-compose.yml`` -- the Compose definition used by + ``nilrt-ctr.sh``. + +What the Containers Are For +=========================== + +NILRT containers are intended for development, testing, and continuous +integration workflows where running on real hardware is inconvenient or +unavailable. Typical use cases include: + +* Spinning up many NILRT systems quickly -- for example, scaling out + tens of targets for software-deployment or discovery testing. +* Validating package installs, feed configuration, and ``opkg`` + workflows without reflashing hardware. +* Exercising NI MAX and VeriStand deployment flows against a + discoverable, networked NILRT system. +* Reproducible CI environments that exercise NILRT userspace software. + +.. warning:: + + NILRT containers are **not** a replacement for real-time hardware in + production. They are a development and test convenience. See + `Real-Time Behavior and the Host Kernel`_ below. + +Real-Time Behavior and the Host Kernel +====================================== + +A container is **not** a virtual machine. All containers on a host share +that host's single Linux kernel; the container image provides only the +userspace. This has an important consequence for NILRT: + +.. warning:: + + A NILRT container runs on the **host's** kernel, not the NILRT + ``PREEMPT_RT`` real-time kernel. The deterministic, low-latency + scheduling that defines the "RT" in NI Linux Real-Time comes from + that kernel. When NILRT userspace runs in a container on a + general-purpose host kernel, real-time determinism is **lost or + significantly degraded**. + +Practically, this means: + +* Even though the NILRT runmode image installs a NILRT kernel into its + root filesystem, that kernel is **not** the one running -- the host + kernel is. The bundled kernel and modules are inert. +* Latency and jitter depend entirely on the host kernel's configuration. + A stock desktop/server kernel makes no real-time guarantees. +* Do not use container measurements to characterize real-time + performance of NI hardware. + +If you need genuine real-time behavior, run NILRT on supported NI +hardware (or, at minimum, on a host running a ``PREEMPT_RT`` kernel, +which still does not replicate NI hardware behavior). + +Drivers in Containers +===================== + +Installing NI hardware drivers inside a NILRT container is **not +sensible** and is not supported. + +* Kernel-mode drivers must match the **running** kernel. Because the + container uses the host kernel (not the NILRT kernel in the image), + NILRT kernel modules will not load. +* The container has no access to the physical NI devices, buses, and + FPGA/board resources that those drivers manage. +* To keep dependent packages installable without pulling in + driver/kernel components that would fail in a container, the container + images inject placeholder ``opkg`` status entries for low-level + driver packages (for example ``ni-dim`` and ``ni-mdbg``). This + satisfies dependency constraints so that higher-level software + installs, but it does **not** provide working drivers. + +In short: use containers for userspace software (LabVIEW RT, VeriStand +engine, web services, package workflows), not for hardware I/O. + +Prerequisites +============= + +Building the images +------------------- + +To **build** the container images you need the standard NILRT build +environment described in the `nilrt README +`_: + +* A Linux build host (NI builds and tests on Ubuntu). +* The Docker engine (the bare engine, **not** Docker Desktop). +* The nilrt project source and submodules checked out, the + ``build-nilrt`` pyrex image built, and ``ni-oe-init-build-env`` + sourced. +* ``MACHINE=x64`` exported (containers are intended for x64 hosts). +* The core package feed and package index built first + (``packagefeed-ni-core`` and ``package-index``), as for any other + image. + +Running the images +------------------- + +To **run** the container images, on the host that will run them: + +* A container runtime: **Docker** (with the Compose plugin) or + **podman**. +* ``python3`` (the helper scripts use it for IP math and network + inspection). +* For LAN-visible containers via macvlan: root/``sudo`` access and an + interface in promiscuous mode (the setup script handles this). In VMs + (for example VirtualBox/VMware) the host NIC must allow promiscuous + mode. +* The containers run as ``--privileged`` (required by the NILRT init, + ``niauth``, bind-mounts, and ``setcap`` in the post-install), so the + host must permit that. + +Building the Containers +======================= + +After completing the build-environment setup and building the core feed +and package index, build the image recipes with bitbake: + +.. code:: bash + + export MACHINE=x64 + + # build the full runmode container image... + bitbake nilrt-runmode-container + + # ...and/or the slim variant + bitbake nilrt-slim-container + +The build emits OCI and docker-archive artifacts under +``$BUILDDIR/tmp-glibc/deploy/images/x64/``. The ``*.docker.tar`` archive +can be loaded directly into Docker: + +.. code:: bash + + cd $BUILDDIR/tmp-glibc/deploy/images/x64/ + + # full image + docker load -i nilrt-runmode-container-x64.docker.tar + # slim image + docker load -i nilrt-slim-container-x64.docker.tar + + # verify the images are present; note the version tag + docker images nilrt-runmode-container + docker images nilrt-slim-container + +The images are tagged ``nilrt-runmode-container:`` and +``nilrt-slim-container:-slim``. The ``nilrt-ctr.sh`` +helper auto-detects the newest locally-available tag, or you can pin one +with the ``NILRT_VERSION`` environment variable. + +For podman, load the archive with: + +.. code:: bash + + podman load -i nilrt-runmode-container-x64.docker.tar + +Running the Containers +====================== + +Create the container network (once) +----------------------------------- + +Containers attach to an external macvlan network named ``nilrt-net``, +which gives each container its own IP address on your physical LAN so +that remote hosts and NI MAX can discover them. Create it once with: + +.. code:: bash + + # auto-detect interface, subnet, and gateway + bash docker/setup-nilrt-network.sh + + # ...or specify everything explicitly, reserving a range for containers + bash docker/setup-nilrt-network.sh -i eth0 -s 192.0.2.0/24 \ + -g 192.0.2.1 -r 192.0.2.64/26 + + # podman users + bash docker/setup-nilrt-network.sh --runtime podman + +Reserving an IP range (``-r/--ip-range``) for containers avoids DHCP +conflicts -- coordinate the range with your network administrator. The +script also sets up a ``nilrt-shim`` interface so the **host** can reach +containers on the macvlan network (macvlan otherwise blocks +host-to-container traffic). Use ``--dry-run`` to preview the commands +without applying them. + +Launch containers +----------------- + +Use ``nilrt-ctr.sh run``, which scans the LAN for free addresses and +pins a collision-free IP to each container. Containers are named +sequentially (``nilrt-1``, ``nilrt-2``, ``nilrt-slim-1``, ...): + +.. code:: bash + + # launch one full runmode container + bash docker/nilrt-ctr.sh run nilrt + + # launch three slim containers + bash docker/nilrt-ctr.sh run nilrt-slim -n 3 + + # restrict allocation to a CIDR, or skip the (slow) LAN scan + bash docker/nilrt-ctr.sh run nilrt -r 192.0.2.64/26 + bash docker/nilrt-ctr.sh run nilrt --no-scan + bash docker/nilrt-ctr.sh run nilrt --dry-run + +For **podman**, assign a free address yourself with an explicit +``--ip`` (the ``nilrt-ctr.sh run`` helper is Docker/Compose-specific): + +.. code:: bash + + podman run -it --privileged --network=nilrt-net --ip 192.0.2.65 \ + nilrt-runmode-container:TAG + +Manage running containers +------------------------- + +``nilrt-ctr.sh`` provides convenience commands. A target can be a +container name, an ID prefix, or a managed index: + +.. code:: bash + + bash docker/nilrt-ctr.sh status nilrt-1 # show a summary + bash docker/nilrt-ctr.sh shell nilrt-1 # interactive shell + bash docker/nilrt-ctr.sh set-feed all 2026Q2 # set the opkg feed + bash docker/nilrt-ctr.sh change-hostname nilrt-1 cRIO-test + +Standard runtime commands also work, filtered to NILRT-managed +containers: + +.. code:: bash + + docker ps -a --filter label=nilrt.managed=true + docker logs CONTAINER + docker exec -it CONTAINER /bin/bash + +Installing LabVIEW and VeriStand +================================ + +LabVIEW Real-Time and the VeriStand engine are installed inside a +running container with ``opkg``, the same package manager used on NILRT +hardware. First point the container at a package feed for the desired +release quarter, then install the packages. + +Using ``nilrt-ctr.sh``: + +.. code:: bash + + # point the container's opkg at a feed (YYYYQN, e.g. 2026Q2) + bash docker/nilrt-ctr.sh set-feed nilrt-1 2026Q2 + + # install LabVIEW Real-Time + bash docker/nilrt-ctr.sh install nilrt-1 --feed 2026Q2 \ + ni-labview-realtime + + # install the VeriStand engine + bash docker/nilrt-ctr.sh install nilrt-1 --feed 2026Q2 \ + ni-veristand-engine + +Equivalently, from a shell inside the container: + +.. code:: bash + + bash docker/nilrt-ctr.sh shell nilrt-1 + + # inside the container: + opkg update + opkg install ni-labview-realtime + opkg install ni-veristand-engine + +.. note:: + + On hardware, installing an RT application package causes a reboot so + that the LabVIEW RT engine (``lvrt``) re-reads its startup + application. Containers are not rebooted, so the images ship an + ``opkg`` wrapper that restarts ``lvrt`` automatically after a + successful install or upgrade of an RT-relevant package + (``ni-labview-realtime*``, ``ni-veristand-engine*``). The restart is + skipped while ``lvrt`` is actively serving an application, so running + deployments are not interrupted. + +Once installed, the container is discoverable by NI MAX and VeriStand +(via mDNS and the NI System Web Server) at the container's LAN IP, and +applications such as the VeriStand engine can be deployed to it over +the network. + +.. warning:: + + Because the container runs on the host kernel (see `Real-Time + Behavior and the Host Kernel`_), LabVIEW RT and VeriStand run + **without** real-time determinism. This is suitable for functional + and integration testing, not for real-time performance validation. + +Configurable Run Options +======================== + +Container behavior is driven by ``docker/docker-compose.yml`` and the +environment variables consumed by the helper scripts. The most useful +knobs: + +.. list-table:: + :header-rows: 1 + :widths: 22 38 40 + + * - Option + - How to set it + - Notes + * - Image variant + - ``run nilrt`` vs ``run nilrt-slim`` + - Full runmode vs slim image. + * - Image version/tag + - ``NILRT_VERSION=`` env var + - Defaults to the newest locally-loaded tag. + * - Number of containers + - ``-n/--count N`` on ``run`` + - Launches N collision-free instances. + * - Network name + - ``NILRT_NETWORK`` env var (default ``nilrt-net``) + - Must be an existing external macvlan network. + * - IP address / range + - ``NILRT_IP`` (per container); ``-r/--ip-range`` on + ``run``/network setup + - ``run`` pins a verified-free IP; podman uses ``--ip``. + * - LAN scan tuning + - ``NILRT_SCAN=0`` (disable), ``NILRT_SCAN_TIMEOUT=`` + - Controls the free-IP probe before launch. + * - Hostname + - ``nilrt-ctr.sh change-hostname `` + - Also re-derives the NI serial number. + * - Package feed + - ``nilrt-ctr.sh set-feed `` + - Writes ``/etc/opkg/base-feeds.conf``. + +Because the containers are launched through Docker Compose, you can +constrain host resources (CPU, memory, storage, devices, extra volumes) +by editing ``docker/docker-compose.yml`` or adding a Compose override. +For example, to limit CPU and memory and add a persistent volume, add to +the relevant service: + +.. code:: yaml + + services: + nilrt: + cpus: "2.0" # max 2 CPU cores + cpuset: "0-1" # pin to specific cores (optional) + mem_limit: "4g" # max 4 GiB RAM + memswap_limit: "4g" # cap swap as well + shm_size: "1g" # /dev/shm size + storage_opt: + size: "20G" # writable-layer size cap (driver-dependent) + volumes: + - /host/path:/c # persist deployed apps/data across restarts + +When running directly with ``docker run`` or ``podman run``, the +equivalent flags are ``--cpus``, ``--cpuset-cpus``, ``--memory``, +``--memory-swap``, ``--shm-size``, ``--storage-opt size=``, and +``-v/--volume``. + +.. warning:: + + The NILRT init requires ``--privileged``. Dropping it will break + ``niauth``, the web server, and the bind-mounts. + +Supported Host Operating Systems +================================ + +The container images are **x64 Linux** images and are intended to run on +a **Linux host** with a native container runtime: + +* **Docker engine** (not Docker Desktop) with the Compose plugin, or + **podman**. +* NI builds and validates on **Ubuntu**; other modern Linux + distributions with a current Docker/podman should work. +* macvlan networking (used for LAN-visible container IPs) is a Linux + feature; it is not available on Docker Desktop for macOS/Windows, so + the LAN-discovery workflow described here is Linux-only. Running the + image without macvlan (for example with default bridge networking) is + possible but loses direct LAN discoverability by NI MAX/VeriStand. +* When the host is itself a VM, enable nested promiscuous mode on the + VM's NIC for macvlan to work.