Skip to main content

Docker credentials & volumes

This article refers to SDK version v0.5.0. The current SDK version is N/A.

Overview

Two node-level docker concerns the SDK covers directly: registry credentials, so a node can pull images from a private registry, the same data behind the Repository credentials card, and volumes, for data that needs to survive beyond a single container's lifetime, covered from the Panel side in Docker Volumes.

Every method below takes a node_id, the internal id from client.nodes.resolve(node_name). See Getting started for how to get one.

Concept

Docker Volumes. Storage a workload's container keeps writing to, that survives the container being recreated: an operator manages these from the node's Docker Volumes card, the same as external drives you'd plug into a regular machine.

Learn more

Register registry credentials

client.nodes.create_docker_credentials(
node.id, [{"user": "bob", "password": "s3cr3t", "server": "docker.io"}]
)

create_docker_credentials(node_id, credentials) takes credentials as a List[Dict[str, str]], one dict per registry login, mirroring the Repository URL / Username / Password fields of the Add credential popup in Panel:

KeyWhat it is
userThe registry username
passwordThe registry password
serverThe registry's URL, for example docker.io for Docker Hub

Pass more than one dict in the list to register several registries in a single call. All three fields are base64-encoded internally before the request is sent, matching Barbara's API convention, so you always work with plain strings on the Python side.

Docker Hub

Panel's own tip applies here too: use http://index.docker.io as the server value, not docker.io alone, or the credential fails to validate against the registry.

credentials = client.nodes.list_docker_credentials(node.id)
client.nodes.delete_docker_credential(node.id, "<credential-id>")

list_docker_credentials(node_id) returns a List[DockerCredential]. Each one has an id (the internal identifier delete_docker_credential expects), a server field, and a user field, both decoded back to plain text. password is deliberately not a field on this type at all: Panel never stores the plaintext password once it's been sent to the node, so the API never returns it, under any role, matching how a credential's password field in Panel's own Docker Credentials card is write-only. delete_docker_credential(node_id, credential_id) removes exactly one credential by that id; delete_all_docker_credentials(node_id) removes every credential on the node in one call, with no arguments beyond the node id.

Create and remove volumes

client.nodes.create_docker_volume(node.id, "shared-cache")

create_docker_volume(node_id, volume_name) takes a plain string volume_name and creates what Panel's Docker Volumes card calls an external volume: one you create yourself, as opposed to an internal volume Docker creates automatically the first time a workload that declares it starts. volume_name is base64-encoded internally, same convention as everywhere else in this guide. The method returns None and, unlike most create calls in the SDK, the underlying API doesn't hand back an id for the new volume either.

volumes = client.nodes.list_docker_volumes(node.id)
client.nodes.delete_docker_volume(node.id, volumes[0]["_id"])
Finding the id you just created

create_docker_volume doesn't return an id, and there's no dedicated list endpoint for node volumes either. list_docker_volumes(node_id) works around both gaps: it fetches the node and decodes the volume list nested in its document, so it returns List[Dict[str, Any]] rather than a typed dataclass. Each entry has an _id key (what delete_docker_volume needs) and a base64-decoded name key. Call list_docker_volumes right after create_docker_volume to find the _id of the volume you just created, matching it by name.

delete_docker_volume(node_id, volume_id) takes that _id, not the volume's name; passing a name here fails silently against the wrong resource. This mirrors the Delete action on a volume's row in the Docker Volumes card, which is disabled while a volume is in use; the SDK doesn't check that for you, so a delete against an in-use volume fails with an API error, not a friendly local message.

Maintain Docker on a node

client.nodes.prune_docker(node.id, "prunevolumes")
client.nodes.prune_docker_all(node.id)
client.nodes.restart_docker_daemon(node.id)

prune_docker(node_id, prune_target) mirrors the per-kind buttons in Advanced Actions: prune_target accepts "prunevolumes", "prunenetworks", "prunecontainers", or "pruneimages", always with that prune prefix on the value, since the bare noun ("volumes", "images", ...) 404s against the API. prune_docker_all(node_id, *, force=False) runs all four in sequence, equivalent to Docker Prune All; set force=True to prune even resources the daemon would otherwise consider still referenced. restart_docker_daemon(node_id) takes only the node id and maps directly to the Restart Docker Daemon action, which interrupts every running container on the node while the daemon restarts.

To inspect what a prune would remove before running it, call get_docker_prune_info:

info = client.nodes.get_docker_prune_info(node.id, "prunevolumes")

It takes the same prune_target values as prune_docker and returns a raw Dict[str, Any], since the response shape depends on which target you asked about.

This can delete data

prune_target="prunevolumes" (and prune_docker_all) can delete data. A pruned volume that held application state or logs is gone, the same caveat Panel gives for the manual Prune Volumes action. Call get_docker_prune_info first if you're not certain what's currently unused.

Delete a node asset

Node Assets, in Panel's Advanced Actions popup, is a per-node file store for operational documentation: schemas, install photos, scripts, and similar files.

client.nodes.delete_asset(node.id, name="wiring-diagram.png", path="/schemas")

delete_asset(node_id, *, name, path) is the only Node Assets operation the public API exposes, there's no list/upload/download endpoint, so you need to already know an asset's name and path, as shown in Panel, before removing it here.

Manage credentials and volumes at cluster scope

client.clusters covers creation and bulk cleanup for cluster-wide registry access (create_docker_credentials and delete_all_docker_credentials; there's no cluster-level list/get/single-delete, unlike at node scope), see Repository Credentials (cluster). Cluster volumes (client.clusters.create_swarm_volume and friends, covered in Clusters & cluster workloads) are created once and shared across every member node instead of per node.

Summary

You can now get a private image onto a node and give a workload somewhere persistent to write, plus clean up docker resources when they pile up.

Doing this from a script means a fleet of nodes ends up with identical registry access and volume layout, instead of each one drifting slightly from manual setup.

For the full method list, see client.nodes in the Reference. To put a private image to use, continue to Deploying your own Docker apps.