banshee is under active development: collectors will keep changing, and a version you publish will likely need adjustments. For stable use, wait for version 1.0.0.

Containers

banshee/containers-collection/containers/docker/ssh/

disk

The space the images, containers, volumes and build cache of a Docker host take, by SSH, through a restricted sudo or the docker group.

  • containers
  • docker
  • disk
  • images
  • volumes
  • build-cache
  • sudo
  • ssh
  • linux

by banshee1 installation2 versions

v2Latest

Published on October 28, 2026. One naming convention across collections; documentation completed.

Keen 1.0.0 · 88 lines
// The space Docker takes on the disk of a host, by SSH: for its images, its containers, its local volumes
// and its build cache, the space used, the space that could be freed, and how many there are and how many
// are in use. One command, docker system df, which only reads: through sudo -n in the one form the sudoers
// line of the documentation allows, or straight when the account is in the docker group.
// The free space of the disk itself is the filesystem collector's: this one says what Docker holds on it.
need('protocol:ssh');
$sudo = variable('docker:sudo', 'boolean', array(
    'label'   => 'Through sudo',
    'help'    => 'Runs docker through sudo, with the sudoers line of the documentation. Off when the account is in the docker group instead.',
    'default' => true,
));

per('type', 'Types');
output('size', 'number', array('label' => 'Space used', 'unit' => 'GiB', 'per' => 'type'));
output('reclaimable', 'number', array('label' => 'Space that could be freed', 'unit' => 'GiB', 'per' => 'type'));
output('count', 'number', array('label' => 'Count', 'per' => 'type'));
output('active', 'number', array('label' => 'In use', 'per' => 'type'));

watch.above('size', 'Docker space used', 'size', array(
    'help'    => 'The threshold depends on the disk: in GiB.',
    'enabled' => false,
));
watch.above('reclaimable', 'Space to free', 'reclaimable', array(
    'help'    => 'Images, containers, volumes or build cache that nothing uses any more, and that docker system prune would free: in GiB.',
    'enabled' => false,
));

// Runs a docker command, through sudo -n when asked, and returns what it wrote. A daemon that does not
// answer is a host whose containers are all down: critical. Anything else that keeps docker from answering
// (sudo refusing, docker missing, the account outside the docker group) is a setting to fix.
function docker_run($sudo, $arguments) {
    $command = '/usr/bin/docker ' . $arguments;
    if ($sudo) {
        $command = 'sudo -n ' . $command;
    }
    $read = ssh.run($command);
    if ($read['exit'] != 0) {
        if (text.contains($read['errors'], 'Cannot connect to the Docker daemon')) {
            fail('critical', 'The Docker daemon is not running', $read['errors']);
        }
        if (text.contains($read['errors'], 'sudo')) {
            fail('misconfigured', 'sudo refused to run docker: see the sudoers line of the documentation', $read['errors']);
        }
        fail('misconfigured', 'docker did not answer', $read['errors']);
    }
    return $read['output'];
}

// A size as Docker writes it, in decimal units, four significant figures: "16.43MB", "212B", "1.2GB (45%)";
// a space before the unit, as the documentation's example writes it, is read too. Returned in GiB, to the
// hundredth (about 10 MiB), the unit of space of every collector. '' when it is not one.
function gib_of($size) {
    $units = array('B' => 1, 'kB' => 1000, 'MB' => 1000000, 'GB' => 1000000000, 'TB' => 1000000000000,
        'PB' => 1000000000000000);
    $m = text.match($size, '^([0-9.]+) ?(B|kB|MB|GB|TB|PB)');
    if (list.count($m) == 0) {
        return '';
    }
    return number.round($m[1] * $units[$m[2]] / 1073741824, 2);
}

// One JSON object per line, one line per type: {"Type": "Images", "TotalCount": "5", "Active": "2", "Size":
// "16.43MB", "Reclaimable": "11.63MB (70%)"}. The types are Images, Containers, Local Volumes and Build
// Cache; each is named in lower case, words joined by "-": local-volumes.
$output = docker_run($sudo, "system df --format '{{json .}}'");
$types = 0;
foreach (text.lines($output) as $line) {
    $row = json.read($line);
    $name = text.lower(text.join(text.words($row['Type']), '-'));
    $types = $types + 1;
    $size = gib_of($row['Size']);
    if ($size != '') {
        value('size', $size, $name);
    }
    $reclaimable = gib_of($row['Reclaimable']);
    if ($reclaimable != '') {
        value('reclaimable', $reclaimable, $name);
    }
    if (text.is_number($row['TotalCount'])) {
        value('count', $row['TotalCount'] + 0, $name);
    }
    if (text.is_number($row['Active'])) {
        value('active', $row['Active'] + 0, $name);
    }
}
if ($types == 0) {
    fail('misconfigured', 'docker system df returned nothing', $output);
}