System designHow-to

PoE camera discovery in a Docker bridge: connect by IP

Why Docker bridge drops PoE camera broadcast discovery, and how to reserve a camera IP, connect by unicast or macvlan, and size packets for the stream.

LumaSpec Vision10 min read Share on LinkedIn

On this page 11 sections
  1. 01Why a bridge network hides your cameras
  2. 02What you need
  3. 03Step 1: Fix the camera's address before touching Docker
  4. 04Step 2: Choose macvlan or bridge by how the camera streams
  5. 05Step 3: Run the app on a macvlan network and keep discovery
  6. 06Step 4: Bridge fallback — connect by IP and skip discovery
  7. 07Worked example: packet size for a 12 MP camera through a 1500-byte bridge
  8. 08Verify the stream end to end
  9. 09Common mistakes and their fixes
  10. 10Where to go next
  11. 11Questions

Your camera list is empty the moment a container stops sharing the host's network stack, and the rest of your stack — a database, a message broker, a dashboard — needs the host stack left alone. The fix is not to fight over host mode. A Docker bridge network drops the UDP broadcast packets that camera discovery depends on, but it forwards unicast in both directions once a flow opens. Reserve the camera's address, connect to it by IP, and keep packet sizes inside the bridge's MTU, and a PoE camera runs like any other container. This guide gives you the address plan, the macvlan option, the bridge fallback, the packet-size arithmetic and the end-to-end checks.

Why a bridge network hides your cameras

A GigE Vision SDK finds cameras by sending a UDP broadcast to 255.255.255.255 on port 3956 and collecting each camera's reply. GenICam discovery runs on that subnet broadcast, which is why ping alone has never found a camera: GenICam discovery uses subnet broadcast: why ping is not enough. A bridge network translates the container behind the host and does not carry subnet broadcasts, so the question never reaches the camera LAN and the answers never come back. The same empty list with good ping shows up when a firewall passes ICMP but blocks broadcast, as in GigE Vision camera firewall: ping works, discovery fails.

What a bridge does carry is unicast. Open a TCP connection or a UDP flow to a known address and the translation handles packets in both directions for the life of the flow. That single fact is the whole strategy: give the camera a fixed address and open it directly instead of waiting for discovery. An Ethernet 3D camera in a Docker container hits the same split — discovery broken by the container, streaming fixed once the address path is right — and the steps below apply that logic to PoE cameras.

What you need

  • A host with two Ethernet interfaces: one for the office network, one dedicated to cameras. Vision controllers bundle those ports, and often PoE, in one box:
Specification MV-VC3301H-128G66 MV-VC5525-256G70-NN MV-VC2140-128G40-1T
CPU Intel® Core i3-8100 Intel® Core i5-12400 Intel® Processor N97
Memory 8 GB 32 GB 8 GB
Storage 128G SSD 256 GB SSD 128 GB SSD + 1 TB HDD
GPU Intel® HD Graphics 630 Intel® UHD Graphics 730 Intel® UHD Graphics
Operating system Windows 10 64-bit, Not activated Unactivated Windows 10 Unactivated 64-bit Windows 10 LTSC 21H2
Encryption method VM6200Pro license key – Not support
Video output HDMI interface × 1, VGA interface × 1; Supports independent display output at the same time; Max. resolution 1920 × 1080 @ 60 Hz HDMI interface × 1, VGA interface × 1; Supports independent display output at the same time; Max. resolution 1920 × 1080 @ 60 Hz HDMI interface × 1, VGA interface × 1; Supports independent display outputs at the same time; Max. resolution 1920 × 1080 @ 60 Hz
Digital I/O 8 digital isolated inputs supported; 16 opto-isolated outputs supported (NPN/PNP switchable) Opto-isolated input × 8; Opto-isolated output × 12 ( supports NPN/PNP switching), digital-isolated low-side driver output × 8; Non-isolated bi-directional differential I/O × 4 Opto-isolated input × 8; Opto-isolated output × 8
Network interface 6× Gigabit Ethernet ports GigE interface × 7, including interface for PoE × 4 GigE interface × 4
USB Interface USB 2.0 × 4; USB 3.0 × 4; Built-in USB 2.0 × 1 USB 2.0 × 4, USB 3.0 × 4, built-in USB 2.0 × 1 USB 2.0 × 2; USB 3.0 × 2
Serial Port 2× full-function RS-232, RS-485/RS-422 switchable RS-232 × 2 by default, supports switching to RS-485 and RS-422 RS-232 × 1, supports switching to RS-485 or RS-422
Light interface 4-channel 24 V constant-voltage light drive, Max. power per channel: 72 W, Max. power (4 channels): 150 W 24 VDC constant voltage × 8; (Max. power consumption of single channel is 72 W, total max. power consumption 190 W) Light interface with 24 VDC constant voltage × 4; (Brightness is adjustable. Max. current 3 A for single light interface, and total max. power consumption 80 W. Supports light mode switching between strobe and solid via external control)
Price $2,419.00 $4,479.00 · quoted $1,679.00

All 3 share: Certification CE, KC. Values as printed in each product's data sheet; open a part for its drawing and full specifications.

  • A PoE switch or injector on the camera LAN for cameras that draw power over the data cable. Cameras with a separate power lead do not need it.
  • Camera data cables sized to the run. The LS-CBL-0199 is a 3 m high-flex GigE lead for the bench; the LS-CBL-0117 RJ45 cable with locking stud covers a 15 m fixed run:
  • A reserved address for the camera, set in Step 1.
  • Docker on the host and your SDK's container image.

Step 1: Fix the camera's address before touching Docker

Skip discovery later and the camera needs an address that never changes.

  1. Reserve an address for the camera's MAC at the DHCP server, or set a static IP in the camera. Keep any static address outside the DHCP pool so the server never hands it to another device.
  2. Keep the camera in the subnet the host's camera interface uses: 192.168.10.0/24 with the camera at 192.168.10.42 in the examples below.
  3. Confirm from the host: ping 192.168.10.42. A reply in under 1 ms is normal on a switched LAN. No reply points to wiring, VLAN or PoE power; Docker is not involved yet.

A DHCP reservation beats a raw static IP because the camera keeps working from any host and the lease tells you the address. If a camera still reboots into an unknown address, finding a DHCP camera's IP after every reboot is the recovery path, and running one DHCP server for the camera LAN keeps the reservations authoritative.

Step 2: Choose macvlan or bridge by how the camera streams

Your software streams over Network to pick Why
UDP image packets (classic GigE Vision) macvlan The SDK tells the camera which address and port to send to; under a bridge that address is the container's private one, which the camera cannot reach
TCP or RTSP, opened by the client bridge An opened TCP flow translates like any web session; connect by IP and it works
SDK with a configurable stream destination bridge Point the destination at the host address and the mapped ports

If you cannot find a stream-destination setting in your SDK, assume UDP and pick macvlan. Reaching cameras on another subnet without broadcast shows the same rule on ordinary networks: unicast crosses, broadcast does not.

Step 3: Run the app on a macvlan network and keep discovery

A macvlan network pins the container to one physical interface and gives it its own address on that LAN, so broadcasts from the container behave exactly as they would from a second PC.

# example values: substitute your camera subnet, gateway and interface name
docker network create -d macvlan \
  --subnet=192.168.10.0/24 \
  --gateway=192.168.10.1 \
  --ip-range=192.168.10.224/27 \
  -o parent=enp3s0 \
  camnet

# .224/27 reserves a 32-address slice (.224-.255); keep it outside the DHCP pool
docker run -d --name inspect --network camnet --ip 192.168.10.230 your-app-image
  1. From a shell in the container, ping 192.168.10.42. It answers on the first try.
  2. Run your SDK's camera enumeration. The broadcast now leaves through the camera interface and the camera appears, discovery included.
  3. Start the stream at the packet size the worked example below computes.

One macvlan limit to know: the host cannot open connections to 192.168.10.230 by default, because the kernel blocks traffic between a parent interface and its macvlan children. Your container-to-camera direction is unaffected. If a host-side service must reach the container, attach a second ordinary bridge network to the same container and use it for that traffic.

On a controller such as the MV-VC5525-256G70-NN, with 5+ LAN ports, the camera interface is one dedicated port and the office LAN stays on another.

Step 4: Bridge fallback — connect by IP and skip discovery

When macvlan is not available — a managed host, a network plugin that owns the interface — a plain bridge still carries control traffic and TCP streams end to end.

services:
  inspect:
    image: your-app-image
    network_mode: bridge
    ports:
      - "5000:5000/tcp"   # example: only needed for inbound TCP the app serves

Then skip discovery on purpose. Most GenICam-based libraries offer an open-by-address path next to enumeration; pass the reserved address, 192.168.10.42 here, and the SDK opens a unicast control session to UDP port 3956 through the translation. TCP-style streams ride the opened connection and work. UDP GigE Vision streams do not: the SDK directs packets at its own container address, the camera cannot reach it, and the stream never starts. That failure is your signal to go back to Step 3.

Set the camera packet size to the bridge MTU, 1500 bytes by default, before the first stream. The arithmetic below shows what that costs and when it matters.

Worked example: packet size for a 12 MP camera through a 1500-byte bridge

Inputs and where each comes from:

  • Camera: the class of the LS-CMR-0053, a 12 MP GigE camera rated at 9 fps. At Mono 8 that is 12,000,000 pixels × 1 byte = 12 MB per frame.
  • Link: 1 Gbit/s switch port and NIC.
  • Bridge MTU: 1500 bytes, the Docker default.
  • Wire overhead: 38 bytes per frame — 8 preamble + 14 Ethernet header + 4 frame check + 12 inter-frame gap.

The rule in words: a link of rate R carries frames of wire size W at R ÷ (W × 8) packets per second, and usable pixel data is that packet rate times the payload left after 28 bytes of IP and UDP headers.

wire bytes per frame = packet size + 38 packets per second = link rate / (wire bytes × 8) pixel budget (bit/s) = packets per second × (packet size − 28) × 8 frame demand (bit/s) = pixels per frame × bytes per pixel × fps × 8

The arithmetic:

  • Frame demand: 12,000,000 bytes × 9 fps = 108 MB/s, × 8 = 864 Mbit/s.
  • Wire frame at 1500-byte packets: 1500 + 38 = 1538 bytes = 12,304 bits.
  • Packet rate: 1,000,000,000 ÷ 12,304 = 81,274 packets/s.
  • Pixel budget: 81,274 × 1472 × 8 = 957,082,624 ≈ 957 Mbit/s.
  • Headroom: 957 − 864 = 93 Mbit/s, about 10 percent of the link.

Decision: set the packet size to 1500 and this camera fits a 1 Gbit/s bridge with 93 Mbit/s spare — no MTU changes anywhere. The break-even sits at about 10 fps: each frame per second costs 96 Mbit/s (864 ÷ 9), and 957 ÷ 96 ≈ 10. Above it, raise MTU to 9000 end to end — switch ports, host NIC, and the Docker network at creation with -o com.docker.network.driver.mtu=9000 — then set packets to 9000, which lifts the budget to about 993 Mbit/s and the break-even to 10.3 fps. Past that, one camera fills a 1 Gbit/s port whatever the packet size: move to a 2.5 or 10 Gbit/s port, or cut the ROI or use binning.

Verify the stream end to end

  1. Frame rate at the application: command 9 fps and average over 100 delivered frames; expect 9, not 8.7. A shortfall means the path is dropping packets.
  2. MTU path from the container: ping with the do-not-fragment flag — ping -M do -s 1472 192.168.10.42 must succeed, since 1472 + 28 bytes of IP and ICMP headers make exactly 1500. On a jumbo path, ping -M do -s 8972 must succeed too.
  3. Buffer completeness over a 10-minute run: no incomplete-buffer errors. The lost-packet fix for buffers that arrive incompletely and the stream-timeout checklist for packets, buffers and MTU cover the failures a container path adds.
  4. Stability across hours: if the stream stalls, the watchdog-and-recovery pattern for PoE camera stream drops is the reference.

Frame rate held and buffers complete means the network is done; everything further is SDK tuning.

Common mistakes and their fixes

  • Jumbo packets through a 1500-byte bridge: torn images and incomplete buffers. Set the camera packet size to 1500, or raise MTU end to end as in the worked example.
  • Camera on unreserved DHCP: the address changes at the next power cycle and the container connects to a stale IP. Reserve first, always.
  • Waiting for discovery on a bridge: the empty list is the expected signature, not a fault. Open by address; if the stream then fails, use Step 3.
  • macvlan bound to the wrong parent: the -o parent= value must name the camera port, not the office port, or no camera ever appears.
  • Two devices sharing one macvlan address: intermittent loss that looks like cable trouble. Give each container its own slice as in Step 3. Duplicate PoE camera discovery caused by host interfaces and network camera discovery troubleshooting for multiple cameras cover the multi-camera forms.
  • PoE budget ignored: ports link while the switch cannot power every camera at boot. Add the cameras' draw and compare it with the switch budget before mounting.

Where to go next

Size the host around LAN port count and PoE before CPU: the system configurator walks camera, controller and extras in order. The rest of the work on broadcast, MTU and streaming sits on the systems topic page. If the container layout is the open question, contact the applications team with your camera list and service plan.

Questions

Does the camera need to be on the same subnet as the container?

With a macvlan network, yes: the container becomes a first-class LAN host, so the camera must sit in the same subnet and VLAN as the interface you attached. With a bridge, no: traffic leaves through the host's own address, so the container reaches any subnet the host routes, including one on a second interface. Either way, keep the camera LAN on its own subnet so office broadcast noise stays out.

Which ports does GigE Vision use, and do I need to map them?

Control and discovery ride GVCP on UDP port 3956; image packets ride GVSP on a port the SDK chooses at stream setup. On a macvlan network nothing needs mapping, because the container owns a real LAN address. On a bridge, outbound unicast flows need no mapping at all; only inbound TCP that a camera or client initiates must be published with a port mapping.

Why does the camera list stay empty even though ping works?

Ping is a unicast exchange to an address you already know, so it crosses a bridge like any other packet. Discovery is a UDP broadcast asking every camera on the subnet to identify itself, and the bridge never forwards it. An empty list with clean ping is the expected bridge signature, not a broken camera; a firewall that passes ICMP but drops broadcasts produces the identical pattern on bare metal.

Can one service keep host networking while the camera app does not?

Yes. Network mode is chosen per service, so a broker or database pinned to host mode places no constraint on the camera container. Give each service its own network setting in the same compose file, then test them separately: the host-mode service by its local port, the camera app by a unicast connect to the reserved address or by discovery inside the macvlan container.

How many cameras can one 1 Gbit/s camera port carry?

About 957 Mbit/s of pixel data is usable on a 1 Gbit/s link with 1500-byte packets. Divide that by each camera's demand: pixels times bytes per pixel times frame rate times eight. The 12 MP camera in the worked example takes 864 Mbit/s at 9 fps, so one camera fills the port; a 1 MP camera at 30 fps takes about 240 Mbit/s, so three fit with margin.