MinIO 三节点分布式集群部署手册(Ubuntu 22.04 · 实测可用)

本文是一份经过真实部署验证的 MinIO 分布式集群部署手册。从空白裸盘开始,到集群可读写、容错演练通过,全程命令可直接复制执行。

文中的坑都是实际踩过的:官方下载源全站 410、环境变量三台不一致导致起不来、三台密码各自随机生成导致 403、容量算错一倍……

建议首次部署就按顺序走,不要跳步。

一、方案设计(先想清楚再动手)

1.1 参考环境

项目 值
节点 3 台,192.168.0.150 / .151 / .152(示例)
系统 Ubuntu 22.04,内核 5.15
数据盘 每节点 1 块 50 GiB 裸盘(/dev/sdb)
系统盘 /dev/sda,LVM 根分区(不要动)
挂载点 /data/minio
API / Console 端口 9000 / 9001

1.2 容量与容错:先算清楚

MinIO 的校验盘数量由每 pool 的盘数自动决定,不是随便配的:

每 pool 盘数 默认 EC 数据/校验 可用比例 可容错
3 EC:1 2 / 1 66% 1 盘
4 ~ 5 EC:2 2/2 或 3/2 50% ~ 60% 2 盘
6 ~ 7 EC:3 3/3 或 4/3 50% ~ 57% 3 盘
≥ 8 EC:4 n-4 / 4 50% ~ 75% 4 盘

3 节点 × 1 盘 = 3 盘,即 EC:1:

3 盘 = 2 份数据 + 1 份校验
裸容量 150 GiB → 可用 ≈ 100 GiB
容错:任意 1 块盘 / 1 台节点整体宕机,读写不中断

我踩过的坑:一开始按 EC:2 估算,以为只有 46 GiB 可用。实际部署后 mc admin info 显示 total: 100 GiB,正好是裸容量的 2/3,才反推出是 EC:1。

验证方法:total ÷ 裸盘总容量 = 可用比例,反推即可确认 EC 等级。

常见误解:3 盘不能容忍 2 台同时宕机。要容忍 2 台节点整体宕机,每台至少 2 盘、总盘数 ≥ 5。

1.3 磁盘布局原则

/dev/sdb (裸盘)
 └─ mkfs.xfs
     └─ mount /data/minio        ← MinIO 视其为 1 个 drive

不要分区、不要 LVM、不要 RAID。 MinIO 自己管冗余,叠 RAID 会让纠删码失效、性能腰斩。

fstab 必须用 UUID + noatime,不要写 /dev/sdb——盘符可能漂移,重启后挂错盘或挂不上。


二、换环境前先改这 6 处

这份手册是在特定环境验证的,换环境时先把参数改掉再执行:

# 需要改的 示例值 说明
1 节点 IP(三处) 192.168.0.150/151/152 各处命令 + unit 里的 MINIO_VOLUMES
2 数据盘设备名 /dev/sdb 必须 lsblk 确认,可能是 /dev/vdb
3 挂载点 /data/minio 改路径要同步改 unit
4 二进制版本 RELEASE.2025-07-23T15-54-02Z 三台必须一致
5 账号密码 admin / 自定义 三台必须一致
6 盘数 / 节点数 3 盘 变则容量与 EC 全变

三、部署前检查(三台都做)

# 1. 目标盘干净、未挂载
lsblk /dev/sdb
blkid /dev/sdb          # 应无输出

# 2. 确认根分区在 sda
df -h /

# 3. 节点互通
for h in 192.168.0.150 192.168.0.151 192.168.0.152; do ping -c2 -W1 $h; done

# 4. 端口未占用
ss -lntp | grep -E ':(9000|9001)\b'    # 应无输出

# 5. 时间同步(分布式必须)
timedatectl status      # 需 "System clock synchronized: yes"

时间不同步会导致签名校验失败,报 RequestTimeTooSkewed。修复:

apt install -y systemd-timesyncd && timedatectl set-ntp true

四、获取 MinIO 二进制(官方源已下线)

4.1 必须用镜像站

dl.min.io 现在对所有社区版路径返回 410 Gone,只剩需要 license 的 AIStor 企业版。用 MinIO 中国镜像:

BASE=https://dl.minio.org.cn
VER=RELEASE.2025-07-23T15-54-02Z

curl -fL -o /usr/local/bin/minio "$BASE/server/minio/release/linux-amd64/archive/minio.$VER"
curl -fL -o /usr/local/bin/mc    "$BASE/client/mc/release/linux-amd64/mc"
chmod +x /usr/local/bin/minio /usr/local/bin/mc
#或者用wget直接下例如下面
# wget https://dl.minio.org.cn/server/minio/release/linux-amd64/archive/minio.RELEASE.2025-07-23T15-54-02Z
# wget https://dl.minio.org.cn/client/mc/release/linux-amd64/mc

必须校验下载结果,防止下到 410 错误页(只有几百字节):

head -c4 /usr/local/bin/minio | od -c | grep -q '177   E   L   F' && echo "ELF 正常"
ls -lh /usr/local/bin/minio /usr/local/bin/mc   # 约 105MB / 30MB
minio --version                                  # 应显示对应 RELEASE
项目 期望
文件类型 ELF 可执行文件
minio ≈ 105 MB
mc ≈ 30 MB
版本 三台完全一致

4.2 内网无法出网

在能上网的机器下载后分发:

scp /usr/local/bin/minio /usr/local/bin/mc root@192.168.0.151:/usr/local/bin/
ssh root@192.168.0.151 'chmod +x /usr/local/bin/minio /usr/local/bin/mc'

4.3 归档二进制(强烈建议)

镜像站是第三方资源,版本可能被清理——dl.min.io 就是这样从可用变成全站 410 的。部署成功后存一份到内网:

mkdir -p /opt/minio-archive/RELEASE.2025-07-23T15-54-02Z
cp /usr/local/bin/minio /usr/local/bin/mc /opt/minio-archive/RELEASE.2025-07-23T15-54-02Z/
cd /opt/minio-archive/RELEASE.2025-07-23T15-54-02Z
sha256sum minio mc > SHA256SUMS

以后扩容、重装、升级回滚都不再依赖外网。


五、磁盘准备(三台都做)

# 确认是空白盘再执行!会清空数据
mkfs.xfs -f -L minio-data /dev/sdb

mkdir -p /data/minio
UUID=$(blkid -s UUID -o value /dev/sdb)
cp /etc/fstab /etc/fstab.bak.$(date +%s)
echo "UUID=$UUID  /data/minio  xfs  defaults,noatime,nodiratime 0 0" >> /etc/fstab
mount -a
mountpoint /data/minio && df -h /data/minio

六、系统调优(三台都做)

6.1 关闭 swap

MinIO 对延迟敏感,官方建议禁用 swap:

swapoff -a
sed -i.bak -E '/\sswap\s/s/^/#/' /etc/fstab

6.2 内核参数

cat > /etc/sysctl.d/99-minio.conf <<'EOF'
vm.swappiness = 1
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
fs.file-max = 2097152
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65000
EOF

# 逐项应用, 单键失败只告警不中断
while IFS='=' read -r k v; do
  [[ -z "$k" || "$k" == \#* ]] && continue
  sysctl -w "$(echo $k)=$(echo $v)" >/dev/null 2>&1 \
    && echo "ok   $k" || echo "warn $k 不支持(可忽略)"
done < /etc/sysctl.d/99-minio.conf

坑:不要加 net.ipv4.conf.all.accept_source_route 和 net.ipv4.conf.all.promote_secondaries。
这两个键在 5.15 内核上返回 Invalid argument,与 MinIO 运行无关,加了只会刷报错。

6.3 文件句柄

cat > /etc/security/limits.d/99-minio.conf <<'EOF'
*      soft   nofile   1048576
*      hard   nofile   1048576
root   soft   nofile   1048576
root   hard   nofile   1048576
EOF

6.4 系统用户与目录

id minio &>/dev/null || useradd -r -s /sbin/nologin -M minio
mkdir -p /etc/minio/certs /var/log/minio
chown -R minio:minio /data/minio /etc/minio /var/log/minio
chmod 750 /etc/minio/certs

七、凭据:三台必须完全一致

umask 077
cat > /etc/minio/minio.env <<'EOF'
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=YourStrongPassw0rd
EOF
chmod 600 /etc/minio/minio.env

最大的坑之一:不要让各节点各自随机生成密码。凭据不一致时集群可能起得来,但所有访问 403,而且报错完全不指向根因,极难排查。

确认三台一致(指纹相同即可):

source /etc/minio/minio.env
printf '%s:%s' "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" | sha256sum | cut -c1-12

密码含 $ 时注意:Pass$word 这类会被 shell 展开。读取一律用变量:

source /etc/minio/minio.env
mc alias set m1 http://192.168.0.150:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD"

不要写 export $(grep ... /etc/minio/minio.env | xargs),也不要直接拼到命令行。


八、systemd 服务:三台写完全相同的文件

cat > /etc/systemd/system/minio.service <<'EOF'
[Unit]
Description=MinIO Object Storage (distributed)
Documentation=https://min.io/docs/minio/linux/index.html
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio

[Service]
Type=notify
User=minio
Group=minio
EnvironmentFile=/etc/minio/minio.env
Environment="MINIO_VOLUMES=http://192.168.0.150:9000/data/minio http://192.168.0.151:9000/data/minio http://192.168.0.152:9000/data/minio"
Environment="MINIO_OPTS=--address :9000 --console-address :9001"
Environment="MINIO_BROWSER=on"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
Restart=always
RestartSec=5
LimitNOFILE=1048576
LimitNPROC=1048576
TasksMax=infinity
TimeoutSec=0
SendSIGKILL=no
StandardOutput=append:/var/log/minio/minio.log
StandardError=append:/var/log/minio/minio.log

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable minio

三条铁律(本次最大的坑)

① MINIO_VOLUMES 三台顺序必须一模一样

顺序不同,MinIO 会认为是不同的集群拓扑。

② 绝对不要设置 MINIO_SERVER_URL / MINIO_BROWSER_REDIRECT_URL

MinIO 启动时会比对三台所有 MINIO_* 变量,要求值完全相同。如果按各自 IP 填写(比如 https://192.168.0.151:9000),必然不同,直接拒绝组集群:

Error: http://192.168.0.152:9000->http://192.168.0.151:9000 has incorrect configuration:
Expected MINIO_* environment name and values across all servers to be same:
Mismatching environment values: [MINIO_SERVER_URL MINIO_BROWSER_REDIRECT_URL]
INFO: Waiting for at least 1 remote servers with valid configuration to be online

这个错误会每 2 秒刷一次,systemd 的 Type=notify 让它看起来像卡死,实际上它在无限等待。

只有前面有负载均衡 / VIP / 统一域名时才设,且三台填同一个值。

③ 不要设 MINIO_PROMETHEUS_AUTH_TYPE

非必要变量越少越好,减少不一致的可能。


九、启动:三台几乎同时

分布式启动是互相等待的,必须三台一起启动:

# 三台各开一个终端, 几乎同时执行
systemctl start minio

或从一台并行启动(需 SSH 免密):

for h in 192.168.0.150 192.168.0.151 192.168.0.152; do
  ssh root@$h 'systemctl start minio' &
done; wait

单台日志出现 Waiting for at least 1 remote servers... 是正常等待,不是卡死。三台都起来后几秒内自动组集群。


十、验证

10.1 健康检查

for h in 192.168.0.150 192.168.0.151 192.168.0.152; do
  printf "%-16s " "$h"
  curl -s -o /dev/null -w '%{http_code}\n' "http://$h:9000/minio/health/cluster"
done
# 三行都应为 200

10.2 集群信息

source /etc/minio/minio.env
mc alias set m1 http://192.168.0.150:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD"
mc admin info m1

期望输出:

●  192.168.0.150:9000
   Uptime: ...
   Version: 2025-07-23T15:54:02Z
   Network: 3/3 OK          ← 节点互连全通
   Drives:  1/1 OK          ← 每台 1 块盘在线
   Pool: 1
●  192.168.0.151:9000   ...
●  192.168.0.152:9000   ...

3 nodes, 3 drives, 1 pool

三个关键点:三台 Version 相同、Network: 3/3 OK、Drives: 1/1 OK。

小坑:mc admin info m1 报 No valid configuration found for 'm1' host alias,是因为没执行 mc alias set。alias 存在 ~/.mc/config.json,换用户或换机器要重设。

不想写配置文件可以用环境变量:export MC_HOST_m1="http://${MINIO_ROOT_USER}:${MINIO_ROOT_PASSWORD}@192.168.0.150:9000"(注意别写成 //IP/:9000 这种畸形格式)。

10.3 读写测试

mc mb m1/testbucket
echo "hello minio $(date)" > /tmp/a.txt
mc cp /tmp/a.txt m1/testbucket/
mc cat m1/testbucket/a.txt

十一、容错演练(必做)

这是验证纠删码真的生效的唯一方法,不是看进程有没有起来。

# 1. 灌入测试数据
mkdir -p /tmp/bulk && for i in $(seq 1 50); do head -c 1M /dev/urandom > /tmp/bulk/f$i.bin; done
mc mb -p m1/testbucket
mc cp --recursive /tmp/bulk/ m1/testbucket/bulk/

# 2. 停掉一台模拟故障
ssh root@192.168.0.151 'systemctl stop minio'

# 3. 立刻读 —— 必须成功
mc cat m1/testbucket/bulk/f25.bin > /dev/null && echo "读取正常 ✓"

# 4. 立刻写 —— 也必须成功
echo test > /tmp/new.txt && mc cp /tmp/new.txt m1/testbucket/ && echo "写入正常 ✓"

# 5. 状态应为 1 drive offline
mc admin info m1 | grep -E 'offline|Drives'

# 6. 恢复并自愈
ssh root@192.168.0.151 'systemctl start minio'
sleep 20
mc admin heal m1 --recursive
mc admin info m1 | grep offline        # 应回到 0 offline

若第 3 步读取失败,说明 EC 未生效,检查三台 MINIO_VOLUMES 是否完全一致。


十二、日常运维

systemctl status minio
journalctl -u minio -f                  # 实时日志
tail -f /var/log/minio/minio.log

mc admin info m1                        # 集群概览
mc admin heal m1 --recursive            # 手动触发自愈
mc admin trace m1                       # 实时请求追踪
mc support perf drive m1                # 磁盘性能基线

滚动升级

三台版本必须一致,逐台替换,每台确认健康后再下一台:

BASE=https://dl.minio.org.cn
NEW_VER=RELEASE.2025-XX-XXTXX-XX-XXZ

cp /usr/local/bin/minio /usr/local/bin/minio.bak
systemctl stop minio
curl -fL -o /usr/local/bin/minio.new "$BASE/server/minio/release/linux-amd64/archive/minio.$NEW_VER"
chmod +x /usr/local/bin/minio.new && mv /usr/local/bin/minio.new /usr/local/bin/minio
systemctl start minio
curl -fsS http://<本机IP>:9000/minio/health/cluster && echo OK

扩容

老集群保持在线,在每台 MINIO_VOLUMES 末尾追加新地址(只能追加,不能插中间),然后所有节点一起重启:

http://192.168.0.150:9000/data/minio
http://192.168.0.151:9000/data/minio
http://192.168.0.152:9000/data/minio
http://192.168.0.153:9000/data/minio     ← 新增

扩完执行 mc admin heal m1 --recursive 让旧数据重分布。

备份

  • 配置:/etc/minio/minio.env、/etc/systemd/system/minio.service
  • 数据:纠删码不是备份。重要数据另存一份:mc mirror m1/prod /backup/prod
  • 不要 rsync /data/minio:分布式布局下单拷某个节点没有意义

十三、TLS

# 文件名固定, 不能改
cp your.crt /etc/minio/certs/public.crt      # 服务器证书(含中间链)
cp your.key /etc/minio/certs/private.key
chown -R minio:minio /etc/minio/certs
chmod 600 /etc/minio/certs/private.key

systemctl restart minio     # 三台都放

证书 SAN 必须包含三台 IP 或覆盖它们的域名,否则 SDK 校验失败。

自签(仅测试):

cd /etc/minio/certs
openssl req -x509 -nodes -days 825 -newkey rsa:2048 \
  -keyout private.key -out public.crt -subj "/CN=minio.local" \
  -addext "subjectAltName=IP:192.168.0.150,IP:192.168.0.151,IP:192.168.0.152"
chown minio:minio private.key public.crt && chmod 600 private.key
systemctl restart minio

启用后地址变为 https://IP:9000 / https://IP:9001,不需要额外设 MINIO_SERVER_URL。


十四、已知坑速查表

现象 原因 处理
curl: (22) ... 410 下载失败 dl.min.io 已下线社区版 用 dl.minio.org.cn
下载的文件只有几百字节 下到了错误页 校验 ELF 头 + 文件大小
sysctl: ... Invalid argument 用了 5.15 不支持的网络键 去掉那两键
启动卡住,刷 Waiting for at least 1 remote servers 其它节点未启动 三台一起启动
Mismatching environment values: [MINIO_SERVER_URL ...] 按节点设了 URL 变量 删掉这两行
集群起来了但访问 403 三台 MINIO_ROOT_PASSWORD 不同 统一 env 后三台重启
No valid configuration found for 'm1' host alias 没执行 mc alias set 先建 alias
RequestTimeTooSkewed 节点时间不同步 timedatectl set-ntp true
写入报 XMinioStorageFull 可用空间 < 5%(硬性保留) 清理或扩容
mkfs.xfs: command not found 未装 xfsprogs apt install -y xfsprogs
重启后 /data/minio 空了 fstab 用了 /dev/sdb 改用 UUID=
Console 打不开 9001 被防火墙挡 检查 ufw / iptables

十五、部署完成确认清单

[ ] 三台 minio --version 完全一致
[ ] 三台 /etc/minio/minio.env 内容一致(凭据指纹相同)
[ ] 三台 minio.service 中 MINIO_VOLUMES 顺序一致
[ ] service 中无 MINIO_SERVER_URL / BROWSER_REDIRECT_URL / PROMETHEUS
[ ] mountpoint /data/minio 通过,df 显示容量正常
[ ] 三台 health/cluster 均返回 200
[ ] mc admin info 显示 3 nodes, 3 drives, 1 pool
[ ] 三台 Network: 3/3 OK、Drives 1/1 OK
[ ] 读写测试通过
[ ] 容错演练通过:停 1 台仍可读写,恢复后 heal 完成
[ ] 二进制已归档到 /opt/minio-archive/

小结

三个最关键的教训,按重要性排序:

  1. 所有 MINIO_* 环境变量必须三台完全一致,任何按节点变化的变量(尤其是 URL 类)都不能进 unit
  2. 凭据必须三台一致,不能各节点随机生成,否则 403 且报错不指向根因
  3. 容量要按盘数算 EC,别凭感觉估,用 mc admin info 的 total ÷ 裸容量 反推验证

其余都是细节。这三条对了,剩下基本不会出问题。

posted @ 2026-10-21 16:40  ZANAN  阅读(15)  评论(0)    收藏  举报