1. Tổng quan
Bài này sẽ giúp bạn triển khai MinIO distributed 4 node × 2 disk theo hai cách:
- A. Demo nhiều node trên 1 máy (4 container, 8 volume) – học cú pháp & hành vi.
- B. Nhiều máy thật (production-style) dùng Docker Swarm (overlay network).
Cả hai đều không dùng Nginx/Gateway, client truy cập trực tiếp vào các cổng của MinIO.
2. Kiến trúc logic & vật lý (minh họa)
Logic (Erasure sets):
+----------------------------------------------+
| Cluster MinIO (S3 API) |
| Objects -> k data + m parity (EC) |
| Phân tán qua nhiều node/đĩa |
+----------------------------------------------+
Vật lý (ví dụ 4 node x 2 disk):
+---------+ +---------+ +---------+ +---------+
Node1 | /data1 | | /data1 | | /data1 | | /data1 |
| /data2 | | /data2 | | /data2 | | /data2 |
+---------+ +---------+ +---------+ +---------+
minio1 minio2 minio3 minio4
\ | | /
\_________________|________________|_______________/
EC set(s)
3. A. Demo 4 node × 2 disk trên 1 máy
3.1. Cấu trúc thư mục
mkdir -p ~/minio-dist && cd ~/minio-dist
mkdir -p data/node1/d{1,2} data/node2/d{1,2} data/node3/d{1,2} data/node4/d{1,2}
3.2. File .env
(khuyến nghị)
cat > ~/minio-dist/.env << 'OEF'
MINIO_IMAGE=quay.io/minio/minio
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin
OEF
source ~/minio-dist/.env
3.3. docker-compose.yml
(single-host, 4 services)
cat > ~/minio-dist/docker-compose.yml << 'OEF'
version: '3.8'
services:
minio1:
image: ${MINIO_IMAGE}
container_name: minio1
restart: unless-stopped
hostname: minio1
ports:
- "9000:9000" # S3 API
- "9001:9001" # Console
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
command: server http://minio{1...4}/data{1...2} --console-address ":9001"
volumes:
- ./data/node1/d1:/data1
- ./data/node1/d2:/data2
networks:
- minio-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 5s
retries: 5
minio2:
image: ${MINIO_IMAGE}
container_name: minio2
restart: unless-stopped
hostname: minio2
ports:
- "9002:9000"
- "9003:9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
command: server http://minio{1...4}/data{1...2} --console-address ":9001"
volumes:
- ./data/node2/d1:/data1
- ./data/node2/d2:/data2
networks:
- minio-net
minio3:
image: ${MINIO_IMAGE}
container_name: minio3
restart: unless-stopped
hostname: minio3
ports:
- "9004:9000"
- "9005:9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
command: server http://minio{1...4}/data{1...2} --console-address ":9001"
volumes:
- ./data/node3/d1:/data1
- ./data/node3/d2:/data2
networks:
- minio-net
minio4:
image: ${MINIO_IMAGE}
container_name: minio4
restart: unless-stopped
hostname: minio4
ports:
- "9006:9000"
- "9007:9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
command: server http://minio{1...4}/data{1...2} --console-address ":9001"
volumes:
- ./data/node4/d1:/data1
- ./data/node4/d2:/data2
networks:
- minio-net
networks:
minio-net:
driver: bridge
OEF
Giải thích nhanh
command: server http://minio{1...4}/data{1...2}
: mỗi service tự biết 8 endpoint (4 node × 2 disk).- Mỗi container expose cặp cổng riêng để bạn có thể mở Console của từng node khi cần (9001, 9003, 9005, 9007).
- Truy cập S3 API bất kỳ node nào đều được (9000/9002/9004/9006).
3.4. Khởi chạy & kiểm tra
docker-compose -f ~/minio-dist/docker-compose.yml up -d
Verify
shell> docker-compose ps
NAME COMMAND SERVICE STATUS PORTS
minio1 "/usr/bin/docker-ent…" minio1 running (healthy) 0.0.0.0:9000-9001->9000-9001/tcp, :::9000-9001->9000-9001/tcp
minio2 "/usr/bin/docker-ent…" minio2 running 0.0.0.0:9002-9003->9000-9001/tcp, :::9002-9003->9000-9001/tcp
minio3 "/usr/bin/docker-ent…" minio3 running 0.0.0.0:9004-9005->9000-9001/tcp, :::9004-9005->9000-9001/tcp
minio4 "/usr/bin/docker-ent…" minio4 running 0.0.0.0:9006-9007->9000-9001/tcp, :::9006-9007->9000-9001/tcp
- Console chính (minio1):
http://localhost:9001
- Các console còn lại:
http://localhost:9003
,...9005
,...9007
3.5. Kết nối mc
và tạo bucket
mc alias set dlocal http://localhost:9000 ${MINIO_ROOT_USER} ${MINIO_ROOT_PASSWORD}
mc mb dlocal/test-bucket
mc ls dlocal
Kết quả nếu bạn truy cập bạn sẽ thấy mặc dù 4 URL dưới, chúng khác nhau nhưng lại cho cùng một kết quả.
- http://10.237.7.77:9001/browser/pvc-c66c6d56-62b8-4597-abd8-cc366eb2708a
- http://10.237.7.77:9003/browser/pvc-c66c6d56-62b8-4597-abd8-cc366eb2708a
- http://10.237.7.77:9005/browser/pvc-c66c6d56-62b8-4597-abd8-cc366eb2708a
- http://10.237.7.77:9007/browser/pvc-c66c6d56-62b8-4597-abd8-cc366eb2708a
4. Triển khai nhiều máy thật bằng Docker Swarm
4.1. Chuẩn bị node
Mình có 4 node (10.237.7.81–84), mỗi node có 3 disk (/dev/sdb
, /dev/sdc
, /dev/sdd
). Dưới đây là quy trình đầy đủ để:
- Chuẩn bị đĩa và mount theo chuẩn cho MinIO,
- Khởi tạo Docker Swarm và gán từng service MinIO vào đúng node,
- Triển khai MinIO distributed 4×3 (4 node × 3 disk) bằng
docker stack deploy
.
4.2. Chuẩn bị đĩa trên mỗi node (81, 82, 83, 84)
Ví dụ dùng ext4
. Nếu bạn thích xfs
, thay mkfs.ext4
bằng mkfs.xfs
.
Tạo filesystem (chỉ chạy một lần cho mỗi disk, trên từng node):
for d in /dev/sdb /dev/sdc /dev/sdd; do
wipefs -a $d
mkfs.ext4 -F -L $(basename $d) $d
done
Tạo mount points và mount:
mkdir -p /opt/minio/d{1,2,3}
echo "/dev/sdb /opt/minio/d1 ext4 noatime,nodiratime 0 2" >> /etc/fstab
echo "/dev/sdc /opt/minio/d2 ext4 noatime,nodiratime 0 2" >> /etc/fstab
echo "/dev/sdd /opt/minio/d3 ext4 noatime,nodiratime 0 2" >> /etc/fstab
mount -a
df -h | egrep 'd1|d2|d3'
Đảm bảo quyền truy cập:
chown -R root:root /opt/minio
chmod -R 755 /opt/minio
Kết quả
shell> df -h | egrep 'd1|d2|d3'
/dev/sdb 2.0G 24K 1.8G 1% /opt/minio/d1
/dev/sdc 2.0G 24K 1.8G 1% /opt/minio/d2
/dev/sdd 2.0G 24K 1.8G 1% /opt/minio/d3
4.3. Khởi tạo Docker Swarm & join
Cài đặt Docker.
# Set proxy
export {http,https}_proxy=http://10.237.7.250:3128
export no_proxy="localhost,127.0.0.1,10.237.7.0/24"
# Installation of Docker on all nodes
apt-get update
apt-get install ca-certificates curl gnupg lsb-release -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io -y
chmod 666 /var/run/docker.sock
curl -L "https://github.com/docker/compose/releases/download/v2.6.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose -v
# Configuration Proxy for Docker on all nodes
mkdir -p /etc/systemd/system/docker.service.d
cat > /etc/systemd/system/docker.service.d/http-proxy.conf << 'OEF'
[Service]
Environment="HTTP_PROXY=http://10.237.7.250:3128" "HTTPS_PROXY=http://10.237.7.250:3128" "NO_PROXY=localhost,127.0.0.1,10.237.7.0/24"
OEF
systemctl daemon-reload
systemctl restart docker
Khởi tạo Docker Swarm trên manager (10.237.7.81):
shell> docker swarm init --advertise-addr 10.237.7.81
Swarm initialized: current node (0uv0burufljrhg6qxyyvoszsg) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-0r3d2pj10u77kwfrp495kehms8jtg1ui9dh5hmzb9ed7zmn3gh-80m1wo10gddtsupej5kmzy0za 10.237.7.81:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions
Lệnh sẽ in ra chuỗi docker swarm join --token SWMTKN-... 10.237.7.81:2377
.
Trên mỗi worker (10.237.7.82, .83, .84): chạy đúng lệnh join vừa in ra:
shell> docker swarm join --token SWMTKN-1-0r3d2pj10u77kwfrp495kehms8jtg1ui9dh5hmzb9ed7zmn3gh-80m1wo10gddtsupej5kmzy0za 10.237.7.81:2377
This node joined a swarm as a worker.
Kiểm tra trên manager:
shell> docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
0uv0burufljrhg6qxyyvoszsg * node81 Ready Active Leader 28.3.3
kdr3tqjdweyltbi256nm7qipw node82 Ready Active 28.3.3
ishp7ceq2jballtgxz6qjkm0v node83 Ready Active 28.3.3
hjuinks6z1l332oyrd7poy91i node84 Ready Active 28.3.3
Bạn sẽ thấy 4 node ở trạng thái Ready
.
Mở port nội bộ giữa các node (nếu có firewall):
- 2377/TCP (cluster management)
- 7946/TCP+UDP (gossip)
- 4789/UDP (overlay/VXLAN)
5. Xác định hostname cho ràng buộc triển khai
Trên từng node, lấy hostname (ví dụ dưới đây cho node81)
shell> hostnamectl --static
node81
Giả sử kết quả:
- 10.237.7.81 →
node81
- 10.237.7.82 →
node82
- 10.237.7.83 →
node83
- 10.237.7.84 →
node84
Nếu hostname thực tế khác, hãy dùng đúng giá trị thật vào placement.constraints
ở bước 6.
6. File môi trường minio.env
(trên manager)
Tạo tại thư mục triển khai (ví dụ /root/minio-swarm/
):
mkdir -p ~/minio-swarm
cd ~/minio-swarm
cat > ~/minio-swarm/.env << 'OEF'
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin
MINIO_IMAGE=quay.io/minio/minio
OEF
Nạp biến khi deploy (an toàn, khuyến nghị)
set -a
source .env
set +a
set -a
đảm bảo tất cả biến trong .env
được export vào môi trường shell, để Docker Swarm thấy được ${MINIO_IMAGE}
, ${MINIO_ROOT_USER}
, ${MINIO_ROOT_PASSWORD}
.
7. File stack minio-swarm.yml
(4 node × 3 disk)
Mỗi service gắn vào đúng 1 node bằng node.hostname
.
Mỗi node bind-mount 3 disk: /opt/minio/d1
, /opt/minio/d2
, /opt/minio/d3
.
Tham số command
khai báo đầy đủ 12 endpoint: http://minio{1...4}/data{1...3}
(4 node × 3 data dir).
cat > ~/minio-swarm/minio-swarm.yml << 'OEF'
version: '3.8'
networks:
minio-net:
driver: overlay
services:
minio1:
image: ${MINIO_IMAGE}
hostname: minio1
env_file: .env
command: server http://minio{1...4}/data{1...3} --console-address ":9001"
volumes:
- /opt/minio/d1:/data1
- /opt/minio/d2:/data2
- /opt/minio/d3:/data3
networks:
- minio-net
ports:
- target: 9000
published: 9000
protocol: tcp
mode: host
- target: 9001
published: 9001
protocol: tcp
mode: host
deploy:
placement:
constraints:
- node.hostname == node81
restart_policy:
condition: on-failure
minio2:
image: ${MINIO_IMAGE}
hostname: minio2
env_file: .env
command: server http://minio{1...4}/data{1...3} --console-address ":9001"
volumes:
- /opt/minio/d1:/data1
- /opt/minio/d2:/data2
- /opt/minio/d3:/data3
networks:
- minio-net
ports:
- target: 9000
published: 9002
protocol: tcp
mode: host
- target: 9001
published: 9003
protocol: tcp
mode: host
deploy:
placement:
constraints:
- node.hostname == node82
restart_policy:
condition: on-failure
minio3:
image: ${MINIO_IMAGE}
hostname: minio3
env_file: .env
command: server http://minio{1...4}/data{1...3} --console-address ":9001"
volumes:
- /opt/minio/d1:/data1
- /opt/minio/d2:/data2
- /opt/minio/d3:/data3
networks:
- minio-net
ports:
- target: 9000
published: 9004
protocol: tcp
mode: host
- target: 9001
published: 9005
protocol: tcp
mode: host
deploy:
placement:
constraints:
- node.hostname == node83
restart_policy:
condition: on-failure
minio4:
image: ${MINIO_IMAGE}
hostname: minio4
env_file: .env
command: server http://minio{1...4}/data{1...3} --console-address ":9001"
volumes:
- /opt/minio/d1:/data1
- /opt/minio/d2:/data2
- /opt/minio/d3:/data3
networks:
- minio-net
ports:
- target: 9000
published: 9006
protocol: tcp
mode: host
- target: 9001
published: 9007
protocol: tcp
mode: host
deploy:
placement:
constraints:
- node.hostname == node84
restart_policy:
condition: on-failure
OEF
Giải thích:
hostname: minio1..4
tạo DNS service nội bộ để 4 service có thể gọi lẫn nhau theo mẫuhttp://minio{1...4}/data{1...3}
.mode: host
để ánh xạ trực tiếp port ra host tương ứng (tránh NAT/ingress khi test).published
dùng các cổng:- Node81: 9000(S3), 9001(Console)
- Node82: 9002(S3), 9003(Console)
- Node83: 9004(S3), 9005(Console)
- Node84: 9006(S3), 9007(Console)
Nếu hostname thật không phải node81..84
, hãy sửa lại node.hostname == <HOSTNAME_THẬT>
.
8. Triển khai stack
Trên manager (10.237.7.81), trong thư mục chứa minio-swarm.yml
và minio.env
:
shell> docker stack deploy -c ~/minio-swarm/minio-swarm.yml minio
Since --detach=false was not specified, tasks will be created in the background.
In a future release, --detach=false will become the default.
Creating network minio_minio-net
Creating service minio_minio3
Creating service minio_minio4
Creating service minio_minio1
Creating service minio_minio2
Kiểm tra.
shell> docker stack services minio
ID NAME MODE REPLICAS IMAGE PORTS
uxujx93114vp minio_minio1 replicated 1/1 quay.io/minio/minio:latest
9awzox36w3lt minio_minio2 replicated 1/1 quay.io/minio/minio:latest
khlszh09paet minio_minio3 replicated 1/1 quay.io/minio/minio:latest
ja86s719byrw minio_minio4 replicated 1/1 quay.io/minio/minio:latest
shell> docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
uxujx93114vp minio_minio1 replicated 1/1 quay.io/minio/minio:latest
9awzox36w3lt minio_minio2 replicated 1/1 quay.io/minio/minio:latest
khlszh09paet minio_minio3 replicated 1/1 quay.io/minio/minio:latest
ja86s719byrw minio_minio4 replicated 1/1 quay.io/minio/minio:latest
shell> docker service ps minio_minio1
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
m7s487fghq0w minio_minio1.1 quay.io/minio/minio:latest node81 Running Running 13 minutes ago *:9001->9001/tcp,*:9001->9001/tcp,*:9000->9000/tcp,*:9000->9000/tcp
9. Kết nối và kiểm thử
9.1. Console:
- Node81:
http://10.237.7.81:9001
- Node82:
http://10.237.7.82:9003
- Node83:
http://10.237.7.83:9005
- Node84:
http://10.237.7.84:9007
9.2. S3 API (bạn có thể dùng bất kỳ node nào):
http://10.237.7.81:9000
http://10.237.7.82:9002
http://10.237.7.83:9004
http://10.237.7.84:9006
9.3. MinIO Client.
Cài đặt mc
trên máy host (hoặc chạy container minio/mc
).
wget https://dl.min.io/client/mc/release/linux-amd64/mc -O /usr/local/bin/mc
chmod +x /usr/local/bin/mc
Kết nối Alias
shell> mc alias set dcluster http://10.237.7.81:9000 minioadmin minioadmin
mc: Configuration written to `/root/.mc/config.json`. Please update your access credentials.
mc: Successfully created `/root/.mc/share`.
mc: Initialized share uploads `/root/.mc/share/uploads.json` file.
mc: Initialized share downloads `/root/.mc/share/downloads.json` file.
Added `dcluster` successfully.
Check Info cho ta biết tình trạng node.
- 4 node (
minio1..4
), mỗi node 3 drive → tổng cộng 12 drive. - Mạng giữa các node OK 4/4.
- Mỗi node báo
Drives: 3/3 OK
→ toàn bộ 12 drive đều online. - Tất cả cùng thuộc Pool 1.
shell> mc admin info dcluster
● minio1:9000
Uptime: 1 minute
Version: 2025-07-23T15:54:02Z
Network: 4/4 OK
Drives: 3/3 OK
Pool: 1
● minio2:9000
Uptime: 1 minute
Version: 2025-07-23T15:54:02Z
Network: 4/4 OK
Drives: 3/3 OK
Pool: 1
● minio3:9000
Uptime: 1 minute
Version: 2025-07-23T15:54:02Z
Network: 4/4 OK
Drives: 3/3 OK
Pool: 1
● minio4:9000
Uptime: 1 minute
Version: 2025-07-23T15:54:02Z
Network: 4/4 OK
Drives: 3/3 OK
Pool: 1
┌──────┬──────────────────────┬─────────────────────┬──────────────┐
│ Pool │ Drives Usage │ Erasure stripe size │ Erasure sets │
│ 1st │ 0.0% (total: 14 GiB) │ 12 │ 1 │
└──────┴──────────────────────┴─────────────────────┴──────────────┘
12 drives online, 0 drives offline, EC:4
- Erasure stripe size: 12 → mỗi object được trải đều qua 12 shards (trên 12 drive).
- Erasure sets: 1 → toàn bộ 12 drive tạo thành 1 erasure set duy nhất.
- EC:4 → đây là con số MinIO hiển thị: cluster được cấu hình 4 parity shards (mất tối đa 4 drive vẫn phục hồi được).
Một số command khác
shell> mc mb dcluster/test-bucket
Bucket created successfully `dcluster/test-bucket`.
shell> mc cp /etc/hosts dcluster/test-bucket/
/etc/hosts: 221 B / 221 B ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 11.97 KiB/s 0s
shell> mc ls dcluster/test-bucket
[2025-09-03 16:11:42 UTC] 221B STANDARD hosts
Lệnh dưới đây dùng để kiểm tra sức khỏe của cụm Minio
shell> mc admin heal dcluster
No active healing is detected for new disks.
Ý nghĩa của thông báo trên có nghĩa là cluster hiện tại không có disk/node nào vừa được thêm mới hoặc vừa khôi phục → Nói cách khác là toàn bộ dữ liệu và metadata trong cluster đang đồng bộ, khỏe mạnh.
10. Cơ chế EC của MinIO
- Với MinIO, bạn không thể chỉnh tay số lượng EC (data/parity) như Ceph hay GlusterFS.
- Khi bạn khai báo
minio server http://node{1...N}/data{1...M}
, tổng số ổ đĩa (drives) được xác định. - MinIO sẽ tự động chọn số data + parity theo thuật toán cố định.
- Quy tắc chung (phiên bản mới, như log bạn thấy):
- Parity = N/3 (làm tròn xuống).
- Data = N – Parity.
- Trong cụm của bạn: 12 drives → parity = 4, data = 8.
→ Như vậy MinIO sẽ tự động tính toán dựa trên tổng số drive. Bạn không thể chỉnh trực tiếp số EC. Nếu bạn muốn mức bảo vệ cao/thấp hơn → cách duy nhất là thay đổi số lượng node/disk để MinIO tính toán lại EC.
11. Lời khuyên
- Bắt đầu bằng môi trường A (single-host) để nắm lệnh
mc
, bucket, user, policy. - Khi chuyển sang môi trường B (multi-host), chuẩn hóa:
- IP/hostname, overlay network, port publish.
- Quy ước thư mục dữ liệu đồng nhất giữa các node.
- Viết script Makefile hoặc bash để
up/down/backup/restore
lặp lại ổn định. - Trước khi đưa dữ liệu thật, diễn tập: mất 1 node, mất 1 disk, khởi động lại, kiểm tra
mc admin heal
.
12. Kết luận
Với 4 node và mỗi node 3 disk, cấu hình ở trên cho phép bạn triển khai MinIO distributed 4×3 bằng Docker Swarm gọn gàng: đĩa bind-mount chuẩn hóa, service ràng buộc đúng node, DNS nội bộ đồng nhất (minio1..4
), port publish rõ ràng, sẵn sàng cho kiểm thử hiệu năng và chịu lỗi. Nếu bạn muốn, tôi có thể bổ sung script kiểm thử (kill 1–2 service, đo thông lượng) và mẫu policy/user cho ứng dụng cụ thể.