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 使用者服務slirp4netns 或 vpnkit:用於網路功能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
|
最佳實踐
- 開發環境:使用 Rootless Docker 進行日常開發
- CI/CD 環境:根據需求選擇適合的模式
- 生產環境:評估安全需求後決定
疑難排解
常見問題
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
|
參考資料