The OpenTAP team is frequently asked about deploying and running OpenTAP in one or more Docker containers. This blog addresses typical rationale for containerization, steps for implementation, and caveats to observe.
Why Containerize OpenTAP?
OpenTAP is a cross-platform test framework with a full CLI, facilitating headless execution in a container. The OpenTAP project supports containerization and already publishes Docker images for each release (see below).
Rationale for container-based deployment includes
Cloneable test stations: In a container, OpenTAP version, plugins, .NET runtime and settings are set in stone, ending test station-based drift and accompanying alignment issues.
CI/CD and regression: Test plans can run as pipeline jobs (GitHub Actions, GitLab CI, Jenkins) against simulated or real instruments.
Scale and orchestration: Using containers supports parallel runs, remote or lab-wide execution under Kubernetes or another scheduler/orchestrator.
Production parity: Developers run the same image(s) deployed on the factory floor.
Benefits of Containerization
There exist many benefits to container-based deployment of OpenTAP, from versioning to fast provisioning to isolation to auditability:
| Benefit | Use Case |
|---|---|
| Immutable, versioned environments | OpenTAP and plugin versions and settings are baked into Docker image tag; roll back by changing the tag |
| Fast provisioning | A new station or CI runner requires only docker pull -- no installer or manual plugin setup needed |
| Isolation | Conflicting plugin sets or .NET versions can coexist on one host |
| Small footprint | Slim runtime images omit SDK and compilers (the SDK can add up over 2.5 GBs to deployment images) |
| Auditability | The Dockerfile itself documents the exact station configuration for regulated or traceable testing |
A Stepwise Guide
You can build and deploy a containerized OpenTAP in just a few steps:
· Build a runtime container image.
· Run with parameters passed at run time.
· Export results before container terminate.
Build a Headless Runtime Image
You can use the official OpenTAP image or build your own over a .NET runtime. Building and customizing your own image is often safer and also lets you choose the latest component versions and/or legacy version that fit your particular configuration.
Create a Dockerfile
Following is a basic working template for creating an OpenTAP-specific Dockerfile.
# Install the latest version of dotnet from Microsoft
FROM mcr.microsoft.com/dotnet/runtime:9.0
RUN apt-get update && apt-get install -y --no-install-recommends curl unzip \
&& rm -rf /var/lib/apt/lists/*
# Install OpenTAP
RUN curl -Lo /tmp/opentap.zip \
'https://packages.opentap.io/4.0/Objects/Packages/OpenTAP?os=Linux&architecture=x64' \
&& unzip /tmp/opentap.zip -d /opt/tap && rm /tmp/opentap.zip \
&& chmod +x /opt/tap/tap
ENV PATH="/opt/tap:${PATH}"
# Install plugins – using “Demonstration” as example only
RUN tap package install "Demonstration" --version 9.x -y --non-interactive
# Add test plan and settings
COPY plans/ /opt/tap/plans/
COPY Settings/ /opt/tap/Settings/
WORKDIR /opt/tap
ENTRYPOINT ["tap", "run"]
CMD ["plans/MyPlan.TapPlan", "--non-interactive"]
Choose a working test plan
While it is possible to use a Docker deployment as a test plan development environment, you are better served by building and testing a test plan first with GUI-based test plan editor or in a separate command-line environment.
Accompanying this blog is a short example test plan to use as a starting point (see below).
Build and Run
In a bash shell, perform the following
docker build -t mytest:1.0 .
docker run --rm -v $PWD/results:/opt/tap/Results mytest:1.0 \
plans/MyPlan.TapPlan -e DUT_IP=192.168.1.50Use -e Name=Value to set external test plan parameters, so one image can serve many DUTs and configurations, as above for the DUT IP address.
Export Results Data
You will need to mount local or network volumes to save test run results, session logs and result-listener output (CSV, SQLite), or send results to a network database. Data remaining inside the container is lost when the session terminates exits.
Smoke Test
We’ve provided a “smoke test” script that
Handles platform details
Works in automated CI/CL environments
Runs consistently
Checks the result
Stops when problems are encountered
Documents the entire procedure
For readers not familiar with the bash shell, we included two versions of smoketest.sh, at the end of this blog.
Caveats
Container-based deployment of OpenTAP can present a few “gotchas”. Following are a number of caveats worth calling out, roughly in order of how often they cause trouble:
Hardware and platform
Linux OS: This blog assumes that you will build and run your container on an x64-based Linux system. OpenTAP supports Ubuntu 24.04 and above, but you should be able to create and deploy a Docker image on the Linux host, distribution, version of your choice.
Non-Linux OS: Options exist for Windows and macOS using Docker Desktop, with very specific caveats:
M-Series Mac – prebuilt Dockerfiles assume x64 and until macOS 27, OpenTAP can run under emulation. Native M-Series execution requires rebuilding OpenTAP with architecture=arm64.
VM -based execution - on both Windows and macOS, Docker Desktop runs your containers inside a Linux virtual machine: WSL2 or Hyper-V on Windows, and Apple’s virtualization framework on a Mac, causing many of the following issues.
USB and GPIB – on macOS, containers can’t see USB instruments at all. On Windows, those devices may require reconnection after reboots and other changes to VM state.
Networking – containers sit behind NAT inside the VM, raising issues with reaching LAN-based instruments across subnets, port mapping and auto-discovery.
Hostnames – mDNS names that resolve on a Mac or PC generally don’t resolve inside containers. Use IP addresses or
--add-host.Bash vs. PowerShell – files and scripts created under Windows may generate error inside a Linux container from differing EOL formats.
Permissions - File ownership and permissions may behave unexpectedly across the platforms.
Plugins may not run on Linux: Many OpenTAP plugins and instrument drivers are Windows-only (e.g., WPF UI, Windows DLLs, vendor drivers). Check the available hosting and CPU architecture for each package before attempting to integrate.
USB and GPIB can be fragile in containers: Device passthrough breaks on hot-plug or re-enumeration. On Docker Desktop for Windows or macOS, USB passthrough and --network host don’t behave like they do on native Linux.
CPU architecture: x64 and ARM64 need separate images. The Dockerfile above is x64 only.
Timing-sensitive steps: Containers add little overhead, but they do share host CPU with other workloads. Validate timing-critical measurements on the intended host.
Instrument connectivity (the hardest part)
Validate with simulated instruments first, then begin using actual instruments and DUTs.
LAN instruments: (SCPI sockets, HiSLIP, VXI-11) are easiest. Use
--network hostor make sure the container can route to the instrument subnet.USB and GPIB: need device passthrough (
--device /dev/usbtmc0or/dev/bus/usb, sometimes--privileged), a Linux VISA library in the image, and drivers that support Linux.
Licensing and support
Node-locked licenses tied to a host ID or MAC address can break whenever a container is recreated. For commercially-licensed software, a floating or network license server is usually the right fit; confirm with Keysight for each plugin. License terms may also not cover container use, so confirm with Keysight and other commercial vendors before rollout.
Operations and Security
Data is lost without volumes: Results, session logs, and changed settings vanish when the container exits.
Segregate station-specific state: Calibration files, instrument addresses, and credentials belong in mounted config or secrets, not baked into the image.
--privileged and root: Privileged mode gives broad access to the host, so prefer specific --device flags and a non-root user.
No GUI: Debugging a failing plan is harder headless, so prototype using a visual test plan editor and deploy with rich logging.
Resources and timing: With Docker Desktop, VM-based execution has fixed CPU and memory. Moreover, when a desktop computer sleeps, the VM-based clock can drift, stalling execution and/or losing network connections. Importantly, time-sensitive tests can fail due to running through VM layers.
Unattended hardware safety. Running plans remotely on high-power or hazardous setups needs proper interlocks, because no operator is present.
Conclusion
Containerizing OpenTAP takes just a few steps: install OpenTAP and your plugins on a .NET runtime base, add your test plans, and run them headless with tap run. The result is a versioned, portable image that turns a hand-built test station into something you can rebuild, share and trust. With containerization, every station and CI runner runs the same environment, new stations spin up with a single docker pull, conflicting plugin sets stay neatly isolated, and rolling back is as easy as changing a tag. Start with a simple smoke test, and you’ll quickly find that Docker makes OpenTAP test automation easier to reproduce, scale and share across your team.