前言:在安全受限的服务器上,使用非 root 用户(如ceshi)通过 Rootless Docker 部署 OceanBase-MySQL 单机精简版 是一种常见的避权方案。但在实际部署中,由于非 root 用户的宿主机系统配额限制以及无根容器的环境特性,容易遭遇连环报错。本文将基于真实的踩坑 closed-loop 闭环实践,为您提供一份详尽的部署与排错指南。

一、 第一阶段:Rootless Docker 离线安装与启动报错解决

1. Docker Rootless 自动化安装脚本

首先,在普通用户(如 ceshi)下准备好 docker-*.tgzdocker-rootless-extras-*.tgz 离线包,使用以下自动化脚本进行安装:

#!/bin/bash
set -e
if [ "$EUID" -eq 0 ]; then
    echo "错误:请勿使用 root 用户运行此脚本!请切换到普通用户后再执行。"
    exit 1
fi

USER_HOME=$HOME
BIN_DIR="$USER_HOME/bin"
RUN_DIR="$USER_HOME/.docker/run"
DATA_DIR="$USER_HOME/.docker/data"

echo "1. 正在创建独立运行时目录..."
mkdir -p "$BIN_DIR"
mkdir -p "$RUN_DIR"
mkdir -p "$DATA_DIR"

echo "2. 正在解压二进制文件..."
if ls docker-*.tgz >/dev/null 2>&1 && ls docker-rootless-extras-*.tgz >/dev/null 2>&1; then
    tar -zxvf docker-*.tgz > /dev/null
    tar -zxvf docker-rootless-extras-*.tgz > /dev/null
    
    mv docker/* "$BIN_DIR/"
    mv docker-rootless-extras/* "$BIN_DIR/"
    rm -rf docker docker-rootless-extras
else
    echo "错误:在当前目录下未找到 docker-*.tgz 或 docker-rootless-extras-*.tgz 压缩包!"
    exit 1
fi

echo "3. 正在写入独立环境变量到 ~/.bashrc ..."
sed -i '/XDG_RUNTIME_DIR/d' "$USER_HOME/.bashrc"
sed -i '/DATA_DIR/d' "$USER_HOME/.bashrc"
sed -i '/DOCKER_HOST/d' "$USER_HOME/.bashrc"
sed -i '#\/bin:#d' "$USER_HOME/.bashrc"

echo "export XDG_RUNTIME_DIR=$RUN_DIR" >> "$USER_HOME/.bashrc"
echo "export DATA_DIR=$DATA_DIR" >> "$USER_HOME/.bashrc"
echo "export PATH=$BIN_DIR:\$PATH" >> "$USER_HOME/.bashrc"
echo "export DOCKER_HOST=unix://$RUN_DIR/docker.sock" >> "$USER_HOME/.bashrc"
export XDG_RUNTIME_DIR=$RUN_DIR
export DATA_DIR=$DATA_DIR
export PATH=$BIN_DIR:$PATH
export DOCKER_HOST=unix://$RUN_DIR/docker.sock

echo "4. 正在后台启动 Docker 引擎 (绕过 systemd 限制)..."
SKIP_IPTABLES=1 nohup dockerd-rootless.sh --data-root="$DATA_DIR" > "$USER_HOME/docker.log" 2>&1 &

echo "5. 等待守护进程初始化 (5秒)..."
sleep 5

echo "6. 验证部署状态..."
if grep -q "Daemon has completed initialization" "$USER_HOME/docker.log"; then
    echo "=========================================================="
    echo "Docker Rootless 离线部署成功!"
    echo "=========================================================="
    echo "请执行以下命令让当前终端的环境变量生效:"
    echo "   source ~/.bashrc"
    echo ""
    echo "随后即可通过 'docker info' 查看运行状态。"
    echo "=========================================================="
else
    echo "启动报错,请执行 'cat ~/docker.log' 查看日志原因。"
fi

2. 报错 1:存储驱动 fuse-overlayfs 缺失

  • 日志现象:level=error msg="failed to mount overlay: operation not permitted"
    level=error msg="exec: \"fuse-overlayfs\": executable file not found in $PATH"

原因剖析:普通用户无权直接挂载内核的 overlay2 存储驱动。Rootless 模式必须依赖用户态文件系统工具 fuse-overlayfs

解决办法:使用具有 sudo 权限的用户,按照依赖顺序离线安装以下两个 RPM 包:

sudo rpm -Uvh --force --nodeps fuse3-libs-*.rpm fuse-overlayfs-*.rpm

3. 报错 2:网段修改参数不合法(CIDR 格式错误)

  • 日志现象:failed to start daemon: Error initializing network controller: invalid CIDR address: 66.66.66.66

  • 原因剖析:为了避免与局域网路由冲突,在指定 --bip 参数时误将其写成了单一主机 IP。Docker 要求此项必须是带子网掩码的标准 CIDR 格式

  • 解决办法:将参数修正为标准网段格式(如 66.66.66.1/24

4. 报错 3:容器运行时残留/通信失败(containerd 状态冲突)

  • 日志现象:failed to start containerd: error until-failed; exit status 1 rootlesskit:parent] error: child exited: exit status 1

  • 原因剖析:由于前几次异常闪退或参数错误导致不正常退出,旧的 containerd 守护进程仍在后台残留,或者在 $XDG_RUNTIME_DIR(即 ~/.docker/run/)下遗留了未释放的 .sock 锁文件与旧进程 PID 记录,导致新进程无法成功绑定。

  • 解决办法:需要彻底清理残留的后台进程并清空运行时缓存目录,然后指定正确的 CIDR 子网网段重新拉起:

# 1. 强行终止残留的 Docker 及 containerd 进程
pkill -f dockerd
pkill -f containerd

# 2. 清理运行时锁文件与残余缓存
rm -rf ~/.docker/run/*

# 3. 带上正确的子网掩码网段参数,重新在后台拉起守护进程
SKIP_IPTABLES=1 nohup dockerd-rootless.sh --data-root=/home/ceshi/.docker/data --bip="66.66.66.1/24" > /home/ceshi/docker.log 2>&1 &

二、 第二阶段:OceanBase 单机版部署与连接假死问题解决

1. OceanBase 容器编排配置

创建 docker-compose-ob.yaml 配置文件,以 MINI(精简版)模式启动容器:

version: "3"

services:
  oceanbase:
    image: oceanbase/oceanbase-ce:4.3.3.1
    container_name: oceanbase
    restart: always
    ports:
      - 2881:2881
    volumes:
      - ./ob:/root/ob
      - ./obd/cluster:/root/.obd/cluster
    environment:
      - MODE=MINI
      - OB_SYS_PASSWORD=SYS密码
      - OB_TENANT_PASSWORD=租户密码
    networks:
      - custom_net

networks:
  custom_net:
    ipam:
      driver: default
      config:
        - subnet: 192.168.22.0/24

2. 现象:提示 boot success 却无法连接数据库

  • 现象描述:执行 docker-compose up -d 启动后,容器日志里明确提示了 boot success! / Connect to observer ok。但外部客户端(如客户端工具或 MySQL 命令行)连接 2881 端口时会瞬间断开:

    Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.

  • 原因剖析:OceanBase 内部架构在初始化租户和提供服务时,会在瞬间创建海量的内部线程与进程。在 Rootless 环境下,容器内进程上限受限于宿主机对该普通用户 nproc(最大进程数)的限制。系统默认配额过低导致 OB 无法为新连接分配线程,引发假死进程无响应。

  • 解决办法: 使用 root 权限修改宿主机的 /etc/security/limits.conf,大幅上调 ceshi用户的最大进程数额度:

# 修改宿主机限额配置文件
ceshi soft nproc 120000
ceshi hard nproc 120000

三、 第三阶段:数据清理与解压文件报错解决

1. 再次启动报错:File size limit exceeded

  • 现象描述:修改完进程限制、清空数据再次构建时,解压离线组件到一半时容器崩溃闪退:

root/boot/start.sh: line 142: ... 19 File size limit exceeded(core dumped) tar -xvzf repository.tar.gz

  • 原因剖析:由于 OceanBase 组件归档包在解压时会释放出体积巨大的单体二进制文件(如 observer 进程文件),触发了 Linux 系统的 ulimit -f(单文件写入大小限制)保护机制。非 root 用户被禁止写入超大文件,导致内核直接强行熔断并引发 Core Dump。

  • 解决办法

    1. 依然以 root 权限打开宿主机的 /etc/security/limits.conf,彻底放开该用户的单文件写入限制:

ceshi soft fsize unlimited
ceshi hard fsize unlimited

  • 重要步骤:修改完 limits 后,必须彻底重启 Rootless Docker 后台守护进程,容器才能感知并继承宿主机的最新系统配额:

pkill -f dockerd && pkill -f containerd
rm -rf ~/.docker/run/*
# 重新拉起守护进程
SKIP_IPTABLES=1 nohup dockerd-rootless.sh --data-root=/home/ceshi/.docker/data --bip="66.66.66.1/24" > /home/ceshi/docker.log 2>&1 &

在配置完上述所有系统配额(limits.conf)之后,切勿直接盲目重启容器。请教导运维或开发人员使用以下标准流程来验证限制是否已经切实应用到 ceshi 用户:

验证方法

新开一个 SSH 终端连接,或者在当前终端中执行以下命令切换至 ceshi 用户(确保环境配置被重新加载):

su - ceshi
# 1. 检查最大进程数限制 (应当显示为 120000)
ulimit -u

# 2. 检查最大文件句柄打开数 (确保满足高并发要求)
ulimit -n

# 3. 检查单文件写入大小限制 (应当显示为 unlimited)
ulimit -f

当看到 ulimit -u 输出为 120000ulimit -f 输出为 unlimited 时,证明宿主机底座的资源配额已经完全打通,此时便可放心地在 Rootless Docker 中流畅运行 OceanBase 容器了。

四、启动Oceanbase-mysql服务

清理掉当前目录下因为解压中断生成的残缺 ./ob./obd 数据目录,再次执行 docker-compose  -f  docker-compose-ob.yaml up -d 即可顺利安装完成。

> 回复「rootless」,ob-mysql镜像、启动yaml、脚本发您,创作不易麻烦点个关注谢谢!!!

更多推荐