Docker 非root用户完整安装部署文档

注意:本文档中 <PLACEHOLDER> 格式(如 <YOUR_PROXY_HOST:PORT><USERNAME><START_UID>)均为占位符,部署时需替换为实际环境的值。


1. 背景与目标

在 openEuler aarch64 服务器上,以普通用户身份(无需 root 权限)安装 Docker,
所有文件(二进制、配置、数据、运行时文件)全部放在 /usr1/xjt_docker/ 目录下,
不影响系统全局 Docker 及其他用户。


2. 环境信息

项目
操作系统 openEuler 20.03 (LTS-SP3)
内核版本 4.19.90-2112.8.0.0131.oe1.aarch64
CPU 架构 aarch64 (ARM64)
目标用户 xjt_docker (uid=54323, gid=54326)
安装根目录 /usr1/xjt_docker/
网络代理 <PROXY_HOST:PORT>(系统环境变量 $HTTP_PROXY,拉取镜像必需)
Docker 版本 29.6.1
存储驱动 vfs(因 kernel 4.19 不兼容 overlay)
网络模式 slirp4netns(用户态网络,无需 root 配置网桥)

3. 前置校验

以下条件需要在安装前确认满足,由 root 用户执行(一次性操作,之后不再需要 root)。

3.1 检查 subuid/subgid 是否配置

Rootless Docker 依赖用户命名空间(user namespaces)进行权限隔离,
必须为安装用户分配从属 UID/GID 范围。

# 检查是否已配置(如无输出则未配置)
grep <USERNAME> /etc/subuid /etc/subgid

期望输出类似:

/etc/subuid:<USERNAME>:<START_UID>:65536
/etc/subgid:<USERNAME>:<START_UID>:65536

如果未配置,需 root 执行:

# 为指定用户分配 65536 个从属 ID(选择一个较大的起始 UID 避免冲突)
usermod --add-subuids <START_UID>-<END_UID> --add-subgids <START_UID>-<END_UID> <USERNAME>

说明:起始 UID 应选择较大值避免与其他用户冲突;65536 是 Docker 要求的标准分配数量。

3.2 检查内核是否启用用户命名空间

# 输出 >= 0 表示已启用
sysctl user.max_user_namespaces

期望输出 user.max_user_namespaces >= 0(默认通常为 0 即无限制)。

3.3 检查磁盘空间

df -h /usr1

二进制文件约需 240MB,镜像和容器数据视使用情况而定,建议至少保留 10GB 可用空间。

3.4 检查网络代理

Rootless Docker 拉取镜像必须通过代理。先用以下命令确认代理地址:

# 检查系统已有的代理环境变量
env | grep -i proxy

如果无输出,则需联系管理员确认代理地址。确认代理后可测试连通性:

curl -x $HTTP_PROXY -I https://registry-1.docker.io 2>&1 | head -5

确认可通过代理访问 Docker Hub。


4. 目录规划

/usr1/xjt_docker/
├── docker-bin/               # 所有 Docker 相关二进制文件(~236MB)
│   ├── docker/               # docker, dockerd, containerd, runc 等
│   ├── rootlesskit           # Rootless 容器管理器
│   └── slirp4netns           # 用户态网络实现
├── docker-config/            # Docker 守护进程配置
│   └── daemon.json
├── docker-data/              # 镜像、容器数据持久化目录
├── docker-run/               # 运行时文件(socket, PID 等)
├── start-docker.sh           # 启动脚本
├── stop-docker.sh            # 停止脚本
└── env.sh                    # 环境变量(备用手动加载)

5. 安装步骤

以下所有步骤以 xjt_docker 用户身份执行,无需 root。

5.1 创建目录结构

mkdir -p /usr1/xjt_docker/{docker-bin/docker,docker-config,docker-data,docker-run}

5.2 下载 Docker 静态二进制包

必须确认架构后再选择下载地址:

uname -m
# 输出 aarch64 → 用 arm64 链接
# 输出 x86_64  → 用 amd64 链接

从 Docker 官方下载静态二进制包:

# 先设置代理(替换为实际代理地址)
export HTTP_PROXY=<YOUR_PROXY_HOST:PORT>
export HTTPS_PROXY=<YOUR_PROXY_HOST:PORT>

# 下载 Docker 29.6.1(按架构选链接)
# aarch64:
wget -O /tmp/docker.tgz \
  https://download.docker.com/linux/static/stable/aarch64/docker-29.6.1.tgz
# x86_64:
# wget -O /tmp/docker.tgz \
#   https://download.docker.com/linux/static/stable/x86_64/docker-29.6.1.tgz

# 解压到指定目录
tar -xzf /tmp/docker.tgz -C /usr1/xjt_docker/docker-bin/docker/ --strip-components=1

# 确保可执行权限
chmod +x /usr1/xjt_docker/docker-bin/docker/*

# 验证
/usr1/xjt_docker/docker-bin/docker/docker --version

功能:解压后包含 docker(客户端)、dockerd(守护进程)、containerd(容器运行时)、
runc(OCI 运行时)、docker-proxy 等全部二进制文件。

5.3 安装 slirp4netns(用户态网络)

Rootless Docker 无法操作宿主机 iptables/网桥,需要 slirp4netns 提供容器网络。

# 下载预编译 aarch64 版本
wget -O /usr1/xjt_docker/docker-bin/slirp4netns \
  https://github.com/rootless-containers/slirp4netns/releases/download/v1.3.4/slirp4netns-aarch64

chmod +x /usr1/xjt_docker/docker-bin/slirp4netns

# 验证
/usr1/xjt_docker/docker-bin/slirp4netns --version

备选:如果 GitHub 被代理拦截无法下载,可在能访问 GitHub 的机器上下载后 scp 传到目标机器,或通过其他渠道获取二进制文件。只要最终把可执行文件放到 docker-bin/slirp4netns 即可。

5.4 安装 rootlesskit

rootlesskit 负责创建用户命名空间,并将 Dockerd 运行在其中。

方式一:Go 编译(推荐,避免平台/版本兼容问题)

# 下载 Go(如系统没有 Go,用 golang.google.cn 国内镜像)
wget https://golang.google.cn/dl/go1.22.5.linux-arm64.tar.gz -O /tmp/go.tar.gz
mkdir -p /usr1/xjt_docker/go /usr1/xjt_docker/go-home
tar -xzf /tmp/go.tar.gz -C /usr1/xjt_docker/go/ --strip-components=1

export PATH=/usr1/xjt_docker/go/bin:$PATH
export GOPATH=/usr1/xjt_docker/go-home
export GOPROXY=https://goproxy.cn,direct              # 国内 Go 代理,避免 GitHub 被墙
export HTTP_PROXY=<YOUR_PROXY_HOST:PORT>               # 替换为实际地址
export HTTPS_PROXY=<YOUR_PROXY_HOST:PORT>

# 编译安装 rootlesskit(自动拉取依赖)
go install github.com/rootless-containers/rootlesskit/v3/cmd/rootlesskit@latest

# 复制到 docker-bin
cp /usr1/xjt_docker/go-home/bin/rootlesskit /usr1/xjt_docker/docker-bin/rootlesskit

# 验证
/usr1/xjt_docker/docker-bin/rootlesskit --version

方式二:下载预编译二进制(需直接访问 GitHub)

wget -O /usr1/xjt_docker/docker-bin/rootlesskit \
  https://github.com/rootless-containers/rootlesskit/releases/download/v3.0.1/rootlesskit-aarch64

chmod +x /usr1/xjt_docker/docker-bin/rootlesskit

功能:rootlesskit 是 Rootless 模式的核心组件,它利用 user_namespaces 创建
隔离环境,使 dockerd 以 rootless 方式运行。

踩坑提醒:如果 GitHub 被代理拦截,方式二会失败,必须用方式一(Go 编译 + GOPROXY 国内代理)。

5.5 配置 Docker 守护进程 (daemon.json)

创建配置文件:

cat > /usr1/xjt_docker/docker-config/daemon.json << 'EOF'
{
    "bridge": "none",
    "iptables": false,
    "ip6tables": false,
    "registry-mirrors": ["https://docker.m.daocloud.io"]
}
EOF

各配置项说明

配置项 说明
"bridge": "none" 禁用默认 docker0 网桥,rootless 下无法创建网桥
"iptables": false 禁用 iptables 规则操作,rootless 无权限修改 iptables
"ip6tables": false 同上,禁用 IPv6 iptables
"registry-mirrors" 国内镜像加速,避免直接从 Docker Hub 拉取被拦截

5.6 创建启动脚本

cat > /usr1/xjt_docker/start-docker.sh << 'SCRIPT'
#!/bin/bash
# Rootless Docker 启动脚本
# 功能:通过 rootlesskit 创建用户命名空间,在其中启动 dockerd

DOCKER_BIN=/usr1/xjt_docker/docker-bin
DOCKER_DATA=/usr1/xjt_docker/docker-data
DOCKER_RUN=/usr1/xjt_docker/docker-run
DOCKER_CONFIG=/usr1/xjt_docker/docker-config

# 设置运行时环境变量
export PATH=$DOCKER_BIN/docker:$DOCKER_BIN:$PATH
export DOCKER_HOST=unix://$DOCKER_RUN/docker.sock
export XDG_RUNTIME_DIR=$DOCKER_RUN
export HTTP_PROXY=<YOUR_PROXY_HOST:PORT>
export HTTPS_PROXY=<YOUR_PROXY_HOST:PORT>
export NO_PROXY=localhost,127.0.0.1,.local

mkdir -p $DOCKER_RUN $DOCKER_DATA

exec $DOCKER_BIN/rootlesskit \
    --net=slirp4netns \
    --slirp4netns-binary=$DOCKER_BIN/slirp4netns \
    --disable-host-loopback \
    --copy-up=/etc \
    --copy-up=/run \
    sh -c "
        # 清理主机残留的 docker/containerd 符号链接(避免与命名空间内文件冲突)
        rm -rf /run/docker /run/docker.pid /run/docker.sock /run/containerd 2>/dev/null
        mkdir -p /run/docker/plugins /run/containerd
        exec $DOCKER_BIN/docker/dockerd \
            --rootless \
            --data-root=$DOCKER_DATA \
            --exec-root=$DOCKER_RUN \
            --config-file=$DOCKER_CONFIG/daemon.json \
            --storage-driver=vfs \
            --pidfile=$DOCKER_RUN/docker.pid
    "
SCRIPT

chmod +x /usr1/xjt_docker/start-docker.sh

关键参数说明

参数 功能
--net=slirp4netns 使用 slirp4netns 用户态网络驱动
--disable-host-loopback 禁用宿主机回环网卡映射,避免端口冲突
--copy-up=/etc 将宿主 /etc 复制到命名空间(dns 解析等需要)
--copy-up=/run 将宿主 /run 复制到命名空间
--rootless 告知 dockerd 以 rootless 模式运行
--storage-driver=vfs 使用 vfs 存储驱动(兼容 kernel 4.19)
sh -c "..." 在命名空间内先清理冲突文件,再启动 dockerd

5.7 创建停止脚本

cat > /usr1/xjt_docker/stop-docker.sh << 'SCRIPT'
#!/bin/bash
# Rootless Docker 停止脚本
# 功能:通过 PID 文件优雅终止 Docker 进程

DOCKER_RUN=/usr1/xjt_docker/docker-run

echo "Stopping rootless Docker..."
if [ -f "$DOCKER_RUN/docker.pid" ]; then
    kill $(cat "$DOCKER_RUN/docker.pid") 2>/dev/null
fi
sleep 2

# 兜底:清理残留进程
pkill -f "docker-bin.*rootlesskit" 2>/dev/null
pkill -f "docker-bin.*containerd" 2>/dev/null
echo "Docker stopped."
SCRIPT

chmod +x /usr1/xjt_docker/stop-docker.sh

5.8 配置用户环境变量

将 Docker 环境变量写入 ~/.bashrc,每次登录自动生效。

注意:以下操作会覆盖 ~/.bashrc,如果已有重要配置,请手动追加内容而非覆盖。

cat > ~/.bashrc << 'EOF'
# Rootless Docker 环境变量
export PATH=/usr1/xjt_docker/docker-bin/docker:/usr1/xjt_docker/docker-bin:$PATH
export DOCKER_HOST=unix:///usr1/xjt_docker/docker-run/docker.sock
export DOCKER_CONFIG=/usr1/xjt_docker/docker-config
export XDG_RUNTIME_DIR=/usr1/xjt_docker/docker-run

# 代理(Docker 拉取镜像需要,替换为实际代理地址)
export HTTP_PROXY=<YOUR_PROXY_HOST:PORT>
export HTTPS_PROXY=<YOUR_PROXY_HOST:PORT>
export NO_PROXY=localhost,127.0.0.1,.local
EOF

# 同时创建 .bash_profile,确保 login shell 也加载 .bashrc
cat > ~/.bash_profile << 'EOF'
if [ -f ~/.bashrc ]; then
    source ~/.bashrc
fi
EOF

# 立即生效:启动新的 login shell(推荐,避免 PATH 缓存干扰)
exec bash -l
# 或手动加载:source ~/.bashrc && hash -r

环境变量说明

变量 作用
PATH docker 命令加入可执行搜索路径
DOCKER_HOST 指定 Docker 客户端连接的 socket 路径
DOCKER_CONFIG Docker CLI 配置文件目录
XDG_RUNTIME_DIR 用户运行时目录(非 systemd 环境下需要手动指定)
HTTP_PROXY/HTTPS_PROXY 代理地址,拉取镜像时使用
NO_PROXY 不走代理的地址列表

6. 启动与验证

6.1 启动 Docker

# 后台启动
nohup /usr1/xjt_docker/start-docker.sh > /dev/null 2>&1 &

# 查看进程
ps aux | grep docker

期望看到 rootlesskitdockerdcontainerd 进程。

6.2 验证运行状态

# 查看客户端和服务端版本
docker version

# 查看 Docker 引擎详细信息
docker info

期望输出中应包含:

  • Server Version: 29.6.1
  • Storage Driver: vfs
  • NetworkDriver: slirp4netns
  • rootlesskit

6.3 运行测试容器

docker run --rm hello-world

期望输出:

Hello from Docker!
This message shows that your installation appears to be working correctly.

7. 日常使用

7.1 启动/停止

# 启动
nohup /usr1/xjt_docker/start-docker.sh > /dev/null 2>&1 &

# 停止
/usr1/xjt_docker/stop-docker.sh

7.2 常用命令速查

docker pull <镜像>        # 拉取镜像(仅支持 ARM64 架构)
docker run -it <镜像> bash # 运行容器
docker ps                  # 查看运行中的容器
docker ps -a               # 查看所有容器
docker images              # 查看本地镜像
docker stop <ID>           # 停止容器
docker rm <ID>             # 删除容器
docker rmi <镜像>          # 删除镜像
docker logs <ID>           # 查看容器日志
docker exec -it <ID> bash  # 进入运行中的容器

7.3 端口映射

Rootless 模式下无法使用低于 1024 的端口,映射示例:

# 正确:使用高端口
docker run -p 8080:80 nginx

# 错误:无法绑定 80 端口
docker run -p 80:80 nginx

7.4 磁盘空间监控

vfs 存储驱动不共享镜像层,磁盘占用较大,建议定期检查:

du -sh /usr1/xjt_docker/docker-data/
docker system df    # 查看 Docker 磁盘使用情况
docker system prune -a   # 清理未使用的镜像、容器、网络(谨慎操作)

8. 常见问题与排查

Q1:docker 命令找不到或执行了系统 Docker

原因:当前终端未加载 ~/.bashrc 中的环境变量。

解决

source ~/.bashrc      # 手动加载
exec bash -l          # 或启动新的 login shell

Q2:镜像拉取失败 (timeout / connection refused)

原因:代理未生效或 Docker Hub 不可达。

排查

echo $HTTP_PROXY      # 检查代理环境变量
curl -x $HTTP_PROXY https://registry-1.docker.io  # 测试代理到 Docker Hub 的连通性

解决:确认 ~/.bashrc 中代理地址正确,且 daemon.json 中配置了镜像加速。

Q3:容器启动报 iptables 错误

原因:rootless 模式无权限操作 iptables。

解决daemon.json 中已配置 "iptables": false,如果仍有报错,检查启动命令是否加载了正确的 daemon.json

Q4:overlay 存储驱动报错

原因:内核 4.19 不支持 rootless 下的 overlay。

解决:启动脚本中已通过 --storage-driver=vfs 强制使用 vfs 驱动,
镜像占用会偏大但功能完整。

Q5:容器内无法访问外网

原因:容器内未继承代理环境变量。

解决:运行容器时传入代理:

docker run -e HTTP_PROXY=$HTTP_PROXY -e HTTPS_PROXY=$HTTPS_PROXY <镜像>

Q6:重新登录后 docker 报 No such file or directory

原因DOCKER_HOST 指向的 socket 文件不存在(Docker 未启动)。

解决:先启动 Docker:

nohup /usr1/xjt_docker/start-docker.sh > /dev/null 2>&1 &

Q7:docker 命令报 /home/xxx/bin/docker: No such file or directory

原因:新旧 shell 会话混用,bash 缓存了旧的 docker 命令路径(hash table)。

解决:清除缓存并重新加载环境:

hash -r && source ~/.bashrc
# 或者直接启动新 shell
exec bash -l

Q8:GitHub 下载链接全部超时或被拒绝

原因:代理拦截了 GitHub 域名。

解决

  • slirp4netns:在能访问 GitHub 的机器上下载后 scp 到目标机器
  • rootlesskit:使用方式一(Go 编译 + GOPROXY=https://goproxy.cn,direct),Go 代理会自动走国内 CDN

Q9:如何确认系统代理地址?

原因:不同环境代理地址不同,需要先获取。

解决

env | grep -i proxy    # 查看当前环境变量中的代理
curl -x <代理地址> http://www.baidu.com  # 测试连通性

附录:快速部署清单

前提:已通过 3.4 节确认系统代理地址,并替换下方 <YOUR_PROXY_HOST:PORT> 为实际值。

# === 前置(需 root 执行一次) ===
# 配置 subuid/subgid(替换 `<START_UID>` `<USERNAME>` 为实际值)
usermod --add-subuids <START_UID>-<END_UID> --add-subgids <START_UID>-<END_UID> <USERNAME>

# === 以下全部以目标用户身份执行 ===
export HTTP_PROXY=<YOUR_PROXY_HOST:PORT>
export HTTPS_PROXY=<YOUR_PROXY_HOST:PORT>

# 1. 创建目录
mkdir -p /usr1/xjt_docker/{docker-bin/docker,docker-config,docker-data,docker-run}

# 2. 下载 Docker 二进制
wget -O /tmp/docker.tgz https://download.docker.com/linux/static/stable/aarch64/docker-29.6.1.tgz
tar -xzf /tmp/docker.tgz -C /usr1/xjt_docker/docker-bin/docker/ --strip-components=1
chmod +x /usr1/xjt_docker/docker-bin/docker/*

# 3. 下载 slirp4netns(GitHub 不可达则手动传)
wget -O /usr1/xjt_docker/docker-bin/slirp4netns \
  https://github.com/rootless-containers/slirp4netns/releases/download/v1.3.4/slirp4netns-aarch64
chmod +x /usr1/xjt_docker/docker-bin/slirp4netns

# 4. 编译 rootlesskit(需要 Go,用国内镜像避免 GitHub 被墙)
wget https://golang.google.cn/dl/go1.22.5.linux-arm64.tar.gz -O /tmp/go.tar.gz
mkdir -p /usr1/xjt_docker/go /usr1/xjt_docker/go-home
tar -xzf /tmp/go.tar.gz -C /usr1/xjt_docker/go/ --strip-components=1
export PATH=/usr1/xjt_docker/go/bin:$PATH
export GOPATH=/usr1/xjt_docker/go-home
export GOPROXY=https://goproxy.cn,direct
go install github.com/rootless-containers/rootlesskit/v3/cmd/rootlesskit@latest
cp /usr1/xjt_docker/go-home/bin/rootlesskit /usr1/xjt_docker/docker-bin/rootlesskit

# 5. 配置 daemon.json
cat > /usr1/xjt_docker/docker-config/daemon.json << 'EOF'
{
    "bridge": "none",
    "iptables": false,
    "ip6tables": false,
    "registry-mirrors": ["https://docker.m.daocloud.io"]
}
EOF

# 6. 创建启动/停止脚本并写入环境变量(参见 5.6 ~ 5.8 节完整内容)

# 7. 启动
nohup /usr1/xjt_docker/start-docker.sh > /dev/null 2>&1 &

# 8. 验证
exec bash -l
docker run --rm hello-world
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐