Disk space, inode and mount mode checks

Define named groups of paths in the container, then reference the group in a resource or condition. A group is reusable across container selections. All paths in a requested group must exist in every selected running container.

dir-groups:
  data:
    paths:
      - /data
      - /var/log
  temporary:
    paths:
      - /tmp
      - /dev/shm
conditions:
  data_disk_full:
    expr:
      - disk_percent[data] > 90
  data_inodes_full:
    expr:
      - inode_percent[data] > 95
  data_read_only:
    expr:
      - fs_mode[data] == ro

Use one group per path when paths need different thresholds. Group names follow the same naming convention as condition aliases. Relative paths and control characters are rejected. Spaces and shell punctuation are passed literally; stat collection never invokes a shell. The mount-mode probe uses a fixed shell script with the path as a quoted positional argument. Duplicate paths are sampled once per cycle and container, including across groups.

Like other configuration sections, dir-groups supports templates, variables and @import_dir-group files.

Read measurements

monit-docker -c config.yml --name 'app-*' stats \
  --rsc 'disk_percent[data]' --rsc 'disk_available[data]' \
  --rsc 'inode_percent[data]' --rsc 'inode_available[data]'

Each resource returns a mapping from path to value. Measurements describe the filesystem containing the path, not the recursive size of the directory. Two paths on the same filesystem normally report the same capacity. Bind mounts, volumes and tmpfs are measured as seen inside the container.

Resource prefix

Value

disk_usage

Used bytes

disk_available

Bytes available to an unprivileged writer

disk_total

Total bytes, including reserved blocks

disk_percent

used / (used + available) * 100

inode_usage

Used inodes

inode_available

Free inodes

inode_total

Total inodes

inode_percent

used / total * 100

fs_mode

Effective mount mode: ro or rw

Append [group] to every prefix. API values use raw bytes; stats formats byte values for readability. Filesystem monit --rsc queries print per-path values; they do not collapse multiple paths into one percentage exit code.

Read-only and read-write mounts

monit-docker -c config.yml --name 'app-*' stats --rsc 'fs_mode[data]'
monit-docker -c config.yml --name 'app-*' monit --dry-run \
  --cmd-if 'fs_mode[data] == ro ? (true)'

fs_mode supports ==, !=, in and not in with ro/rw, using the same group and same-path matching rules as disk and inode checks. An unavailable mode is an error (115), never silently rw. In the API, unrequested modes are null.

The probe opens each directory for reading and resolves its actual mount ID using Linux fdinfo and mountinfo. This follows symlinks and handles bind mounts without guessing from path prefixes. Either a read-only per-mount flag or a read-only superblock yields ro. A mode-only query needs no stat command or Docker statistics stream and creates no test file. Only directories are accepted by this probe.

rw describes the mount, not the application’s ability to create files. Unix permissions, ACLs, quotas, a full disk and security policy can still prevent writes. This check does not change permissions or remount anything. Read-only roots and configuration mounts can be intentional: select the paths expected to remain writable. Diagnose a filesystem unexpectedly remounted read-only before choosing a remediation command.

Evaluate rules

monit-docker -c config.yml --name 'app-*' monit --dry-run \
  --cmd-if '@data_disk_full ? (true)' \
  --cmd-if '@data_inodes_full ? (true)'

Replace (true) with an explicitly configured remediation command when ready. The commands above are a harmless rule preview, not a cleanup procedure. The same expressions work with cron and serve, including their existing cooldowns, trigger delays and action journal.

A rule matches when any path in its group satisfies its conditions. When an alias contains several conditions on the same group, they must all hold on the same path. Conditions on different groups must each find a matching path. Each rule executes once per container per cycle, regardless of how many paths match. Separate rules remain independent and may each execute an action. Trigger delays and cooldowns track the container/rule pair, not individual paths.

Validate paths and group references without contacting Docker:

monit-docker -c config.yml check-config \
  --cmd-if 'disk_available[data] < 1 GiB ? (true)'

This validates configuration syntax, not the existence of paths in containers.

Continuous monitoring and notifications

monit-docker -c config.yml --name 'app-*' serve \
  --rsc cpu_percent --rsc mem_percent \
  --rsc 'disk_percent[data]' --rsc 'inode_percent[data]' --rsc 'fs_mode[data]' \
  --rsc 'disk_percent[temporary]' --rsc 'inode_percent[temporary]'

Only groups requested by --rsc or rules are sampled. Defining a group alone does not enable collection or add any container exec calls to CPU/memory checks. /v1/status adds a filesystems list per container, with group, path and all eight numeric values plus fs_mode. Uncollected values are null. Prometheus exports these gauges with id, name, group and path labels:

  • monit_docker_container_disk_usage_bytes

  • monit_docker_container_disk_available_bytes

  • monit_docker_container_disk_total_bytes

  • monit_docker_container_disk_usage_percent

  • monit_docker_container_inode_usage

  • monit_docker_container_inode_available

  • monit_docker_container_inode_total

  • monit_docker_container_inode_usage_percent

  • monit_docker_container_filesystem_read_only (1 for ro, 0 for rw; omitted when not collected)

Add Prometheus alerts to the existing Alertmanager notification pipeline, for example monit_docker_container_disk_usage_percent{group="data"} > 90 and monit_docker_container_inode_usage_percent{group="data"} > 95. Use for to choose how long a threshold must remain exceeded before notifying. The path label identifies the affected location; thresholds can also filter by path.

For mount modes, alert on monit_docker_container_filesystem_read_only{group="data"} == 1, with the same freshness checks used for other container metrics.

Requirements and errors

Capacity collection uses Docker exec and stat -f -c '%S %b %f %a %c %d' -- PATH in Linux containers, compatible with GNU stat and Alpine’s BusyBox stat. The container must provide this command and allow access to the path. Images without stat, including many distroless images, cannot use this collector. No helper is installed and no privileged container access or host filesystem mount is needed.

Mount-mode collection instead requires sh, cat, readable directories and Linux /proc/self/fdinfo and /proc/self/mountinfo. It works with Alpine BusyBox and standard GNU tools. Both probes run with the container’s configured exec user.

Output reading is limited to five seconds per probe: 4 KiB for stat and 256 KiB for mount information. Oversized output is an error. Docker API setup requests use the client’s normal timeout. Closing a timed-out exec connection does not forcibly kill a stuck probe process inside the container.

A missing/inaccessible path, unsupported stat, invalid output or timed-out read fails collection with error 115 and container/group/path context. Metric-based actions are not run from a partial sample; the service reports collection not ready and withholds stale container metrics. Earlier status-only actions keep the existing engine ordering and may already have run.

Paused containers cannot execute stat and produce error 115 when a filesystem check is requested. Stopped containers keep their usual status-only behavior and have no filesystem samples. Filesystems reporting zero total inodes have unavailable inode values, not 0% usage: requesting those values fails the check.