diff --git a/README.md b/README.md index 674e058a34..0a22fe3c01 100644 --- a/README.md +++ b/README.md @@ -144,12 +144,23 @@ The node\_exporter is designed to monitor the host system. It's not recommended to deploy it as Docker container because it requires access to the host system. Be aware that any non-root mount points you want to monitor will need bind-mounted into the container. +If you start container for host monitoring, specify `path.rootfs` argument. +This argument must match path in bind-mount of host root. The node\_exporter will use +`path.rootfs` as prefix to filter entries in ${path.procfs}/mounts and to +cleanup it from `mountpoint` label. You also need bind-mount host proc and host sys +with `path.procfs` and `path.sysfs` arguments. +Also you need to use `bind-propagation=rslave` option for bind-mount host rootfs to +propagate host mounts changes to container (option available since 17.05.0). ```bash docker run -d \ --net="host" \ --pid="host" \ - quay.io/prometheus/node-exporter + -v "/proc:/host/proc:ro" -v "/sys:/host/sys:ro" \ + --mount "type=bind,source=/,target=/rootfs,readonly,bind-propagation=rslave" \ + quay.io/prometheus/node-exporter \ + --path.procfs /host/proc --path.sysfs /host/sys \ + --path.rootfs /rootfs ``` On some systems, the `timex` collector requires an additional Docker flag, diff --git a/collector/filesystem_linux.go b/collector/filesystem_linux.go index 04c21a698d..ad89f190bf 100644 --- a/collector/filesystem_linux.go +++ b/collector/filesystem_linux.go @@ -70,7 +70,7 @@ func (c *filesystemCollector) GetStats() ([]filesystemStats, error) { go stuckMountWatcher(labels.mountPoint, success) buf := new(syscall.Statfs_t) - err = syscall.Statfs(labels.mountPoint, buf) + err = syscall.Statfs(rootfsFilePath(labels.mountPoint), buf) stuckMountsMtx.Lock() close(success) @@ -86,7 +86,7 @@ func (c *filesystemCollector) GetStats() ([]filesystemStats, error) { labels: labels, deviceError: 1, }) - log.Debugf("Error on statfs() system call for %q: %s", labels.mountPoint, err) + log.Debugf("Error on statfs() system call for %q: %s", rootfsFilePath(labels.mountPoint), err) continue } @@ -143,6 +143,10 @@ func mountPointDetails() ([]filesystemLabels, error) { scanner := bufio.NewScanner(file) for scanner.Scan() { parts := strings.Fields(scanner.Text()) + // skip non rootfs paths if rootfsPath defined + if !rootfsPathDetect(parts[1]) { + continue + } // Ensure we handle the translation of \040 and \011 // as per fstab(5). @@ -151,7 +155,7 @@ func mountPointDetails() ([]filesystemLabels, error) { filesystems = append(filesystems, filesystemLabels{ device: parts[0], - mountPoint: parts[1], + mountPoint: rootfsStripPrefix(parts[1]), fsType: parts[2], options: parts[3], }) diff --git a/collector/paths.go b/collector/paths.go index f8e6e6e535..92a99edb22 100644 --- a/collector/paths.go +++ b/collector/paths.go @@ -15,6 +15,7 @@ package collector import ( "path" + "strings" "github.com/prometheus/procfs" "gopkg.in/alecthomas/kingpin.v2" @@ -22,8 +23,9 @@ import ( var ( // The path of the proc filesystem. - procPath = kingpin.Flag("path.procfs", "procfs mountpoint.").Default(procfs.DefaultMountPoint).String() - sysPath = kingpin.Flag("path.sysfs", "sysfs mountpoint.").Default("/sys").String() + procPath = kingpin.Flag("path.procfs", "procfs mountpoint.").Default(procfs.DefaultMountPoint).String() + sysPath = kingpin.Flag("path.sysfs", "sysfs mountpoint.").Default("/sys").String() + rootfsPath = kingpin.Flag("path.rootfs", "rootfs mountpoint.").Default("").String() ) func procFilePath(name string) string { @@ -33,3 +35,30 @@ func procFilePath(name string) string { func sysFilePath(name string) string { return path.Join(*sysPath, name) } + +func rootfsFilePath(name string) string { + if name == "/" { + return *rootfsPath + } + return path.Join(*rootfsPath, name) +} + +func rootfsStripPrefix(path string) string { + if path == *rootfsPath { + return "/" + } + if strings.HasPrefix(path, *rootfsPath) { + return strings.TrimPrefix(path, *rootfsPath) + } + return path +} + +func rootfsPathDetect(path string) bool { + if *rootfsPath == "" { + return true + } + if strings.HasPrefix(path, *rootfsPath) { + return true + } + return false +}