How to Mount Docker Container Filesystem on Host for Inspection (Read-Only Access)


2 views

When debugging Docker containers, we often need to examine their filesystem contents from the host machine. While docker exec allows command execution inside containers, sometimes direct filesystem access provides better visibility. The naive approach of browsing /var/lib/docker exposes implementation details that may change between Docker versions.

Docker provides several built-in methods for container filesystem access:

# Export container filesystem as archive
docker export container_id > container_fs.tar

# Create image from container
docker commit container_id inspection_image

# Copy files from container to host
docker cp container_id:/path/in/container /host/path

For persistent read-only access, we can use these techniques:

Method 1: Using docker run with volumes

# First get the container's rootfs path
CONTAINER_ID=$(docker inspect --format '{{.Id}}' your_container)
HOST_PATH="/var/lib/docker/overlay2/$CONTAINER_ID/merged"

# Mount as read-only
sudo mount --bind -o ro $HOST_PATH /mnt/container_fs

Method 2: Leveraging nsenter

# Get container's PID
CONTAINER_PID=$(docker inspect --format '{{.State.Pid}}' your_container)

# Mount the namespace
sudo nsenter --mount --target $CONTAINER_PID -- sh -c 'mount --bind --ro / /mnt && sleep infinity' &

# Access from host
sudo ls /proc/$CONTAINER_PID/root/

For production systems, consider these robust approaches:

  • Create a custom Docker volume plugin
  • Use runc directly to access container rootfs
  • Implement FUSE-based solutions for safer access

Always mount container filesystems as read-only when possible. Remember that:

  • Direct filesystem access bypasses container isolation
  • Some paths (/proc, /sys) appear different from host perspective
  • Permissions might require root access on host

When debugging containers or analyzing their contents, we often need read-only access to a container's filesystem from the host machine. While docker exec allows interactive inspection, mounting the entire filesystem provides better visibility for batch operations, file comparisons, or forensic analysis.

The Docker Engine doesn't provide a direct API for this operation, but we have several reliable methods:

Method 1: Using docker export

This creates a portable filesystem snapshot:


# Create temporary container if needed
docker create --name temp_container my_image

# Export and extract
docker export temp_container | tar -xC /host/mount/path

# Clean up
docker rm temp_container

Method 2: Bind Mounting Storage Driver Paths

For advanced users comfortable with Docker internals (works with btrfs, overlay2):


# Find the container's writable layer
CONTAINER_ID=$(docker inspect --format '{{.Id}}' my_container)
STORAGE_PATH="/var/lib/docker/overlay2/$CONTAINER_ID/merged"

# Mount read-only
sudo mount --bind -o ro $STORAGE_PATH /mnt/container_view

For frequent usage, consider developing a volume plugin:


package main

import (
    "github.com/docker/go-plugins-helpers/volume"
    "path/filepath"
)

type fsInspectorDriver struct {
    mountPath string
}

func (d *fsInspectorDriver) Mount(req *volume.MountRequest) (*volume.MountResponse, error) {
    containerPath := filepath.Join("/var/lib/docker", req.Name)
    return &volume.MountResponse{Mountpoint: containerPath}, nil
}

// Implement other required volume plugin methods...
  • Always mount read-only (-o ro) when inspecting containers
  • Prefer docker export for production systems to avoid storage driver dependencies
  • Consider filesystem permissions - you may need root access for some methods

For complex inspection needs:

  • dive - Analyzes Docker image layers
  • container-diff - Compares container filesystems
  • sysdig - Real-time container monitoring