Shared Memory
Media engines live in shared memory: uncompressed frames are large enough that the only sensible way to move them between processes is not to move them at all. Every Norsk instance’s media container therefore gets a /dev/shm — and it is always private to that instance. It is the engine’s own working memory, sized for that instance alone, and there is no mechanism to share it.
Sharing media between instances, or with another vendor’s software, is a real and supported arrangement — but it happens through a separate, operator-created mount, never through an instance’s own /dev/shm. Never the twain shall meet.
Between Norsk instances on one host there is a simpler route than a shared mount: put them in the same Norsk Domain, and they exchange frames zero-copy over the norsk-link.
Private by default — and always
Section titled “Private by default — and always”Each instance’s media container runs with its own /dev/shm. Two properties follow, and both are the point:
- Isolation. No instance can read, overwrite, or delete another instance’s in-flight media. A shared pool is also a shared budget — one process filling it makes every other process’s writes fail — so a private pool keeps one misbehaving instance’s blast radius to itself.
- Deliberate sizing. Docker’s own default
/dev/shmis 64MB, which no media workload survives; the host’s default tmpfs is typically half of RAM, which is far too much to hand a single container implicitly. A private pool has one owner, so its size can mean something.
Sizing
Section titled “Sizing”The effective size of an instance’s /dev/shm resolves through three levels, first match wins:
| Source | Set by |
|---|---|
--shm-size at launch (or the Launch form’s field) | You, per instance |
| The product template’s declared default | The product |
2gb | The runner’s fallback |
Docker syntax throughout (2gb, 512m). The instance detail view shows the resolved value. Docker cannot resize a running container’s /dev/shm, so size changes take effect at the next launch.
The Quadra exception
Section titled “The Quadra exception”NETINT’s driver for the Quadra keeps the card’s resource table and lock files at a hard-coded /dev/shm, and expects the host and every container using a card to share the one copy — that table is how sessions across processes coordinate load on the card. There is no setting to move it. So on the quadra hardware profile, and only there, the media container’s private /dev/shm is shadowed by a bind mount of the host’s: the same arrangement NETINT documents for containers, and the one the original studio-docker compose shipped.
What that costs is stated plainly: on a Quadra host an instance is not isolated in shared memory from the host or from other Quadra instances, and --shm-size does not govern — the host’s tmpfs does. The trade is the card’s, and it is confined to hosts that chose the card. The same profile maps every NETINT NVMe device the host carries (the card is driven through its /dev/nvmeXn1 block node, whose number the kernel assigns each boot) and refuses to launch if it finds none. Hardware Acceleration covers the profile itself — the probe, the device mapping, and the container user it needs.
Sharing media between systems: shared-memory mounts
Section titled “Sharing media between systems: shared-memory mounts”When an instance needs to exchange uncompressed media with something else on the same host — another Norsk instance, or another vendor’s MXL-capable system — the shared area is a dedicated tmpfs the host’s operator creates, mounted into the instance with --shared-memory:
norsk-ctl instance launch-template mixer \ --template my-product \ --shared-memory /mnt/mxlThe division of labour is deliberate:
- The host owns the mount. Creating a tmpfs needs root, exactly once per machine, and a mount owned by the host (a systemd mount unit) comes back on reboot before anyone’s containers start. Neither runtime’s restart cycle can take the shared area away from the other.
norsk-ctlmounts and verifies it. Each path is bind-mounted into the media container at the same path, and the launch refuses loudly unless the path exists, is a tmpfs, and is world-writable — because each of those failures otherwise degrades silently (a missing path becomes a root-owned plain directory; a plain directory becomes disk-backed “shared memory” that works, slowly).- The workflow decides what to exchange. The mount only makes the path visible; what reads and writes it is workflow configuration — for MXL, the ingest/egest components pointed at the domain path.
The option is repeatable, and multiple mounts are first-class: an instance bridging two domains mounts both — A ↔ B ↔ C without A and C ever seeing each other’s media. Interoperate with MXL or shared memory is the full walkthrough, including creating the mount and sizing it.
A product built around a shared domain can declare the conventional path as a template default (advanced.sharedMemory.default), pre-filling the launch form — the operator still owns creating the mount, and can override or decline at launch.
The trust model
Section titled “The trust model”A shared mount is a mutual-trust zone. Every participant can read every flow in it (the media itself, not just metadata), can corrupt or delete what others wrote, and draws from the same fixed budget — a full pool fails everyone’s writes. There are no per-member quotas inside a tmpfs.
So share the narrowest thing that works: one mount per group of systems that are allowed to see each other’s media, and separate mounts (not just separate subdirectories) for tenants that must not affect each other’s capacity. The instance’s own /dev/shm is never part of any such zone — that is the point of the split.