Skip to content

Instantly share code, notes, and snippets.

@psavarmattas
Last active February 19, 2025 15:38
Show Gist options
  • Save psavarmattas/909ca4cdd5c118a8f74b7aa401f427b4 to your computer and use it in GitHub Desktop.
Save psavarmattas/909ca4cdd5c118a8f74b7aa401f427b4 to your computer and use it in GitHub Desktop.
docker-rootless-install-scripts
#!/bin/bash
# Script to install rootless Docker for the current user
check_command() {
if ! command -v "$1" &> /dev/null; then
echo "Error: $1 is required but not found. Please install it and try again." >&2
exit 1
fi
}
check_subuid_subgid() {
local user="$1"
if ! grep -q "^$user:" /etc/subuid; then
echo "Error: No entry found for user '$user' in /etc/subuid." >&2
echo "Please add an entry for your user to /etc/subuid (as root):" >&2
echo " echo \"$user:$(id -u):65536\" | sudo tee -a /etc/subuid" >&2
exit 1
fi
if ! grep -q "^$user:" /etc/subgid; then
echo "Error: No entry found for user '$user' in /etc/subgid." >&2
echo "Please add an entry for your user to /etc/subgid (as root):" >&2
echo " echo \"$user:$(id -u):65536\" | sudo tee -a /etc/subgid" >&2
exit 1
fi
}
add_to_bashrc() {
local file="$1"
local line="$2"
if ! grep -Fq "$line" "$file"; then
echo "$line" >> "$file"
echo "Added '$line' to $file"
else
echo "'$line' already exists in $file, skipping."
fi
}
check_command curl
check_command tar
check_command newuidmap
check_command newgidmap
check_subuid_subgid "$USER"
home_dir="$HOME"
if [ ! -d "$home_dir/.docker" ]; then
mkdir -p "$home_dir/.docker"
fi
mkdir -p "$home_dir/bin"
echo "Installing rootless Docker..."
curl -fsSL https://get.docker.com/rootless | sh
echo "Configuring systemd..."
if ! dockerd-rootless-setuptool.sh install; then
echo "Error: dockerd-rootless-setuptool.sh failed. See output above for details." >&2
exit 1
fi
echo "Configuring environment variables..."
add_to_bashrc "$home_dir/.bashrc" 'export PATH="$HOME/bin:$PATH"'
add_to_bashrc "$home_dir/.bashrc" 'export DOCKER_HOST="unix:///run/user/$(id -u)/docker.sock"'
# --- NVIDIA Configuration (User-Specific) ---
# Check if the nvidia runtime is configured system-wide
if grep -q '"nvidia"' /etc/docker/daemon.json; then
echo "NVIDIA Container Toolkit detected (system-wide configuration)."
# Create the user's daemon.json if it doesn't exist
mkdir -p "$HOME/.config/docker"
if [ ! -f "$HOME/.config/docker/daemon.json" ]; then
touch "$HOME/.config/docker/daemon.json"
fi
# Add "default-runtime": "nvidia" to the user's daemon.json, handling existing content
if ! jq -e '.["default-runtime"]' "$HOME/.config/docker/daemon.json" >/dev/null 2>&1; then
# If "default-runtime" doesn't exist, add it
jq '. += {"default-runtime": "nvidia"}' "$HOME/.config/docker/daemon.json" > "$HOME/.config/docker/daemon.json.tmp" && mv "$HOME/.config/docker/daemon.json.tmp" "$HOME/.config/docker/daemon.json"
else
# If "default-runtime" exists, check and potentially update
current_runtime=$(jq -r '.["default-runtime"]' "$HOME/.config/docker/daemon.json")
if [[ "$current_runtime" != "nvidia" ]]; then
echo "Updating default runtime to nvidia in user configuration."
jq '.["default-runtime"] = "nvidia"' "$HOME/.config/docker/daemon.json" > "$HOME/.config/docker/daemon.json.tmp" && mv "$HOME/.config/docker/daemon.json.tmp" "$HOME/.config/docker/daemon.json"
else
echo "User configuration already set to use nvidia runtime."
fi
fi
else
echo "NVIDIA Container Toolkit not detected or not configured system-wide. Skipping NVIDIA setup."
fi
cat <<EOF
Rootless Docker installation complete.
Please log out and log back in for the changes to take effect.
**Optional: X11 Forwarding**
- If you need X11 forwarding with Docker, ensure your SSH configuration
- allows it (e.g., `ForwardX11 yes` in your SSH client config and
- `X11Forwarding yes` in the server's sshd_config). You may also need to set
- the DISPLAY environment variable appropriately before running Docker
- commands that require X11. The exact setup depends on your specific
- X11 configuration.
EOF
exit 0
#!/bin/bash
# Script to prepare a user for rootless Docker (run as root)
check_command() {
if ! command -v "$1" &> /dev/null; then
echo "Error: $1 is required but not found. Please install it and try again." >&2
exit 1
fi
}
if [ -z "$1" ]; then
echo "Usage: $0 <username>" >&2
exit 1
fi
username="$1"
if ! id "$username" &> /dev/null; then
echo "Error: User '$username' does not exist." >&2
exit 1
fi
check_command apparmor_status
if ! apparmor_status 2>&1 | grep -q "AppArmor is enabled"; then
echo "Warning: AppArmor does not appear to be enabled. Rootless Docker might not work correctly." >&2
fi
profile_content=$(cat <<EOT
# ref: https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces
abi <abi/4.0>,
include <tunables/global>
/home/$username/bin/rootlesskit {
userns,
capability setuid,
capability setgid,
capability chown,
capability dac_override,
capability fowner,
capability fsetid,
capability kill,
capability net_bind_service,
capability net_raw,
capability setpcap,
include if exists <local/home.$username.bin.rootlesskit>
}
EOT
)
temp_profile=$(mktemp)
echo "$profile_content" > "$temp_profile"
chown root:root "$temp_profile"
chmod 644 "$temp_profile"
if ! mv "$temp_profile" "/etc/apparmor.d/home.$username.bin.rootlesskit"; then
echo "Error: Failed to create AppArmor profile." >&2
rm -f "$temp_profile"
exit 1
fi
systemctl restart apparmor.service
# --- NVIDIA Configuration (System-Wide) ---
if lspci | grep -q NVIDIA; then
check_command nvidia-ctk
echo "Configuring NVIDIA Container Toolkit (system-wide)..."
nvidia-ctk runtime configure --runtime=docker
else
echo "NVIDIA hardware not detected. Skipping system-wide nvidia-ctk configuration."
fi
id -u "$username" &> /dev/null || { echo "User $username does not exist" >&2; exit 1; }
grep -q "^$username:" /etc/subuid || { echo "$username:$(id -u "$username"):65536" | tee -a /etc/subuid; }
grep -q "^$username:" /etc/subgid || { echo "$username:$(id -u "$username"):65536" | tee -a /etc/subgid; }
echo "User '$username' prepared for rootless Docker."
exit 0
@psavarmattas
Copy link
Author

Rootless Docker Automated Setup Scripts

This Gist provides two scripts to automate the setting up of rootless Docker for individual users on a Linux system. This allows users to run Docker containers without requiring root (sudo) privileges, including support for NVIDIA GPUs.

Prerequisites

  • A Linux system (tested on Ubuntu, but should work on most distributions with appropriate adjustments).
  • curl, tar, newuidmap, newgidmap, and jq must be installed on the system.
    • On Debian/Ubuntu: sudo apt update && sudo apt install curl tar uidmap jq
  • AppArmor is recommended to be enabled (it usually is by default on Ubuntu).
  • For NVIDIA GPU support: The NVIDIA Container Toolkit must be installed before running these scripts.
  • The user must have a home directory.

Two Scripts

  1. prepare_user_for_rootless.sh (Admin Script): Run with sudo for each user. Sets up AppArmor, system configurations, and system-wide NVIDIA settings (if applicable).

  2. install_rootless_docker.sh (User Script): Run by each user in their account. Installs rootless Docker and configures the NVIDIA runtime (if available).

Instructions for the Administrator (Root/Sudo User)

  1. Download both scripts from this Gist.

  2. Make prepare_user_for_rootless.sh executable:

    chmod +x prepare_user_for_rootless.sh
  3. For each user who needs rootless Docker, run the script with the username as an argument:

    sudo ./prepare_user_for_rootless.sh <username>

    Replace <username> with the actual username (e.g., sudo ./prepare_user_for_rootless.sh john). Repeat this step for all users who require rootless Docker.

  4. Important: Ensure that /etc/subuid and /etc/subgid have entries for each user. The prepare_user_for_rootless.sh script attempts to add these, but you should verify them. Each file should have a line like:

    username:start_uid:count
    

    For example:

    john:1000:65536
    

    Where username is the user's login name, start_uid is a unique starting UID (usually the user's UID), and count is the number of subordinate UIDs (65536 is a common value). If these entries are missing or incorrect, rootless Docker will not work. You can manually add them using usermod or by directly editing the files (with sudo). The admin script now adds these automatically.

Instructions for the User

  1. Log in to your user account.

  2. Download the install_rootless_docker.sh script from this Gist.

  3. Make the script executable:

    chmod +x install_rootless_docker.sh
  4. Run the script:

    ./install_rootless_docker.sh
  5. Log out and log back in for the changes to take effect. This is crucial for the updated environment variables and systemd configuration to be loaded.

  6. Test the installation by running:

    docker run hello-world

    If everything is set up correctly, you should see the "Hello from Docker!" message.

  7. Test NVIDIA (if applicable): If you have an NVIDIA GPU and the admin configured it, try:

    docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi

    This should show your GPU information.

Optional: X11 Forwarding (User)

If you need to run GUI applications inside Docker containers, you'll need to configure X11 forwarding. This is a more advanced topic and depends on your specific SSH and X11 setup. Ensure:

  • Your SSH client configuration allows X11 forwarding (e.g., ForwardX11 yes).
  • The server's sshd_config allows X11 forwarding (X11Forwarding yes).
  • You may need to set the DISPLAY environment variable before running Docker commands that require X11.

Troubleshooting

  • "docker: command not found": Make sure you logged out and back in after running the installation script. Check your $PATH environment variable (echo $PATH) to ensure it includes $HOME/bin.
  • Permission errors: Double-check the /etc/subuid and /etc/subgid entries for your user (see Administrator instructions). Ensure the AppArmor profile was created correctly (check /etc/apparmor.d/).
  • "Cannot connect to the Docker daemon": Verify that the DOCKER_HOST environment variable is set correctly (echo $DOCKER_HOST). It should be something like unix:///run/user/1000/docker.sock (where 1000 is your user ID). Also, make sure the Docker service is running: systemctl --user status docker
  • NVIDIA-related errors: If you're using NVIDIA GPUs, ensure the NVIDIA Container Toolkit is installed and that the nvidia-ctk command was run successfully by the administrator.
  • AppArmor errors: If you see AppArmor-related errors in your system logs (dmesg or /var/log/syslog), the AppArmor profile might be too restrictive. You might need to adjust the profile (see the prepare_user_for_rootless.sh script).
  • NVIDIA GPU not detected inside container:
    • Ensure the NVIDIA Container Toolkit is properly installed on the host system.
    • Ensure the administrator ran prepare_user_for_rootless.sh successfully.
    • Ensure you logged out and back in after running install_rootless_docker.sh.
    • Check that /etc/docker/daemon.json contains a "runtimes" section with an entry for "nvidia".
    • Check that $HOME/.config/docker/daemon.json contains "default-runtime": "nvidia".
  • Check the output: Make sure to always read the output of all the commands and scripts.

Important Notes

  • Rootless Docker runs containers without root privileges. This improves security, but it also means some Docker features might not be available or might behave differently.
  • Each user gets their own isolated Docker environment. Containers and images are not shared between users.
  • This setup is particularly useful for homelabs, development environments, and situations where you want to give users Docker access without granting them full root privileges on the system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment