Docker Rootless 無根模式設定

Docker Rootless Mode Configuration

Rootless 模式概述

Docker Rootless 模式允許使用者在不需要 root 權限的情況下執行 Docker daemon 和容器。這種模式大幅提升了系統安全性,因為即使容器或 daemon 被入侵,攻擊者也無法獲得主機的 root 權限。

為什麼需要 Rootless 模式?

傳統的 Docker 安裝需要 root 權限來執行 daemon,這帶來了以下安全風險:

  • 容器逃逸攻擊:若容器被入侵,攻擊者可能獲得主機 root 權限
  • Daemon 漏洞:Docker daemon 的安全漏洞可能導致系統被完全控制
  • 過度授權:將使用者加入 docker 群組等同於授予 root 權限

Rootless 模式的優勢

  • 降低攻擊面:容器和 daemon 以普通使用者身份運行
  • 命名空間隔離:使用 user namespace 提供額外的隔離層
  • 符合最小權限原則:遵循安全最佳實踐
  • 多租戶環境友善:適合共享主機環境

系統需求

在安裝 Rootless Docker 之前,請確認您的系統符合以下需求:

作業系統支援

  • Ubuntu 20.04 或更新版本
  • Debian 10 或更新版本
  • CentOS 8 / RHEL 8 或更新版本
  • Fedora 32 或更新版本

核心需求

1
2
3
4
5
6
# 確認核心版本(建議 5.11 以上)
uname -r

# 確認 user namespace 支援
cat /proc/sys/kernel/unprivileged_userns_clone
# 輸出應為 1

必要套件

  • uidmap:提供 newuidmap 和 newgidmap 工具
  • dbus-user-session:用於 systemd 使用者服務
  • slirp4netnsvpnkit:用於網路功能
  • fuse-overlayfs:用於檔案系統層疊(建議安裝)

安裝前置作業

1. 安裝必要套件

Ubuntu / Debian:

1
2
sudo apt-get update
sudo apt-get install -y uidmap dbus-user-session slirp4netns fuse-overlayfs

CentOS / RHEL:

1
sudo dnf install -y shadow-utils fuse-overlayfs slirp4netns

2. 設定 subuid 和 subgid

確認使用者已配置從屬 UID 和 GID 範圍:

1
2
3
4
5
6
# 檢查設定
grep $USER /etc/subuid
grep $USER /etc/subgid

# 若無輸出,手動新增(以 username 為例)
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER

3. 啟用 user namespace(若未啟用)

1
2
3
4
5
6
7
8
9
# 檢查狀態
cat /proc/sys/kernel/unprivileged_userns_clone

# 若輸出為 0,執行以下指令啟用
sudo sysctl -w kernel.unprivileged_userns_clone=1

# 永久啟用
echo 'kernel.unprivileged_userns_clone=1' | sudo tee /etc/sysctl.d/99-rootless.conf
sudo sysctl --system

4. 移除現有的 Docker 安裝(如有需要)

若您已安裝標準版 Docker,可以選擇移除或與 Rootless 版本共存:

1
2
3
4
5
# 停止現有的 Docker 服務
sudo systemctl stop docker docker.socket

# 可選:完全移除
sudo apt-get remove docker-ce docker-ce-cli containerd.io

安裝 Rootless Docker

方法一:使用官方安裝腳本

1
2
3
4
# 下載並執行安裝腳本
curl -fsSL https://get.docker.com/rootless | sh

# 安裝完成後會顯示環境變數設定指引

方法二:手動安裝

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 下載 Rootless Docker 套件
curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-24.0.7.tgz -o docker.tgz
curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-rootless-extras-24.0.7.tgz -o docker-rootless-extras.tgz

# 解壓縮
tar xzf docker.tgz
tar xzf docker-rootless-extras.tgz

# 移動到使用者目錄
mkdir -p ~/bin
mv docker/* ~/bin/
mv docker-rootless-extras/* ~/bin/

# 安裝
~/bin/dockerd-rootless-setuptool.sh install

設定環境變數

安裝完成後,需要設定環境變數以便系統找到 Rootless Docker:

新增到 Shell 設定檔

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 編輯 ~/.bashrc 或 ~/.zshrc
cat >> ~/.bashrc << 'EOF'

# Docker Rootless 設定
export PATH=$HOME/bin:$PATH
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
EOF

# 套用變更
source ~/.bashrc

啟動 Docker daemon

1
2
3
4
5
6
7
8
# 使用 systemd 使用者服務
systemctl --user start docker

# 設定開機自動啟動
systemctl --user enable docker

# 確保使用者登出後服務繼續運行
sudo loginctl enable-linger $USER

驗證安裝

1
2
3
4
5
6
7
8
# 確認 Docker 版本
docker version

# 確認以 Rootless 模式運行
docker info | grep -i rootless

# 測試執行容器
docker run hello-world

限制與注意事項

Rootless 模式雖然提升了安全性,但也有一些限制需要了解:

功能限制

功能支援狀態說明
特權容器有限支援--privileged 功能受限
AppArmor不支援無法套用 AppArmor 設定檔
Checkpoint不支援無法使用容器快照功能
Overlay 網路不支援需使用其他網路驅動程式
低於 1024 的連接埠預設不支援需額外設定

連接埠綁定限制

預設情況下,非 root 使用者無法綁定 1024 以下的連接埠:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 方法一:使用 sysctl 允許非特權連接埠綁定
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80

# 永久設定
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# 方法二:使用連接埠轉發
docker run -p 8080:80 nginx
# 然後使用 iptables 或 nginx 反向代理轉發 80 -> 8080

資源限制

1
2
3
4
5
6
7
# cgroup v2 環境下設定資源限制
docker run --memory=512m --cpus=1 nginx

# 若使用 cgroup v1,需要額外設定
# 將 cgroup 委派給使用者
sudo mkdir -p /sys/fs/cgroup/cpu/user.slice/user-$(id -u).slice
sudo chown -R $USER:$USER /sys/fs/cgroup/cpu/user.slice/user-$(id -u).slice

網路設定

Rootless Docker 使用 slirp4netns 或 vpnkit 提供網路功能:

slirp4netns 設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 查看 slirp4netns 版本
slirp4netns --version

# 自訂 MTU 設定(在 ~/.config/docker/daemon.json)
mkdir -p ~/.config/docker
cat > ~/.config/docker/daemon.json << 'EOF'
{
  "mtu": 1500
}
EOF

容器間通訊

1
2
3
4
5
6
7
8
9
# 建立使用者定義網路
docker network create my-network

# 在同一網路中啟動多個容器
docker run -d --name web --network my-network nginx
docker run -d --name db --network my-network postgres

# 容器間可透過名稱互相存取
docker exec web ping db

對外服務存取

1
2
3
4
5
# 映射連接埠
docker run -d -p 8080:80 --name webserver nginx

# 確認綁定
curl http://localhost:8080

儲存設定

儲存驅動程式

Rootless Docker 支援以下儲存驅動程式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 查看目前使用的儲存驅動程式
docker info | grep "Storage Driver"

# 使用 fuse-overlayfs(推薦)
cat > ~/.config/docker/daemon.json << 'EOF'
{
  "storage-driver": "fuse-overlayfs"
}
EOF

# 重新啟動 daemon
systemctl --user restart docker

資料目錄

1
2
3
4
5
6
7
8
# Rootless Docker 的資料目錄位於
ls ~/.local/share/docker

# 包含以下子目錄
# - containers: 容器資料
# - image: 映像檔層
# - volumes: 磁碟區
# - network: 網路設定

磁碟區管理

1
2
3
4
5
6
7
8
# 建立磁碟區
docker volume create my-data

# 使用磁碟區
docker run -v my-data:/data nginx

# 磁碟區位置
ls ~/.local/share/docker/volumes/my-data/_data

與標準 Docker 共存

您可以在同一系統上同時運行標準 Docker 和 Rootless Docker:

設定方式

1
2
3
4
5
6
7
8
9
# 標準 Docker(需要 root)
sudo docker ps

# Rootless Docker(使用者層級)
docker ps  # 使用 DOCKER_HOST 環境變數

# 明確指定 socket
docker -H unix://$XDG_RUNTIME_DIR/docker.sock ps  # Rootless
docker -H unix:///var/run/docker.sock ps          # 標準版(需 sudo)

使用 context 管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 建立 Rootless context
docker context create rootless --docker "host=unix://$XDG_RUNTIME_DIR/docker.sock"

# 建立標準 Docker context
docker context create default-root --docker "host=unix:///var/run/docker.sock"

# 切換 context
docker context use rootless
docker context use default-root

# 列出所有 context
docker context ls

最佳實踐

  1. 開發環境:使用 Rootless Docker 進行日常開發
  2. CI/CD 環境:根據需求選擇適合的模式
  3. 生產環境:評估安全需求後決定

疑難排解

常見問題

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 問題:無法啟動 daemon
# 解決:檢查 XDG_RUNTIME_DIR
echo $XDG_RUNTIME_DIR
# 應輸出類似 /run/user/1000

# 問題:網路連線失敗
# 解決:確認 slirp4netns 已安裝
which slirp4netns

# 問題:儲存空間不足
# 解決:清理未使用的資源
docker system prune -a

日誌查看

1
2
3
4
5
# 查看 daemon 日誌
journalctl --user -u docker

# 即時追蹤日誌
journalctl --user -u docker -f

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy