Creating a Docker Image for your ZED Application

Open in ClaudeOpen in ChatGPT

This is the recommended workflow for creating your own Docker image for your application:

  1. Write a Dockerfile for your application.
  2. Build the image with the docker build command.
  3. Host your Docker image on a registry.
  4. Pull and run the image on the target machine.

Write the Dockerfile

Docker builds images automatically by reading the instructions in a Dockerfile: a text file that contains all the commands needed to assemble a given image.

In the following example, we will build and run the Hello ZED tutorial application in a container.

First, let’s prepare the host with the source code:

$git clone https://github.com/stereolabs/zed-sdk.git
$cd zed-sdk/tutorials/tutorial\ 1\ -\ hello\ ZED/

Open a text editor and create a new Dockerfile with the following content:

1# Specify the parent image from which we build
2FROM stereolabs/zed:5.4-devel-cuda12.8-ubuntu22.04
3
4# Set the working directory
5WORKDIR /app
6
7# Copy files from your host to your current working directory
8COPY cpp hello_zed_src
9
10# Build the application with CMake
11RUN mkdir /app/hello_zed_src/build && cd /app/hello_zed_src/build && \
12 cmake -DCMAKE_LIBRARY_PATH=/usr/local/cuda/lib64/stubs \
13 -DCMAKE_CXX_FLAGS="-Wl,--allow-shlib-undefined" .. && \
14 make
15
16# Run the application
17CMD ["/app/hello_zed_src/build/ZED_Tutorial_1"]

We pass a few extra arguments to CMake so that CMake and GCC can find all the required CUDA libraries. We also tell the linker to allow linking even when there are undefined symbols from libraries such as nvcuvid, which are not yet available at build time. These libraries are provided at runtime by the NVIDIA® Container Toolkit.

For more information on writing Dockerfiles, see the Dockerfile reference documentation.

Build your Docker Image

Now that you have created a Dockerfile, it’s time to build your image with the docker build command.

$docker build -t hellozed:v1 .

Tip: On NVIDIA® Jetson™, we recommend building your Jetson™ Docker image on an x86 host and running it on the target device to avoid long compilation times on boards such as the NVIDIA® Jetson™ Orin™ Nano.

Test the Image

Let’s start a container from the image we just created using the docker run command.

$docker run -it --gpus all -e NVIDIA_DRIVER_CAPABILITIES=all --privileged -v /dev:/dev hellozed:v1

On NVIDIA® Jetson™ or with older Docker versions, use these arguments instead:

$docker run -it --runtime nvidia --privileged -v /dev:/dev hellozed:v1

If you use a ZED X or ZED X One camera, you need a few extra shared volumes:

$docker run -it --runtime nvidia --privileged -v /dev:/dev -v /tmp:/tmp -v /etc/systemd/system/zed_x_daemon.service:/etc/systemd/system/zed_x_daemon.service -v /var/nvidia/nvcam/settings/:/var/nvidia/nvcam/settings/ hellozed:v1

You should now see the output in your terminal:

$Hello! This is my serial number: 23468248

When running a Docker image on an NVIDIA® Jetson™ device, make sure the L4T (Linux for Tegra) version of your host system matches the L4T version of the container you are using.

Volumes

When running a Docker image for ZED cameras, a few volumes should be shared with the host.

  • [required] /dev:/dev: required to share the video devices.
  • [optional] /usr/local/zed/resources:/usr/local/zed/resources: if you plan to use the AI module of the ZED SDK (Object Detection, Body Tracking, NEURAL depth), we recommend bind-mounting a folder to avoid downloading and optimizing the AI models every time the container is restarted. The first time you use an AI model inside the container, it is downloaded and optimized into the bind-mounted folder, then reused on subsequent runs.
  • For GMSL2 cameras (ZED X, ZED X One):
    • [required] /tmp:/tmp
    • [required] /var/nvidia/nvcam/settings/:/var/nvidia/nvcam/settings/
    • [required] /etc/systemd/system/zed_x_daemon.service:/etc/systemd/system/zed_x_daemon.service

Optimize your Image Size

Docker images can grow very large and become a problem when pulling over the network or pushing to devices with limited storage (such as the NVIDIA® Jetson™ Orin™ Nano). Here are a few tips to keep your image size down:

  • Minimize the number of RUN commands. Each command adds a layer to the image, so consolidating RUN instructions reduces the number of layers in the final image. Note that layers are reusable and are not pushed or pulled if they did not change.
  • Use --no-install-recommends when installing packages with apt-get install to skip optional packages and save disk space.
  • Remove tarballs and other archive files that were copied during installation. Each layer is stacked on top of the previous ones, so files that are not removed within a given RUN step remain in the final image even if they are deleted in a later RUN step.
  • Similarly, clean the package lists downloaded by apt-get update by removing /var/lib/apt/lists/* in the same RUN step.
  • Create separate images for development and production. Production images should not include all of the libraries and dependencies pulled in by the build.
  • Use multi-stage builds and push only your prod image.
$RUN apt-get update -y && \
> apt-get autoremove -y && \
> apt-get install --no-install-recommends lsb-release && \
> tar -xvf archive.tar.gz && \
> rm -rf /var/lib/apt/lists/* && \
> rm -rf archive.tar.gz

Host your Docker Image

Now that you have created your image, you need to share it on a registry so it can be downloaded and run on any destination machine. A registry is a stateless, server-side application that stores Docker images and lets you distribute them.

Use the Docker Hub Registry

By default, Docker provides an official free-to-use registry, Docker Hub, where you can push and pull your images. For example, at StereoLabs the ZED SDK Docker images are built automatically from the zed-docker GitHub repository and pushed to the StereoLabs Docker Hub repository.

There are situations where you do not want your image to be publicly available. In that case, you can create your own private Docker registry. You can get private repositories from Docker, or from many other third-party providers.

Use a Local Registry Server

For local development, if your host and target machines are on the same network, you can set up a local registry server and push your images there.

For more information on deploying your own registry server, refer to the Docker Registry documentation.

Save and Load Images as Files

Lastly, you can also export and load your Docker image as a file.

To export a Docker image, simply use:

$# Saving can take some time depending on the image size
$docker save hellozed:v1 -o hellozed_v1.tar

On the destination machine, load the Docker image with:

$docker load -i hellozed_v1.tar
$
$cc967c529ced: Loading layer [==================================================>] 65.57MB/65.57MB
$2c6ac8e5063e: Loading layer [==================================================>] 991.2kB/991.2kB
$6c01b5a53aac: Loading layer [==================================================>] 15.87kB/15.87kB
$e0b3afb09dc3: Loading layer [==================================================>] 3.072kB/3.072kB
$37b9a4b22186: Loading layer [==================================================>] 17.1MB/17.1MB
$dd841c774a30: Loading layer [==================================================>] 29.22MB/29.22MB
$52ad947270f1: Loading layer [==================================================>] 3.072kB/3.072kB
$4e3516398cef: Loading layer [==================================================>] 793.6MB/793.6MB
$582ab80c9f26: Loading layer [==================================================>] 1.394GB/1.394GB
$85fd2f8b4dc8: Loading layer [==================================================>] 3.727GB/3.727GB
$d5bd3dceedb5: Loading layer [==================================================>] 222.1MB/222.1MB
$f6b7ec875383: Loading layer [==================================================>] 2.048kB/2.048kB
$eef68a3e44c4: Loading layer [==================================================>] 11.78kB/11.78kB
$2b29f57c8c23: Loading layer [==================================================>] 930.3kB/930.3kB
$Loaded image: hellozed:v1