Docker部署-非root用户openEuler 20.03部署

📅 2026/7/1 2:51:21
Docker部署-非root用户openEuler 20.03部署
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.aarch64CPU 架构aarch64 (ARM64)目标用户xjt_docker (uid54323, gid54326)安装根目录/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 范围。# 检查是否已配置如无输出则未配置grepUSERNAME/etc/subuid /etc/subgid期望输出类似/etc/subuid:USERNAME:START_UID:65536 /etc/subgid:USERNAME:START_UID:65536如果未配置需root执行# 为指定用户分配 65536 个从属 ID选择一个较大的起始 UID 避免冲突usermod--add-subuidsSTART_UID-END_UID--add-subgidsSTART_UID-END_UIDUSERNAME说明起始 UID 应选择较大值避免与其他用户冲突65536是 Docker 要求的标准分配数量。3.2 检查内核是否启用用户命名空间# 输出 0 表示已启用sysctluser.max_user_namespaces期望输出user.max_user_namespaces 0默认通常为 0 即无限制。3.3 检查磁盘空间df-h/usr1二进制文件约需240MB镜像和容器数据视使用情况而定建议至少保留10GB可用空间。3.4 检查网络代理Rootless Docker 拉取镜像必须通过代理。先用以下命令确认代理地址# 检查系统已有的代理环境变量env|grep-iproxy如果无输出则需联系管理员确认代理地址。确认代理后可测试连通性curl-x$HTTP_PROXY-Ihttps://registry-1.docker.io21|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 官方下载静态二进制包# 先设置代理替换为实际代理地址exportHTTP_PROXYYOUR_PROXY_HOST:PORTexportHTTPS_PROXYYOUR_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-components1# 确保可执行权限chmodx /usr1/xjt_docker/docker-bin/docker/*# 验证/usr1/xjt_docker/docker-bin/docker/docker--version功能解压后包含docker客户端、dockerd守护进程、containerd容器运行时、runcOCI 运行时、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-aarch64chmodx /usr1/xjt_docker/docker-bin/slirp4netns# 验证/usr1/xjt_docker/docker-bin/slirp4netns--version备选如果 GitHub 被代理拦截无法下载可在能访问 GitHub 的机器上下载后 scp 传到目标机器或通过其他渠道获取二进制文件。只要最终把可执行文件放到docker-bin/slirp4netns即可。5.4 安装 rootlesskitrootlesskit 负责创建用户命名空间并将 Dockerd 运行在其中。方式一Go 编译推荐避免平台/版本兼容问题# 下载 Go如系统没有 Go用 golang.google.cn 国内镜像wgethttps://golang.google.cn/dl/go1.22.5.linux-arm64.tar.gz-O/tmp/go.tar.gzmkdir-p/usr1/xjt_docker/go /usr1/xjt_docker/go-hometar-xzf/tmp/go.tar.gz-C/usr1/xjt_docker/go/ --strip-components1exportPATH/usr1/xjt_docker/go/bin:$PATHexportGOPATH/usr1/xjt_docker/go-homeexportGOPROXYhttps://goproxy.cn,direct# 国内 Go 代理避免 GitHub 被墙exportHTTP_PROXYYOUR_PROXY_HOST:PORT# 替换为实际地址exportHTTPS_PROXYYOUR_PROXY_HOST:PORT# 编译安装 rootlesskit自动拉取依赖goinstallgithub.com/rootless-containers/rootlesskit/v3/cmd/rootlesskitlatest# 复制到 docker-bincp/usr1/xjt_docker/go-home/bin/rootlesskit /usr1/xjt_docker/docker-bin/rootlesskit# 验证/usr1/xjt_docker/docker-bin/rootlesskit--version方式二下载预编译二进制需直接访问 GitHubwget-O/usr1/xjt_docker/docker-bin/rootlesskit\https://github.com/rootless-containers/rootlesskit/releases/download/v3.0.1/rootlesskit-aarch64chmodx /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.jsonEOF { bridge: none, iptables: false, ip6tables: false, registry-mirrors: [https://docker.m.daocloud.io] } EOF各配置项说明配置项说明bridge: none禁用默认 docker0 网桥rootless 下无法创建网桥iptables: false禁用 iptables 规则操作rootless 无权限修改 iptablesip6tables: false同上禁用 IPv6 iptablesregistry-mirrors国内镜像加速避免直接从 Docker Hub 拉取被拦截5.6 创建启动脚本cat/usr1/xjt_docker/start-docker.shSCRIPT #!/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_HOSTunix://$DOCKER_RUN/docker.sock export XDG_RUNTIME_DIR$DOCKER_RUN export HTTP_PROXYYOUR_PROXY_HOST:PORT export HTTPS_PROXYYOUR_PROXY_HOST:PORT export NO_PROXYlocalhost,127.0.0.1,.local mkdir -p $DOCKER_RUN $DOCKER_DATA exec $DOCKER_BIN/rootlesskit \ --netslirp4netns \ --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-drivervfs \ --pidfile$DOCKER_RUN/docker.pid SCRIPTchmodx /usr1/xjt_docker/start-docker.sh关键参数说明参数功能--netslirp4netns使用 slirp4netns 用户态网络驱动--disable-host-loopback禁用宿主机回环网卡映射避免端口冲突--copy-up/etc将宿主/etc复制到命名空间dns 解析等需要--copy-up/run将宿主/run复制到命名空间--rootless告知 dockerd 以 rootless 模式运行--storage-drivervfs使用 vfs 存储驱动兼容 kernel 4.19sh -c ...在命名空间内先清理冲突文件再启动 dockerd5.7 创建停止脚本cat/usr1/xjt_docker/stop-docker.shSCRIPT #!/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. SCRIPTchmodx /usr1/xjt_docker/stop-docker.sh5.8 配置用户环境变量将 Docker 环境变量写入~/.bashrc每次登录自动生效。注意以下操作会覆盖~/.bashrc如果已有重要配置请手动追加内容而非覆盖。cat~/.bashrcEOF # Rootless Docker 环境变量 export PATH/usr1/xjt_docker/docker-bin/docker:/usr1/xjt_docker/docker-bin:$PATH export DOCKER_HOSTunix:///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_PROXYYOUR_PROXY_HOST:PORT export HTTPS_PROXYYOUR_PROXY_HOST:PORT export NO_PROXYlocalhost,127.0.0.1,.local EOF# 同时创建 .bash_profile确保 login shell 也加载 .bashrccat~/.bash_profileEOF if [ -f ~/.bashrc ]; then source ~/.bashrc fi EOF# 立即生效启动新的 login shell推荐避免 PATH 缓存干扰execbash-l# 或手动加载source ~/.bashrc hash -r环境变量说明变量作用PATH将docker命令加入可执行搜索路径DOCKER_HOST指定 Docker 客户端连接的 socket 路径DOCKER_CONFIGDocker CLI 配置文件目录XDG_RUNTIME_DIR用户运行时目录非 systemd 环境下需要手动指定HTTP_PROXY/HTTPS_PROXY代理地址拉取镜像时使用NO_PROXY不走代理的地址列表6. 启动与验证6.1 启动 Docker# 后台启动nohup/usr1/xjt_docker/start-docker.sh/dev/null21# 查看进程psaux|grepdocker期望看到rootlesskit、dockerd、containerd进程。6.2 验证运行状态# 查看客户端和服务端版本dockerversion# 查看 Docker 引擎详细信息dockerinfo期望输出中应包含Server Version: 29.6.1Storage Driver: vfsNetworkDriver: slirp4netnsrootlesskit6.3 运行测试容器dockerrun--rmhello-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/null21# 停止/usr1/xjt_docker/stop-docker.sh7.2 常用命令速查dockerpull镜像# 拉取镜像仅支持 ARM64 架构dockerrun-it镜像bash# 运行容器dockerps# 查看运行中的容器dockerps-a# 查看所有容器dockerimages# 查看本地镜像dockerstopID# 停止容器dockerrmID# 删除容器dockerrmi镜像# 删除镜像dockerlogsID# 查看容器日志dockerexec-itIDbash# 进入运行中的容器7.3 端口映射Rootless 模式下无法使用低于 1024 的端口映射示例# 正确使用高端口dockerrun-p8080:80 nginx# 错误无法绑定 80 端口dockerrun-p80:80 nginx7.4 磁盘空间监控vfs 存储驱动不共享镜像层磁盘占用较大建议定期检查du-sh/usr1/xjt_docker/docker-data/dockersystemdf# 查看 Docker 磁盘使用情况dockersystem prune-a# 清理未使用的镜像、容器、网络谨慎操作8. 常见问题与排查Q1docker命令找不到或执行了系统 Docker原因当前终端未加载~/.bashrc中的环境变量。解决source~/.bashrc# 手动加载execbash-l# 或启动新的 login shellQ2镜像拉取失败 (timeout / connection refused)原因代理未生效或 Docker Hub 不可达。排查echo$HTTP_PROXY# 检查代理环境变量curl-x$HTTP_PROXYhttps://registry-1.docker.io# 测试代理到 Docker Hub 的连通性解决确认~/.bashrc中代理地址正确且daemon.json中配置了镜像加速。Q3容器启动报iptables错误原因rootless 模式无权限操作 iptables。解决daemon.json中已配置iptables: false如果仍有报错检查启动命令是否加载了正确的daemon.json。Q4overlay存储驱动报错原因内核 4.19 不支持 rootless 下的 overlay。解决启动脚本中已通过--storage-drivervfs强制使用 vfs 驱动镜像占用会偏大但功能完整。Q5容器内无法访问外网原因容器内未继承代理环境变量。解决运行容器时传入代理dockerrun-eHTTP_PROXY$HTTP_PROXY-eHTTPS_PROXY$HTTPS_PROXY镜像Q6重新登录后 docker 报No such file or directory原因DOCKER_HOST指向的 socket 文件不存在Docker 未启动。解决先启动 Dockernohup/usr1/xjt_docker/start-docker.sh/dev/null21Q7docker命令报/home/xxx/bin/docker: No such file or directory原因新旧 shell 会话混用bash 缓存了旧的docker命令路径hash table。解决清除缓存并重新加载环境hash-rsource~/.bashrc# 或者直接启动新 shellexecbash-lQ8GitHub 下载链接全部超时或被拒绝原因代理拦截了 GitHub 域名。解决slirp4netns在能访问 GitHub 的机器上下载后 scp 到目标机器rootlesskit使用方式一Go 编译 GOPROXYhttps://goproxy.cn,directGo 代理会自动走国内 CDNQ9如何确认系统代理地址原因不同环境代理地址不同需要先获取。解决env|grep-iproxy# 查看当前环境变量中的代理curl-x代理地址http://www.baidu.com# 测试连通性附录快速部署清单前提已通过 3.4 节确认系统代理地址并替换下方YOUR_PROXY_HOST:PORT为实际值。# 前置需 root 执行一次 # 配置 subuid/subgid替换 START_UID USERNAME 为实际值usermod--add-subuidsSTART_UID-END_UID--add-subgidsSTART_UID-END_UIDUSERNAME# 以下全部以目标用户身份执行 exportHTTP_PROXYYOUR_PROXY_HOST:PORTexportHTTPS_PROXYYOUR_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.tgztar-xzf/tmp/docker.tgz-C/usr1/xjt_docker/docker-bin/docker/ --strip-components1chmodx /usr1/xjt_docker/docker-bin/docker/*# 3. 下载 slirp4netnsGitHub 不可达则手动传wget-O/usr1/xjt_docker/docker-bin/slirp4netns\https://github.com/rootless-containers/slirp4netns/releases/download/v1.3.4/slirp4netns-aarch64chmodx /usr1/xjt_docker/docker-bin/slirp4netns# 4. 编译 rootlesskit需要 Go用国内镜像避免 GitHub 被墙wgethttps://golang.google.cn/dl/go1.22.5.linux-arm64.tar.gz-O/tmp/go.tar.gzmkdir-p/usr1/xjt_docker/go /usr1/xjt_docker/go-hometar-xzf/tmp/go.tar.gz-C/usr1/xjt_docker/go/ --strip-components1exportPATH/usr1/xjt_docker/go/bin:$PATHexportGOPATH/usr1/xjt_docker/go-homeexportGOPROXYhttps://goproxy.cn,direct goinstallgithub.com/rootless-containers/rootlesskit/v3/cmd/rootlesskitlatestcp/usr1/xjt_docker/go-home/bin/rootlesskit /usr1/xjt_docker/docker-bin/rootlesskit# 5. 配置 daemon.jsoncat/usr1/xjt_docker/docker-config/daemon.jsonEOF { 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/null21# 8. 验证execbash-ldockerrun--rmhello-world