Triển Khai MinIO Distributed

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ẫu http://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.ymlminio.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ể.

Bài viết gần đây

spot_img

Related Stories

Leave A Reply

Please enter your comment!
Please enter your name here

Đăng ký nhận thông tin bài viết qua email