Install via Container#
dpsctl is published as a container image at
nvcr.io/nvidia/dpsctl:<release-version>. Use the tag that matches the
DPS server release. This path does not require a separate
binary download or platform selection.
Prerequisites#
Linux or macOS operating system
amd64 or arm64 architecture
Docker (or a compatible OCI runtime such as Podman)
One-shot docker run#
Run any dpsctl subcommand directly:
export DPSCTL_VERSION="<release-version>"
docker run --rm -it --network host \
--mount type=bind,source=/path/to/api-ca.crt,target=/certs/api-ca.crt,readonly \
"nvcr.io/nvidia/dpsctl:${DPSCTL_VERSION}" \
login --host api.dps.example.com --port 443 \
--ca-cert-path /certs/api-ca.crt
Notes:
--network hostlets the container reachlocalhostand any cluster DNS names that resolve on your host.
Install as a dpsctl Shim#
For a smoother experience, install a small wrapper script as ~/.local/bin/dpsctl so every invocation transparently runs the container with sensible defaults (HOME mount, working-directory mount, TTY detection, env-var pass-through):
mkdir -p ~/.local/bin
cat > ~/.local/bin/dpsctl <<'EOF'
#!/bin/bash
# dpsctl wrapper — proxies all calls to the Docker image.
# Set DPSCTL_VERSION to the release that matches the server.
IMAGE="${DPSCTL_IMAGE:-nvcr.io/nvidia/dpsctl}"
VERSION="${DPSCTL_VERSION:?Set DPSCTL_VERSION to the server release}"
mkdir -p "${HOME}/.dpsctl"
# Resolve real path so symlinks inside PWD work inside the container
WORKSPACE=$(realpath "${PWD}" 2>/dev/null || echo "${PWD}")
# Mount only the client state directory and current workspace.
MOUNTS=(-v "${HOME}/.dpsctl:${HOME}/.dpsctl" -v "${WORKSPACE}:${WORKSPACE}")
# Always keep stdin attached; only allocate a TTY when running interactively,
# so redirected/captured output is not corrupted by terminal control sequences.
TTY_FLAGS=(-i)
if [ -t 0 ] && [ -t 1 ]; then
TTY_FLAGS+=(-t)
fi
exec docker run --rm \
--network host \
"${TTY_FLAGS[@]}" \
--user "$(id -u):$(id -g)" \
-e HOME="${HOME}" \
"${MOUNTS[@]}" \
-w "${WORKSPACE}" \
-e DPSCTL_USERNAME \
-e DPSCTL_HOST \
-e DPSCTL_PORT \
-e DPSCTL_CA_CERT_PATH \
-e DPSCTL_CLIENT_CERT_PATH \
-e DPSCTL_CLIENT_KEY_PATH \
-e DPSCTL_AUTH_MODE \
-e DPSCTL_INSECURE_TLS_SKIP_VERIFY \
-e DPSCTL_INSECURE \
-e DPSCTL_GRPC_TIMEOUT \
-e DPSCTL_OUTPUT \
"${IMAGE}:${VERSION}" \
"$@"
EOF
chmod +x ~/.local/bin/dpsctl
Then make sure ~/.local/bin is on your PATH:
export PATH="${HOME}/.local/bin:${PATH}"
What the wrapper does:
Mounts only
~/.dpsctlfrom the home directory so client credentials persist without exposing unrelated home-directory content to the container.Mounts the current working directory at the same path inside the container so commands like
dpsctl topology import ./datacenter.jsonJust Work.Requires files referenced by
dpsctlto be under the current working directory or~/.dpsctl, the only mounted paths.Uses
--network hostso the container can use host routes and names that the host resolves. Host-network support varies by container runtime.Passes through only the endpoint, TLS, authentication-mode, timeout, username, and output-format variables listed in the script. Add
-eentries for any other globaldpsctlenvironment variables, including OIDC client credentials.Does not pass
DPSCTL_PASSWORDinto the container. Use--password-stdinfor non-interactive login. Refer to dpsctl login.Allocates a TTY only when stdin/stdout are interactive, so piped output stays clean.
Pinning a Different Version#
DPSCTL_IMAGE and DPSCTL_VERSION can be overridden independently — the wrapper joins them as ${IMAGE}:${VERSION}:
# Use a different image tag for one invocation
DPSCTL_VERSION="<release-version>" dpsctl --version
# Override both repo and tag (e.g. internal mirror)
DPSCTL_IMAGE=nvcr.io/nvidia/dpsctl \
DPSCTL_VERSION="<release-version>" dpsctl --version
Examples Using the Wrapper#
Once the shim is on your PATH, every command behaves like a native binary:
cp /path/to/api-ca.crt .
dpsctl login --host api.dps.example.com --port 443 \
--ca-cert-path "${PWD}/api-ca.crt"
dpsctl topology import ./datacenter.json
dpsctl resource-group list