Docker Rootless Mode Configuración
Docker rootless mode enables running contenedores without requiring root privileges, significantly reducing the attack surface and improving security. Esta guía completa cubre prerequisites, installation, cgroup v2 configuration, networking with slirp4netns, limitations, troubleshooting, and production best practices. Rootless mode is essential for multi-tenant environments and organizations with strict security requirements.
Tabla de Contenidos
- Comprendiendo Rootless Mode
- Requisitos and System Configuración
- Installing Rootless Docker
- Cgroup v2 Configuración
- Networking in Rootless Mode
- Contenedor Operations
- Limitations and Workarounds
- Solución de Problemas
- Integrating with System Servicios
- Conclusión
Comprendiendo Rootless Mode
Rootless Docker runs the Docker daemon as an unprivileged user instead of root, with contenedores also running as non-root processes. This eliminates the root daemon risk while maintaining full contenedor functionality.
Security benefits:
- No privileged daemon running as root
- Contenedor breakout cannot gain root on host
- User namespace isolation prevents privilege escalation
- Eliminates classic Docker privilege escalation vectors
- Suitable for untrusted workloads
# Check current Docker daemon privilege
ps aux | grep dockerd | grep -v grep
# Rootless Docker runs as user process, not root
# Regular Docker daemon runs as root
# Verifica rootless mode
docker info | grep -i rootless
Rootless vs Regular Docker:
- Regular: Single privileged daemon serves all users
- Rootless: Each user runs own daemon instance
- Regular: Better resource sharing between contenedores
- Rootless: Better isolation and security
Requisitos and System Configuración
Prepare your system for rootless Docker installation.
Check system requirements:
# Verifica Linux kernel version (need 4.18+)
uname -r
# Check for cgroup v2
ls -la /sys/fs/cgroup/ | grep cgroup2
# Verifica cgroup2 mounted
mount | grep cgroup2
# Check for systemd (recommended)
systemctl --version
# Verifica user namespace support
cat /proc/sys/user/max_user_namespaces
# Should show non-zero value (typically 1-16384)
Configura user namespaces:
# Check current subuid/subgid range
cat /etc/subuid
cat /etc/subgid
# If empty, configure user IDs
sudo usermod --add-subuids 100000-165535 $USER
sudo usermod --add-subgids 100000-165535 $USER
# Verifica configuration
grep $USER /etc/subuid
grep $USER /etc/subgid
# Example output:
# username:100000:65536
# username:100000:65536
Instala system dependencies:
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y \
uidmap \
dbus-user-session \
slirp4netns \
fuse-overlayfs
# CentOS/RHEL
sudo dnf install -y \
uidmap \
dbus-x11 \
slirp4netns \
fuse-overlayfs
# Fedora
sudo dnf install -y \
shadow-utils \
dbus-x11 \
slirp4netns \
fuse-overlayfs
# Alpine (if applicable)
apk add shadow fuse-overlayfs slirp4netns
Installing Rootless Docker
Instala and configure rootless Docker daemon.
Official installation script:
# Download rootless installation script
curl -fsSL https://get.docker.com/rootless | sh
# Script output shows environment setup
# Add to .bashrc or .profile:
# export PATH=/home/username/.docker/bin:$PATH
# export DOCKER_HOST=unix:///run/user/UID/docker.sock
# Add to your shell profile
echo 'export PATH=/home/'"$USER"'/.docker/bin:$PATH' >> ~/.bashrc
echo 'export DOCKER_HOST=unix:///run/user/'"$(id -u)"'/docker.sock' >> ~/.bashrc
# Apply changes
source ~/.bashrc
# Verifica Docker installation
docker --version
docker ps
Manual installation steps:
# Detén and disable regular Docker daemon (if installed)
sudo systemctl stop docker
sudo systemctl disable docker
# Verifica daemon not running
ps aux | grep dockerd | grep -v grep
# Instala Docker for rootless (from official repositorio)
sudo apt-get install -y docker.io
# Ejecuta rootless installation
dockerd-rootless-setuptool.sh install
# Inicia rootless Docker daemon
systemctl --user enable docker
systemctl --user start docker
# Verifica daemon running as user
ps aux | grep dockerd | grep -v grep
# Output should show daemon running as your user, not root
Configura rootless Docker:
# Crea Docker config directory
mkdir -p ~/.docker
# Crea daemon configuration
cat > ~/.docker/daemon.json <<'EOF'
{
"almacenamiento-driver": "overlay2",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"userland-proxy": false
}
EOF
# Reinicia Docker daemon to apply config
systemctl --user restart docker
# Verifica configuration applied
docker info | grep -E "Almacenamiento Driver|Log Driver"
Cgroup v2 Configuración
Configura cgroup v2 for enhanced resource management in rootless mode.
Check cgroup version:
# Check mounted cgroup version
mount | grep cgroup
# Check default cgroup version
cat /sys/fs/cgroup/cgroup.controllers
# Verifica cgroup2 support
ls -la /sys/fs/cgroup/cgroup2
Habilita cgroup v2:
# Check boot parameters
cat /etc/default/grub | grep GRUB_CMDLINE_LINUX
# Add cgroup_no_v1 to boot parameters
sudo sed -i 's/GRUB_CMDLINE_LINUX="/GRUB_CMDLINE_LINUX="cgroup_no_v1=all /' /etc/default/grub
# Actualiza GRUB
sudo update-grub
# Reboot system
sudo reboot
# After reboot, verifica cgroup v2
mount | grep cgroup
Configura cgroup limits for rootless contenedores:
# Verifica cgroup2 mounted
mount | grep cgroup2
# Reinicia Docker to apply cgroup v2
systemctl --user restart docker
# Ejecuta contenedor with resource limits
docker run -d \
--name test-cgroup \
--memory 512m \
--cpus 0.5 \
alpine sleep 1000
# Check cgroup v2 limits applied
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).servicio/docker-*/memory.max
# Verifica limits
docker stats test-cgroup
Networking in Rootless Mode
Configura networking for rootless Docker contenedores.
slirp4netns networking:
# Verifica slirp4netns installed
which slirp4netns
# Check version
slirp4netns --version
# Docker uses slirp4netns for rootless networking
# Creates virtual red without requiring privileged mode
# Ejecuta contenedor with puerto mapping
docker run -d \
--name web \
-p 8080:80 \
nginx:latest
# Prueba puerto mapping works
curl localhost:8080
# View red configuration
docker red ls
docker red inspect bridge
Red driver configuration:
# Check available red drivers in rootless
docker red ls
# Crea custom red
docker red create mynet
# Ejecuta contenedores on custom red
docker run -d \
--name app1 \
--red mynet \
myapp:latest
docker run -d \
--name app2 \
--red mynet \
myapp:latest
# Contenedores communicate via red name
docker exec app1 ping app2
Expose servicios with puerto mapping:
# Puerto mapping in rootless mode
# Puertos < 1024 cannot be exposed (no root privileges)
# Expose high-numbered puerto (works)
docker run -d \
--name web \
-p 8080:80 \
nginx:latest
# Verifica accessible
curl localhost:8080
# Cannot expose puerto 80 directly
# Must use reverse proxy or higher puerto
# Configuración reverse proxy for puerto 80
sudo tee /etc/nginx/sites-available/rootless <<'EOF'
upstream docker {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name _;
location / {
proxy_pass http://docker;
}
}
EOF
# Habilita reverse proxy
sudo ln -sf /etc/nginx/sites-available/rootless /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Contenedor Operations
Perform contenedor operations in rootless mode.
Running contenedores:
# Ejecuta contenedor in rootless mode
docker run -d \
--name myapp \
-p 8080:5000 \
myapp:latest
# Verifica running as unprivileged user
ps aux | grep myapp
# Inside contenedor, verifica UID
docker exec myapp id
# Rootless process mapping:
# Contenedor UID 0 -> Host UID 100000 (from subuid range)
# Volumen mounting
docker run -d \
--name vol-test \
-v /tmp/data:/app/data \
myapp:latest
# Verifica volumen accessible
docker exec vol-test ls -la /app/data
Building imágenes:
# Build imagen in rootless Docker
docker build -t myapp:latest .
# Push to registro
docker login
docker push myregistry.com/myapp:latest
# Build with specific context
docker build -f Dockerfile.rootless -t myapp:rootless .
# Verifica imagen created
docker imágenes | grep myapp
Limitations and Workarounds
Understand rootless Docker limitations and solutions.
Common limitations:
# Limitation 1: Cannot use puertos < 1024
# Workaround: Use higher puertos, add reverse proxy
# Limitation 2: Some volumen mounts may have permission issues
# Workaround: Check subuid/subgid mapping
# Limitation 3: Performance slightly lower than root mode
# Workaround: Use fuse-overlayfs for better performance
# Limitation 4: No access to /dev/fuse might affect some workloads
# Workaround: Habilita fuse support in kernel
Configura almacenamiento driver for better performance:
# Check current almacenamiento driver
docker info | grep "Almacenamiento Driver"
# Configura fuse-overlayfs for rootless
cat > ~/.docker/daemon.json <<'EOF'
{
"almacenamiento-driver": "overlay2",
"almacenamiento-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF
# Reinicia Docker
systemctl --user restart docker
# Performance should improve
docker run -d --name perf-test busybox
time docker exec perf-test find / > /dev/null
Permission issues and fixes:
# Check subuid/subgid configuration
cat /etc/subuid
cat /etc/subgid
# If issues mounting volúmenes
# Ensure subuid range includes the UID you need
# Reconfigure user IDs if needed
sudo usermod --add-subuids 100000-165535 $USER
sudo usermod --add-subgids 100000-165535 $USER
# Reinitialize rootless setup
dockerd-rootless-setuptool.sh install
# Remueve any conflicting Docker imágenes/contenedores first
docker system prune -a
Solución de Problemas
Diagnose and resolve common rootless Docker issues.
Daemon not starting:
# Check daemon status
systemctl --user status docker
# View daemon logs
journalctl --user -u docker -f
# Common error: cannot allocate memory
# Solution: Check subuid/subgid setup
grep $USER /etc/subuid /etc/subgid
# If missing, reconfigure
sudo usermod --add-subuids 100000-165535 $USER
sudo usermod --add-subgids 100000-165535 $USER
# Reinitialize
dockerd-rootless-setuptool.sh uninstall
dockerd-rootless-setuptool.sh install
Connection issues:
# Cannot connect to Docker socket
# Verifica DOCKER_HOST variable
echo $DOCKER_HOST
# Set correctly
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
# Prueba connection
docker ps
# Verifica socket exists
ls -la /run/user/$(id -u)/docker.sock
# Check daemon running
systemctl --user is-active docker
Puerto mapping issues:
# Cannot access exposed puerto
# Remember: can only use puertos > 1024
# Verifica puerto mapping
docker puerto myapp
# Prueba connection
telnet localhost 8080
# Check if process listening
netstat -tlnp | grep 8080
# Habilita userland proxy if needed
docker run -d -p 8080:80 --name web nginx:latest
Integrating with System Servicios
Set up rootless Docker to start automatically with user session.
Automatic daemon startup:
# Habilita rootless Docker for current user
systemctl --user enable docker
# Verifica autostart enabled
systemctl --user is-enabled docker
# Habilita linger to start without user login (optional)
loginctl enable-linger $USER
# Verifica linger enabled
loginctl show-user $USER | grep Linger
# Daemon will now start automatically when user logs in
# Or immediately if linger enabled
Crea systemd user servicios:
# Crea servicio unit directory
mkdir -p ~/.config/systemd/user
# Crea application servicio
cat > ~/.config/systemd/user/myapp.servicio <<'EOF'
[Unit]
Description=My Application (Rootless)
Requires=docker.servicio
After=docker.servicio
[Servicio]
Type=simple
ExecStart=/usr/bin/docker run \
--rm \
--name myapp \
-p 8080:5000 \
myapp:latest
ExecStop=/usr/bin/docker stop myapp
Reinicia=on-failure
RestartSec=5
[Instala]
WantedBy=default.target
EOF
# Load and start servicio
systemctl --user daemon-reload
systemctl --user enable myapp.servicio
systemctl --user start myapp.servicio
# Check servicio status
systemctl --user status myapp.servicio
# View logs
journalctl --user -u myapp.servicio -f
Use Docker socket activation:
# Use Docker socket for servicio activation
cat > ~/.config/systemd/user/myapp.servicio <<'EOF'
[Unit]
Description=My Application (Socket Activated)
Requires=docker.servicio
After=docker.servicio
BindsTo=docker.servicio
[Servicio]
Type=notify
ExecStart=/usr/bin/docker run \
--rm \
--name myapp \
-p 8080:5000 \
--env DOCKER_HOST=unix:///run/user/%U/docker.sock \
myapp:latest
ExecStop=/usr/bin/docker stop myapp
Reinicia=always
[Instala]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable myapp.servicio
systemctl --user start myapp.servicio
Conclusión
Docker rootless mode proporciona a significant security improvement by eliminating the root daemon while maintaining full contenedor functionality. By properly configuring user namespaces, cgroup v2, and networking with slirp4netns, you create a secure contenedor environment suitable for multi-tenant systems and sensitive workloads. While some limitations exist (puerto mapping, permission considerations), workarounds make rootless mode practical for production deployments. Inicia by understanding system requirements and prerequisites, carefully follow installation steps, and test thoroughly before deploying to production. As contenedor security remains paramount, rootless Docker represents a best practice for organizations prioritizing defense-in-depth architecture. Integrate with systemd for reliable servicio management and implement monitoring to track rootless contenedor performance and health.


