Recent Posts
Archives

PostHeaderIcon Docker Rootless Mode, or Fixing Persistent Docker Daemon Failure in WSL 2

This comprehensive tutorial addresses the complex and persistent issue of the Docker daemon failing to start with a "Device or resource busy" error when running a native Docker Engine inside a WSL 2 (Windows Subsystem for Linux 2) distribution, ultimately leading to the necessity of switching to Docker Rootless Mode.

1. The Problem Overview

The core issue is the native system-wide Docker daemon (dockerd) failing to initialize upon startup inside the WSL 2 environment. This failure manifests as a persistent loop of errors:

  1. High-Level Status: Active: failed (Result: exit-code) or Start request repeated too quickly.
  2. Access Block: Attempts to clear corrupted storage often fail with mv: cannot move '/var/lib/docker': Device or resource busy.
  3. Root Cause: The failures stem from a combination of stale lock files (docker.pid), corrupted storage metadata (metadata.db), and fundamental conflicts with the WSL 2 kernel's implementation of features like Cgroups or network socket activation.

To resolve this reliably, the solution is to bypass the system-level conflicts by switching from the problematic rootful daemon to the more stable Docker Rootless mode.


2. Step-by-Step Resolution

The resolution involves three phases: diagnosing the specific low-level crash, performing an aggressive cleanup to free the lock, and finally, installing the stable rootless solution.

Phase 1: Aggressive Cleanup and File Lock Removal

The persistent "Device or resource busy" error is the primary block. Even a full Windows reboot or wsl --shutdown often fails to clear the lock held on /var/lib/docker.

A. Forcefully Shut Down WSL 2

  1. Close all WSL terminals.
  2. Open Windows PowerShell (or CMD).
  3. Execute the global shutdown command: This ensures the Linux kernel and all running processes are terminated, releasing file locks.
    wsl --shutdown
    

B. Identify and Rename the Corrupted Directory

  1. Relaunch your WSL terminal.
  2. Rename the Corrupted Docker Storage: This creates a fresh start for the storage driver. If this fails with Device or resource busy (which is highly likely), proceed to step C.
    sudo mv /var/lib/docker /var/lib/docker.bak
    
  3. [If Rename Fails] Terminate and Delete the Lock File: The daemon failed because it was locked by a rogue PID, which often leaves behind a stale PID file.

    # Stop the failing service (just in case it auto-started)
    sudo systemctl stop docker.service
    
    # Delete the stale PID file that falsely signals the daemon is running
    sudo rm /var/run/docker.pid
    

Phase 2: Switch to Docker Rootless Mode

Rootless mode installs the daemon under your standard user account, isolating it from the system-level issues that caused the failure.

A. Install Prerequisites

Install the uidmap package, which is necessary for managing user namespaces in the rootless environment.

  1. Check and clear any package locks (if necessary):
    If sudo apt install hangs, check for and kill the conflicting process (e.g., unattended-upgr using sudo kill -9 <PID>), and then delete the lock files:

    sudo rm /var/lib/dpkg/lock-frontend
    sudo rm /var/lib/dpkg/lock
    sudo dpkg --configure -a
    
  2. Install uidmap:
    sudo apt update
    sudo apt install uidmap
    

B. Install the Rootless Daemon

  1. Ensure the system-wide daemon is stopped and disabled to prevent conflicts:
    sudo systemctl stop docker.service
    sudo systemctl disable docker.service
    sudo rm /var/run/docker.sock # Clean up the system socket
    
  2. Run the Rootless setup script:
    dockerd-rootless-setuptool.sh install
    

Phase 3: Configure and Launch

The setup script completes the installation but requires manual configuration to launch the daemon and set the necessary environment variables.

A. Configure Shell Environment

  1. Edit your bash profile (~/.bashrc):
    vi ~/.bashrc
    
  2. Add the necessary environment variables (these lines are typically provided by the setup script and redirect the client to the rootless socket):
    # Docker Rootless configuration for user <your_username>
    export XDG_RUNTIME_DIR=/home/<your_username>/.docker/run
    export PATH=/usr/bin:$PATH
    export DOCKER_HOST=unix:///home/<your_username>/.docker/run/docker.sock
    
  3. Save the file and exit the editor.

B. Startup Sequence (Required on Every WSL Launch)

Because your WSL environment is not using a fully managed systemd to start the rootless daemon automatically, you must execute the following two commands every time you open a new terminal:

  1. Source the configuration: Activates the DOCKER_HOST environment variable in the current session.
    source ~/.bashrc
    
  2. Start the Rootless Daemon: Launches the user-level daemon in the background.
    dockerd-rootless.sh &
    

C. Final Verification

Wait a few seconds after launching the daemon, then verify connectivity:

docker ps

The client will now connect to the stable, user-level daemon, resolving the persistent startup failures.

Leave a Reply