카테고리 없음

MinIO 스터디 2주차 - DirectPV & Perfomance

시스템엔지니어 2025. 9. 17. 19:55

실습 환경을 클라우드 포메이션으로 배포

# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/minio-ec2-1node.yaml

# CloudFormation 스택 배포
# aws cloudformation deploy --template-file kans-7w.yaml --stack-name mylab --parameter-overrides KeyName=<My SSH Keyname> SgIngressSshCidr=<My Home Public IP Address>/32 --region ap-northeast-2
예시) aws cloudformation deploy --template-file minio-ec2-1node.yaml --stack-name miniolab --parameter-overrides KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

## Tip. 인스턴스 타입 변경 : MyInstanceType=t3.xlarge (vCPU 4, Mem 16)
예시) aws cloudformation deploy --template-file minio-ec2-1node.yaml --stack-name miniolab --parameter-overrides MyInstanceType=t3.xlarge KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

# CloudFormation 스택 배포 완료 후 작업용 EC2 IP 출력
aws cloudformation describe-stacks --stack-name miniolab --query 'Stacks[*].Outputs[0].OutputValue' --output text --region ap-northeast-2

# [모니터링] CloudFormation 스택 상태 : 생성 완료 확인
while true; do 
  date
  AWS_PAGER="" aws cloudformation list-stacks \
    --stack-status-filter CREATE_IN_PROGRESS CREATE_COMPLETE CREATE_FAILED DELETE_IN_PROGRESS DELETE_FAILED \
    --query "StackSummaries[*].{StackName:StackName, StackStatus:StackStatus}" \
    --output table
  sleep 1
done

# 배포된 aws ec2 유동 공인 IP 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text
k3s-s   43.202.60.44    running

# EC2 SSH 접속 : 바로 접속하지 말고, 3~5분 정도 후에 접속 할 것
ssh -i ~/.ssh/kp-gasida.pem ubuntu@$(aws cloudformation describe-stacks --stack-name miniolab --query 'Stacks[*].Outputs[0].OutputValue' --output text --region ap-northeast-2)
...
(⎈|default:N/A) root@k3s-s:~# <- kubeps 가 나오지 않을 경우 ssh logout 후 다시 ssh 접속 할 것!

 

kc get node -owide
NAME     STATUS   ROLES                  AGE     VERSION         INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION   CONTAINER-RUNTIME
k3s-s    Ready    control-plane,master   2m12s   v1.28.15+k3s1   192.168.10.10    <none>        Ubuntu 22.04.5 LTS   6.8.0-1029-aws   containerd://1.7.22-k3s1.28

hostnamectl 
...
 Hardware Vendor: Amazon EC2
  Hardware Model: t3.xlarge

# Install Krew
wget -P /root "https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-linux_amd64.tar.gz"
tar zxvf "/root/krew-linux_amd64.tar.gz" --warning=no-unknown-keyword
./krew-linux_amd64 install krew
export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH" # export PATH="$PATH:/root/.krew/bin"
echo 'export PATH="$PATH:/root/.krew/bin:/root/go/bin"' >> /etc/profile
kubectl krew install get-all neat rolesum pexec stern
kubectl krew list

서버 접속 후 환경 설정

 

#
lsblk -a -o NAME,KNAME,MAJ:MIN,SIZE,TYPE,MOUNTPOINT,FSTYPE,UUID,MODEL,SERIAL
NAME         KNAME      MAJ:MIN  SIZE TYPE MOUNTPOINT                   FSTYPE   UUID                                 MODEL                      SERIAL
...
nvme0n1      nvme0n1    259:0     30G disk                                                                            Amazon Elastic Block Store vol0833a7ec553e64b74
├─nvme0n1p1  nvme0n1p1  259:5     29G part /                            ext4     0eec2352-4b50-40ec-ae93-7ce2911392bb                            
├─nvme0n1p14 nvme0n1p14 259:6      4M part                                                                                                       
├─nvme0n1p15 nvme0n1p15 259:7    106M part /boot/efi                    vfat     2586-E57C                                                       
└─nvme0n1p16 nvme0n1p16 259:8    913M part /boot                        ext4     1eb1aa76-4a46-48d9-95d8-a2ecf2d505c2                            
nvme1n1      nvme1n1    259:1     30G disk                                                                            Amazon Elastic Block Store vol0da5a82ea4ada0efc
nvme3n1      nvme3n1    259:2     30G disk                                                                            Amazon Elastic Block Store vol079fd88ba55971938
nvme2n1      nvme2n1    259:3     30G disk                                                                            Amazon Elastic Block Store vol012134019ba9f1c8a
nvme4n1      nvme4n1    259:4     30G disk                                                                            Amazon Elastic Block Store vol04d49a7ef31a119a2

# fio 설치 되어 있음
apt install fio -y
fio -h

# 측정 기본
## IOPS: 초당 입출력 횟수
## Throughput: 초당 MB 전송량
## Block size, Queue depth, RW 패턴 (랜덤/순차, 읽기/쓰기) 조합에 따라 결과가 달라집니다.
## AWS gp3는 기본 IOPS 3000/Throughput 125MB/s

# 4k 랜덤 읽기/쓰기, iodepth=16, numjobs=4
## --rw=randrw : 랜덤 읽기/쓰기 혼합
## --rwmixread=70 : 70% 읽기 / 30% 쓰기
## --bs=4k : 4KB 블록 → IOPS 측정용
## --iodepth=16 : 큐 깊이 16
## --numjobs=4 : 4개의 병렬 job
## --time_based --runtime=60 : 60초 동안 측정
## --group_reporting : 그룹 단위 결과 요약
fio --name=randrw_test \
  --filename=/mnt/testfile \
  --size=4G \
  --rw=randrw \
  --rwmixread=70 \
  --bs=4k \
  --iodepth=16 \
  --numjobs=4 \
  --time_based \
  --runtime=60 \
  --group_reporting

## 읽기 평균 IOPS : 2388
  read: IOPS=2388, BW=9553KiB/s (9782kB/s)(560MiB/60003msec)

## 쓰기 평균 IOPS : 1030
  write: IOPS=1030, BW=4121KiB/s (4220kB/s)(241MiB/60003msec); 0 zone resets

## 디스크 활용률 : 읽기/쓰기 IO 수량(132k/49k) , 디스크 활용률 87%
Disk stats (read/write):
  nvme0n1: ios=132972/49709, sectors=1063776/420736, merge=0/8, ticks=232695/154017, in_queue=386713, util=87.09%

디스크 I/O 성능 측정

 

# mlocate or plocate
systemctl disable --now plocate-updatedb 
systemctl list-timers | grep locate

# updatedb
systemctl disable --now updatedb.timer
systemctl list-timers | grep updatedb

# auditd
systemctl disable --now auditd
systemctl list-timers | grep audit

# Crowdstrike Falcon & Antivirus software (clamav)

MinIO 최적화 튜닝

- 파일 시스템, 시스템 수준 호출 또는 커널 수준 호출을 인덱싱, 스캔 또는 감사하는 시스템 서비스를 비활성화합니다.
- 이러한 서비스는 리소스 경합이나 MinIO 작업 차단으로 인해 성능이 저하될 수 있습니다.
- MinIO는 MinIO를 실행하는 호스트에서 다음 서비스를 제거하거나 비활성화할 것을 강력히 권장합니다.

 

#
sysctl -a > before.txt


# 설치 되어 있음
apt install tuned -y

# 서비스 시작
systemctl start tuned && systemctl enable tuned
cat /usr/lib/systemd/system/tuned.service

# To see the current active profile, run:
tuned-adm active
Current active profile: throughput-performance

# To show the current profile selection mode, run:
tuned-adm profile_mode
Profile selection mode: auto

# To list all available profiles, run:
tuned-adm list
Available profiles:
- accelerator-performance     - Throughput performance based tuning with disabled higher latency STOP states
- aws                         - Optimize for aws ec2 instances
- balanced                    - General non-specialized tuned profile
- balanced-battery            - Balanced profile biased towards power savings changes for battery
- desktop                     - Optimize for the desktop use-case
- hpc-compute                 - Optimize for HPC compute workloads
- intel-sst                   - Configure for Intel Speed Select Base Frequency
- latency-performance         - Optimize for deterministic performance at the cost of increased power consumption
- network-latency             - Optimize for deterministic performance at the cost of increased power consumption, focused on low latency network performance
- network-throughput          - Optimize for streaming network throughput, generally only necessary on older CPUs or 40G+ networks
- optimize-serial-console     - Optimize for serial console use.
- powersave                   - Optimize for low power consumption
- throughput-performance      - Broadly applicable tuning that provides excellent performance across a variety of common server workloads
- virtual-guest               - Optimize for running inside a virtual guest
- virtual-host                - Optimize for running KVM guests
Current active profile: throughput-performance

# To switch to a different profile, run:
## The enabled profile is persisted into /etc/tuned/active_profile, which is read when the daemon starts or is restarted.
tuned-adm profile <profile-name>

# To disable all tunings, run:
tuned-adm off

tuned-adm active
No current active profile.

#
tuned-adm profile virtual-guest

tuned-adm active
Current active profile: virtual-guest

#
sysctl -a > after.txt

#
vi -d before.txt after.txt


# 4k 랜덤 읽기/쓰기, iodepth=16, numjobs=4
fio --name=randrw_test \
  --filename=/mnt/testfile \
  --size=4G \
  --rw=randrw \
  --rwmixread=70 \
  --bs=4k \
  --iodepth=16 \
  --numjobs=4 \
  --time_based \
  --runtime=60 \
  --group_reporting

## 읽기 평균 IOPS : 2388
  read: IOPS=2395, BW=9584KiB/s (9814kB/s)(562MiB/60003msec)

## 읽기 평균 IOPS : 1030
  write: IOPS=1033, BW=4134KiB/s (4233kB/s)(242MiB/60003msec); 0 zone resets

## 디스크 활용률 : 읽기/쓰기 IO 수량(132k/49k) , 디스크 활용률 87%
Disk stats (read/write):
  nvme0n1: ios=133343/49277, sectors=1066744/416808, merge=0/43, ticks=231976/154776, in_queue=386752, util=86.35%

tuned profiles

 

 

DirectPV

DirectPV란 ?

MinIO DirectPV는 AGPL 3.0 라이선스 하에 배포되는 Kubernetes용 Container Storage Interface(CSI) 드라이버로, 직접 연결된 스토리지(Direct Attached Storage)를 위한 분산 퍼시스턴트 볼륨 관리자입니다.

  • DirectPV는 SAN(스토리지 영역 네트워크)이나 NAS(네트워크 연결 스토리지)와 같은 스토리지 시스템 자체가 아니라, 여러 서버에 걸친 로컬 드라이브를 발견(discover), 포맷(format), 마운트(mount), 스케줄(schedule), 모니터링(monitor)하는 기능을 제공합니다.
  • Kubernetes에서 기존 hostPath나 local PV가 정적이고 제한적인 반면, DirectPV는 경량이며 수만 개의 드라이브를 확장 가능하게 관리할 수 있도록 설계되었습니다.

구성요소

  • 명령줄 인터페이스를 통해 DirectPV CSI 드라이버를 관리하기 위해 로컬 머신에 설치된 DirectPV 플러그인
  • 로컬 볼륨을 프로비저닝하는 Kubernetes 클러스터에 직접 설치된 DirectPV CSI 드라이버

 

DirectPV 설치

#
k krew install directpv
k directpv -h

# 
k directpv install
┌──────────────────────────────────────┬──────────────────────────┐
│ NAME                                 │ KIND                     │
├──────────────────────────────────────┼──────────────────────────┤
│ directpv                             │ Namespace                │
│ directpv-min-io                      │ ServiceAccount           │
│ directpv-min-io                      │ ClusterRole              │
│ directpv-min-io                      │ ClusterRoleBinding       │
│ directpv-min-io                      │ Role                     │
│ directpv-min-io                      │ RoleBinding              │
│ directpvdrives.directpv.min.io       │ CustomResourceDefinition │
│ directpvvolumes.directpv.min.io      │ CustomResourceDefinition │
│ directpvnodes.directpv.min.io        │ CustomResourceDefinition │
│ directpvinitrequests.directpv.min.io │ CustomResourceDefinition │
│ directpv-min-io                      │ CSIDriver                │
│ directpv-min-io                      │ StorageClass             │
│ node-server                          │ Daemonset                │
│ controller                           │ Deployment               │
└──────────────────────────────────────┴──────────────────────────┘

#
k get crd | grep min
directpvdrives.directpv.min.io         2025-09-13T05:23:40Z
directpvinitrequests.directpv.min.io   2025-09-13T05:23:40Z
directpvnodes.directpv.min.io          2025-09-13T05:23:40Z
directpvvolumes.directpv.min.io        2025-09-13T05:23:40Z

k get sc directpv-min-io -o yaml | yq
k get sc
NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
directpv-min-io        directpv-min-io         Delete          WaitForFirstConsumer   true                   4m17s

k get-all -n directpv
k get deploy,ds,pod -n directpv
k rolesum directpv-min-io -n directpv

k get directpvnodes.directpv.min.io
k get directpvnodes.directpv.min.io -o yaml | yq


# controller 파드 1대 정보 확인
kc describe pod -n directpv controller-75d5595d5b-bqwbs
...
Containers:
  csi-provisioner:
    ...
    Args:
      --v=3
      --timeout=300s
      --csi-address=$(CSI_ENDPOINT)
      --leader-election
      --feature-gates=Topology=true
      --strict-topology
    ...
    Environment:
      CSI_ENDPOINT:  unix:///csi/csi.sock
    Mounts:
      /csi from socket-dir (rw)
  ...
  csi-resizer:
    ...
    Args:
      --v=3
      --timeout=300s
      --csi-address=$(CSI_ENDPOINT)
      --leader-election
    ...
    Environment:
      CSI_ENDPOINT:  unix:///csi/csi.sock
    Mounts:
      /csi from socket-dir (rw)
  ...
  controller:
    ...
    Args:
      controller
      --identity=directpv-min-io
      -v=3
      --csi-endpoint=$(CSI_ENDPOINT)
      --kube-node-name=$(KUBE_NODE_NAME)
      --readiness-port=30443
    ...
    Environment:
      KUBE_NODE_NAME:   (v1:spec.nodeName)
      CSI_ENDPOINT:    unix:///csi/csi.sock
    Mounts:
      /csi from socket-dir (rw)
...
Volumes:
  socket-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /var/lib/kubelet/plugins/controller-controller
    HostPathType:  DirectoryOrCreate
...

ls -l /var/lib/kubelet/plugins/controller-controller
total 0
srwxr-xr-x 1 root root 0 Sep 14 11:17 csi.sock

k get lease -n directpv -o yaml | yq
k get lease -n directpv
...

#
k get pod -n directpv -l selector.directpv.min.io.service=enabled
kc describe pod -n directpv -l selector.directpv.min.io.service=enabled
...
Containers:
  node-driver-registrar:
    ...
    Args:
      --v=3
      --csi-address=unix:///csi/csi.sock
      --kubelet-registration-path=/var/lib/kubelet/plugins/directpv-min-io/csi.sock

  node-server:
    ...
    Args:
      node-server
      -v=3
      --identity=directpv-min-io
      --csi-endpoint=$(CSI_ENDPOINT)
      --kube-node-name=$(KUBE_NODE_NAME)
      --readiness-port=30443
      --metrics-port=10443

  node-controller:
    ...
    Args:
      node-controller
      -v=3
      --kube-node-name=$(KUBE_NODE_NAME)

  liveness-probe:
    ...
    Args:
      --csi-address=/csi/csi.sock
      --health-port=9898

Volumes:
  socket-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /var/lib/kubelet/plugins/directpv-min-io
    HostPathType:  DirectoryOrCreate
  mountpoint-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /var/lib/kubelet/pods
    HostPathType:  DirectoryOrCreate
  registration-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /var/lib/kubelet/plugins_registry
    HostPathType:  DirectoryOrCreate
  plugins-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /var/lib/kubelet/plugins
    HostPathType:  DirectoryOrCreate
  directpv-common-root:
    Type:          HostPath (bare host directory volume)
    Path:          /var/lib/directpv/
    HostPathType:  DirectoryOrCreate
  direct-csi-common-root:
    Type:          HostPath (bare host directory volume)
    Path:          /var/lib/direct-csi/
    HostPathType:  DirectoryOrCreate
  sysfs:
    Type:          HostPath (bare host directory volume)
    Path:          /sys
    HostPathType:  DirectoryOrCreate
  devfs:
    Type:          HostPath (bare host directory volume)
    Path:          /dev
    HostPathType:  DirectoryOrCreate
  run-udev-data-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /run/udev/data
    HostPathType:  DirectoryOrCreate
...

 

DirectPV로 물리디스크 관리하기

#
k directpv info
┌─────────┬──────────┬───────────┬─────────┬────────┐
│ NODE    │ CAPACITY │ ALLOCATED │ VOLUMES │ DRIVES │
├─────────┼──────────┼───────────┼─────────┼────────┤
│ • k3s-s │ -        │ -         │ -       │ -      │
└─────────┴──────────┴───────────┴─────────┴────────┘

#
k directpv discover
 Discovered node 'k3s-s' ✔
┌─────────────────────┬───────┬─────────┬────────┬────────────┬────────────────────────────┬───────────┬─────────────┐
│ ID                  │ NODE  │ DRIVE   │ SIZE   │ FILESYSTEM │ MAKE                       │ AVAILABLE │ DESCRIPTION │
├─────────────────────┼───────┼─────────┼────────┼────────────┼────────────────────────────┼───────────┼─────────────┤
│ 259:1$Pna+Q57t+y... │ k3s-s │ nvme1n1 │ 30 GiB │ -          │ Amazon Elastic Block Store │ YES       │ -           │
│ 259:3$QURUJfcllF... │ k3s-s │ nvme2n1 │ 30 GiB │ -          │ Amazon Elastic Block Store │ YES       │ -           │
│ 259:2$/28TF0pThR... │ k3s-s │ nvme3n1 │ 30 GiB │ -          │ Amazon Elastic Block Store │ YES       │ -           │
│ 259:4$+AaiQHygVH... │ k3s-s │ nvme4n1 │ 30 GiB │ -          │ Amazon Elastic Block Store │ YES       │ -           │
└─────────────────────┴───────┴─────────┴────────┴────────────┴────────────────────────────┴───────────┴─────────────┘
Generated 'drives.yaml' successfully.

# (참고) 적용 예외 설정 시 select: "no" 설정
cat drives.yaml | yq
{
  "version": "v1",
  "nodes": [
    {
      "name": "k3s-s",
      "drives": [
        {
          "id": "259:4$+AaiQHygVHSl7AmoNWxVgP1kJsoha2CeGIzxfuoqBvw=",
          "name": "nvme4n1",
          "size": 32212254720,
          "make": "Amazon Elastic Block Store",
          "select": "yes"
        },
...

#
k directpv init drives.yaml
ERROR Initializing the drives will permanently erase existing data. Please review carefully before performing this *DANGEROUS* operation and retry this command with --dangerous flag.

# Perform initialization of drives which will permanently erase existing data
k directpv init drives.yaml --dangerous
Processed initialization request '75caf826-e374-4ff2-b4d6-bdbf1ac0e847' for node 'k3s-s' ✔

┌──────────────────────────────────────┬───────┬─────────┬─────────┐
│ REQUEST_ID                           │ NODE  │ DRIVE   │ MESSAGE │
├──────────────────────────────────────┼───────┼─────────┼─────────┤
│ 75caf826-e374-4ff2-b4d6-bdbf1ac0e847 │ k3s-s │ nvme1n1 │ Success │
│ 75caf826-e374-4ff2-b4d6-bdbf1ac0e847 │ k3s-s │ nvme2n1 │ Success │
│ 75caf826-e374-4ff2-b4d6-bdbf1ac0e847 │ k3s-s │ nvme3n1 │ Success │
│ 75caf826-e374-4ff2-b4d6-bdbf1ac0e847 │ k3s-s │ nvme4n1 │ Success │
└──────────────────────────────────────┴───────┴─────────┴─────────┘

#
k directpv list drives
┌───────┬─────────┬────────────────────────────┬────────┬────────┬─────────┬────────┐
│ NODE  │ NAME    │ MAKE                       │ SIZE   │ FREE   │ VOLUMES │ STATUS │
├───────┼─────────┼────────────────────────────┼────────┼────────┼─────────┼────────┤
│ k3s-s │ nvme1n1 │ Amazon Elastic Block Store │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ k3s-s │ nvme2n1 │ Amazon Elastic Block Store │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ k3s-s │ nvme3n1 │ Amazon Elastic Block Store │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ k3s-s │ nvme4n1 │ Amazon Elastic Block Store │ 30 GiB │ 30 GiB │ -       │ Ready  │
└───────┴─────────┴────────────────────────────┴────────┴────────┴─────────┴────────┘

k directpv info
┌─────────┬──────────┬───────────┬─────────┬────────┐
│ NODE    │ CAPACITY │ ALLOCATED │ VOLUMES │ DRIVES │
├─────────┼──────────┼───────────┼─────────┼────────┤
│ • k3s-s │ 120 GiB  │ 0 B       │ 0       │ 4      │
└─────────┴──────────┴───────────┴─────────┴────────┘
0 B/120 GiB used, 0 volumes, 4 drives


lsblk
NAME         MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
...
nvme1n1      259:1    0   30G  0 disk /var/lib/directpv/mnt/03ab4af0-14e3-47d2-ae39-2742c986a71d
nvme3n1      259:2    0   30G  0 disk /var/lib/directpv/mnt/8d0c7b6f-07f8-4908-bca6-5c14ad068400
nvme2n1      259:3    0   30G  0 disk /var/lib/directpv/mnt/324af346-29f1-4a9b-93bf-fbae1f21302d
nvme4n1      259:4    0   30G  0 disk /var/lib/directpv/mnt/088e2e11-8708-4a6c-8466-631c89c03f5c

df -hT --type xfs
/dev/nvme1n1    xfs        30G  248M   30G   1% /var/lib/directpv/mnt/03ab4af0-14e3-47d2-ae39-2742c986a71d
/dev/nvme4n1    xfs        30G  248M   30G   1% /var/lib/directpv/mnt/088e2e11-8708-4a6c-8466-631c89c03f5c
/dev/nvme3n1    xfs        30G  248M   30G   1% /var/lib/directpv/mnt/8d0c7b6f-07f8-4908-bca6-5c14ad068400
/dev/nvme2n1    xfs        30G  248M   30G   1% /var/lib/directpv/mnt/324af346-29f1-4a9b-93bf-fbae1f21302d

tree -h /var/lib/directpv/
[4.0K]  /var/lib/directpv/
├── [4.0K]  mnt
│   ├── [  75]  03ab4af0-14e3-47d2-ae39-2742c986a71d
│   ├── [  75]  088e2e11-8708-4a6c-8466-631c89c03f5c
│   ├── [  75]  324af346-29f1-4a9b-93bf-fbae1f21302d
│   └── [  75]  8d0c7b6f-07f8-4908-bca6-5c14ad068400
└── [  40]  tmp

#
k get directpvdrives.directpv.min.io -o yaml | yq
k get directpvdrives.directpv.min.io
NAME                                   AGE
03ab4af0-14e3-47d2-ae39-2742c986a71d   5m58s
088e2e11-8708-4a6c-8466-631c89c03f5c   5m58s
324af346-29f1-4a9b-93bf-fbae1f21302d   5m58s
8d0c7b6f-07f8-4908-bca6-5c14ad068400   5m58s

#
cat /etc/fstab

 

#
df -hT --type xfs
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme4n1   xfs    30G  248M   30G   1% /var/lib/directpv/mnt/ab82b195-5204-47fa-a864-a351f66b38d2
/dev/nvme2n1   xfs    30G  248M   30G   1% /var/lib/directpv/mnt/94be15e6-5d0d-49a9-a6d8-d139977a3446
/dev/nvme1n1   xfs    30G  248M   30G   1% /var/lib/directpv/mnt/dc26b422-5364-464e-bc54-a6ab6b8d4e32
/dev/nvme3n1   xfs    30G  248M   30G   1% /var/lib/directpv/mnt/246f427a-3e32-4311-b81c-fc9e45ebc6ad

lsblk
...
nvme1n1      259:0    0   30G  0 disk /var/lib/directpv/mnt/dc26b422-5364-464e-bc54-a6ab6b8d4e32
nvme3n1      259:2    0   30G  0 disk /var/lib/directpv/mnt/246f427a-3e32-4311-b81c-fc9e45ebc6ad
nvme4n1      259:3    0   30G  0 disk /var/lib/directpv/mnt/ab82b195-5204-47fa-a864-a351f66b38d2
nvme2n1      259:4    0   30G  0 disk /var/lib/directpv/mnt/94be15e6-5d0d-49a9-a6d8-d139977a3446

k get directpvdrives,directpvvolumes

#
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
spec:
  volumeMode: Filesystem
  storageClassName: directpv-min-io
  accessModes: [ "ReadWriteOnce" ]
  resources:
    requests:
      storage: 8Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  volumes:
    - name: nginx-volume
      persistentVolumeClaim:
        claimName: nginx-pvc
  containers:
    - name: nginx-container
      image: nginx:alpine
      volumeMounts:
        - mountPath: "/mnt"
          name: nginx-volume
EOF

#
k get pod,pvc,pv
NAME            READY   STATUS    RESTARTS   AGE
pod/nginx-pod   1/1     Running   0          2m27s

NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/nginx-pvc   Bound    pvc-97418e78-41db-4244-a3d5-e56b94c6c2bd   8Mi        RWO            directpv-min-io   <unset>                 2m27s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS      VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pvc-97418e78-41db-4244-a3d5-e56b94c6c2bd   8Mi        RWO            Delete           Bound    default/nginx-pvc   directpv-min-io   <unset>                          2m27s

k exec -it nginx-pod -- df -hT -t xfs
Filesystem           Type            Size      Used Available Use% Mounted on
/dev/nvme3n1         xfs             8.0M      4.0K      8.0M   0% /mnt

k exec -it nginx-pod -- sh -c 'echo hello > /mnt/hello.txt'
k exec -it nginx-pod -- sh -c 'cat /mnt/hello.txt'
hello

#
lsblk
nvme1n1      259:0    0   30G  0 disk /var/lib/directpv/mnt/dc26b422-5364-464e-bc54-a6ab6b8d4e32
nvme4n1      259:3    0   30G  0 disk /var/lib/directpv/mnt/ab82b195-5204-47fa-a864-a351f66b38d2
nvme2n1      259:4    0   30G  0 disk /var/lib/directpv/mnt/94be15e6-5d0d-49a9-a6d8-d139977a3446
nvme3n1      259:2    0   30G  0 disk /var/lib/kubelet/pods/171f29cf-45e1-458f-b20e-082a78702e03/volumes/kubernetes.io~csi/pvc-97418e78-41db-4244-a3d5-e56b94c6c2bd/mount
                                      /var/lib/kubelet/plugins/kubernetes.io/csi/directpv-min-io/0a26dd2aeb3b456582028ecddabce74e4684252502203e78f857fa23e738649b/globalmount
                                      /var/lib/directpv/mnt/246f427a-3e32-4311-b81c-fc9e45ebc6ad

tree -a /var/lib/directpv/mnt
/var/lib/directpv/mnt
├── 246f427a-3e32-4311-b81c-fc9e45ebc6ad
│   ├── .FSUUID.246f427a-3e32-4311-b81c-fc9e45ebc6ad -> .
│   ├── .directpv
│   │   └── meta.info
│   └── pvc-97418e78-41db-4244-a3d5-e56b94c6c2bd
│       └── hello.txt
├── 94be15e6-5d0d-49a9-a6d8-d139977a3446
│   ├── .FSUUID.94be15e6-5d0d-49a9-a6d8-d139977a3446 -> .
│   └── .directpv
│       └── meta.info
├── ab82b195-5204-47fa-a864-a351f66b38d2
│   ├── .FSUUID.ab82b195-5204-47fa-a864-a351f66b38d2 -> .
│   └── .directpv
│       └── meta.info
└── dc26b422-5364-464e-bc54-a6ab6b8d4e32
    ├── .FSUUID.dc26b422-5364-464e-bc54-a6ab6b8d4e32 -> .
    └── .directpv
        └── meta.info
        
cat /var/lib/directpv/mnt/*/pvc*/hello.txt
hello

#
k get directpvvolumes
k get directpvvolumes -o yaml | yq


#
k delete pod nginx-pod
k get pvc,pv
k delete pvc nginx-pvc
k get pv

#
lsblk
tree -a /var/lib/directpv/mnt

 

특정 Drive에 볼륨 사용 테스트(label)

#
k directpv list drives
┌───────┬─────────┬────────────────────────────┬────────┬────────┬─────────┬────────┐
│ NODE  │ NAME    │ MAKE                       │ SIZE   │ FREE   │ VOLUMES │ STATUS │
├───────┼─────────┼────────────────────────────┼────────┼────────┼─────────┼────────┤
│ k3s-s │ nvme1n1 │ Amazon Elastic Block Store │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ k3s-s │ nvme2n1 │ Amazon Elastic Block Store │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ k3s-s │ nvme3n1 │ Amazon Elastic Block Store │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ k3s-s │ nvme4n1 │ Amazon Elastic Block Store │ 30 GiB │ 30 GiB │ -       │ Ready  │
└───────┴─────────┴────────────────────────────┴────────┴────────┴─────────┴────────┘

# Label the 'nvme1n1' drive in all nodes as 'fast' with the 'tier' key.
kubectl directpv label drives --drives=nvme1n1 tier=fast

# Verify that the labels are properly set by using the list command with the
k directpv list drives --show-labels
kubectl directpv list drives --drives /dev/nvme1n1 --show-labels
┌───────┬─────────┬────────────────────────────┬────────┬────────┬─────────┬────────┬───────────┐
│ NODE  │ NAME    │ MAKE                       │ SIZE   │ FREE   │ VOLUMES │ STATUS │ LABELS    │
├───────┼─────────┼────────────────────────────┼────────┼────────┼─────────┼────────┼───────────┤
│ k3s-s │ nvme1n1 │ Amazon Elastic Block Store │ 30 GiB │ 30 GiB │ -       │ Ready  │ tier=fast │
└───────┴─────────┴────────────────────────────┴────────┴────────┴─────────┴────────┴───────────┘

#
k get sc
vi create-storage-class.sh
chmod +x create-storage-class.sh
./create-storage-class.sh -h

#
./create-storage-class.sh fast-tier-storage 'directpv.min.io/tier: fast'
k get sc
kc describe sc fast-tier-storage
...
Parameters:            directpv.min.io/tier=fast,fstype=xfs
...

#
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
spec:
  volumeMode: Filesystem
  storageClassName: fast-tier-storage
  accessModes: [ "ReadWriteOnce" ]
  resources:
    requests:
      storage: 8Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  volumes:
    - name: nginx-volume
      persistentVolumeClaim:
        claimName: nginx-pvc
  containers:
    - name: nginx-container
      image: nginx:alpine
      volumeMounts:
        - mountPath: "/mnt"
          name: nginx-volume
EOF

# 해당 drive가 있는 node 에 pv 가 만들어지고, 파드 역시 해당 node 에 기동되었음
k get pod,pvc,pv -owide
NAME            READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
pod/nginx-pod   1/1     Running   0          11s   10.42.0.13   k3s-s   <none>           <none>

NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        VOLUMEATTRIBUTESCLASS   AGE   VOLUMEMODE
persistentvolumeclaim/nginx-pvc   Bound    pvc-127ee2bb-b4b6-4cc5-bfdd-d79b2e7e5957   8Mi        RWO            fast-tier-storage   <unset>                 11s   Filesystem

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS        VOLUMEATTRIBUTESCLASS   REASON   AGE   VOLUMEMODE
persistentvolume/pvc-127ee2bb-b4b6-4cc5-bfdd-d79b2e7e5957   8Mi        RWO            Delete           Bound    default/nginx-pvc   fast-tier-storage   <unset>                          11s   Filesystem

kc describe pv
...
Node Affinity:
  Required Terms:
    Term 0:        directpv.min.io/identity in [directpv-min-io]
                   directpv.min.io/node in [k3s-s]
                   directpv.min.io/rack in [default]
                   directpv.min.io/region in [default]
                   directpv.min.io/zone in [default]
Message:
Source:
    Type:              CSI (a Container Storage Interface (CSI) volume source)
    Driver:            directpv-min-io
    FSType:            xfs
    VolumeHandle:      pvc-127ee2bb-b4b6-4cc5-bfdd-d79b2e7e5957
    ReadOnly:          false
    VolumeAttributes:      directpv.min.io/tier=fast
                           fstype=xfs
                           storage.kubernetes.io/csiProvisionerIdentity=1757816235335-1863-directpv-min-io

#
kc describe node
...
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/instance-type=k3s
                    beta.kubernetes.io/os=linux
                    directpv.min.io/identity=directpv-min-io
                    directpv.min.io/node=k3s-s
                    directpv.min.io/rack=default
                    directpv.min.io/region=default
                    directpv.min.io/zone=default
...

#
k get directpvnodes.directpv.min.io -o yaml | yq
kc describe directpvdrives.directpv.min.io
Name:         dc26b422-5364-464e-bc54-a6ab6b8d4e32
Namespace:
Labels:       directpv.min.io/access-tier=Default
              directpv.min.io/created-by=directpv-driver
              directpv.min.io/drive-name=nvme1n1
              directpv.min.io/node=k3s-s
              directpv.min.io/tier=fast
              directpv.min.io/version=v1beta1

# 삭제
kubectl delete pod nginx-pod && kubectl delete pvc nginx-pvc

 

 

 

라벨 활용법

#
k label nodes k3s-s directpv.min.io/rack=rack01 --overwrite
node/k3s-s labeled

kc describe node
...
                    directpv.min.io/rack=rack01

kc describe directpvdrives.directpv.min.io
...
 Topology:
   directpv.min.io/rack:      default

#
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
spec:
  volumeMode: Filesystem
  storageClassName: fast-tier-storage
  accessModes: [ "ReadWriteOnce" ]
  resources:
    requests:
      storage: 8Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  volumes:
    - name: nginx-volume
      persistentVolumeClaim:
        claimName: nginx-pvc
  containers:
    - name: nginx-container
      image: nginx:alpine
      volumeMounts:
        - mountPath: "/mnt"
          name: nginx-volume
EOF

#
k get pod,pvc,pv
NAME            READY   STATUS    RESTARTS   AGE
pod/nginx-pod   0/1     Pending   0          4s

NAME                              STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS        VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/nginx-pvc   Pending                                      fast-tier-storage   <unset>                 4s

#
kc describe pod
...
Events:
  Type     Reason            Age               From               Message
  ----     ------            ----              ----               -------
  Warning  FailedScheduling  15s               default-scheduler  running PreBind plugin "VolumeBinding": binding volumes: provisioning failed for PVC "nginx-pvc"
  Warning  FailedScheduling  9s (x2 over 13s)  default-scheduler  running PreBind plugin "VolumeBinding": binding volumes: provisioning failed for PVC "nginx-pvc"

# no drive found for requested topology
kc describe pvc
...
Events:
  Type     Reason                Age                From                                                                              Message
  ----     ------                ----               ----                                                                              -------
  Normal   WaitForFirstConsumer  66s                persistentvolume-controller                                                       waiting for first consumer to be created before binding
  Normal   ExternalProvisioning  7s (x9 over 66s)   persistentvolume-controller                                                       Waiting for a volume to be created either by the external provisioner 'directpv-min-io' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.
  Normal   Provisioning          7s (x8 over 66s)   directpv-min-io_controller-75d5595d5b-bqwbs_4e34d69c-36a7-4c94-8ce0-a02df9c63fc8  External provisioner is provisioning volume for claim "default/nginx-pvc"
  Warning  ProvisioningFailed    7s (x8 over 66s)   directpv-min-io_controller-75d5595d5b-bqwbs_4e34d69c-36a7-4c94-8ce0-a02df9c63fc8  failed to provision volume with StorageClass "fast-tier-storage": rpc error: code = ResourceExhausted desc = no drive found for requested topology; requested node(s): k3s-s; requested size: 8388608 bytes

# 해결 1 : label 값 원복
k label nodes k3s-s directpv.min.io/rack=default --overwrite

# 해결 2 : directpvdrives CR에 label 값 directpv.min.io/rack=rack01 로 수정

# 확인
k get pod,pvc,pv

# 삭제
kubectl delete pod nginx-pod && kubectl delete pvc nginx-pvc

 

  Warning  ProvisioningFailed    7s (x5 over 30s)  directpv-min-io_controller-5db75d68cc-tx8vw_4d6e6fba-d62e-4a05-bd6c-82fc8a68a4c9  failed to provision volume with StorageClass "fast-tier-storage": rpc error: code = ResourceExhausted desc = no drive found for requested topology; requested node(s): k3s-s; requested size: 8388608 bytes

 

 

 

MinIO 설치  & 버킷 생성

#
helm repo add minio-operator https://operator.min.io

# https://github.com/minio/operator/blob/master/helm/operator/values.yaml
cat << EOF > minio-operator-values.yaml
operator:  
  env:
  - name: MINIO_OPERATOR_RUNTIME
    value: "Rancher"
  replicaCount: 1
EOF
helm install --namespace minio-operator --create-namespace minio-operator minio-operator/operator --values minio-operator-values.yaml

# 확인 : 참고로 현재는 오퍼레이터 관리 웹 미제공
k get-all -n minio-operator
k get pod,svc,ep -n minio-operator
k get crd
k exec -it -n minio-operator deploy/minio-operator -- env | grep MINIO
MINIO_OPERATOR_RUNTIME=Rancher

------------------------------------------------------
# If using Amazon Elastic Block Store (EBS) CSI driver : Please make sure to set xfs for "csi.storage.k8s.io/fstype" parameter under StorageClass.parameters.
k get sc directpv-min-io -o yaml | grep -i fstype
  csi.storage.k8s.io/fstype: xfs

  
# tenant values : https://github.com/minio/operator/blob/master/helm/tenant/values.yaml
cat << EOF > minio-tenant-1-values.yaml
tenant:
  name: tenant1

  configSecret:
    name: tenant1-env-configuration
    accessKey: minio
    secretKey: minio123

  pools:
    - servers: 1
      name: pool-0
      volumesPerServer: 4
      size: 10Gi 
      storageClassName: directpv-min-io
  env:
    - name: MINIO_STORAGE_CLASS_STANDARD
      value: "EC:1"

  metrics:
    enabled: true
    port: 9000
    protocol: http
EOF
helm install --namespace tenant1 --create-namespace --values minio-tenant-1-values.yaml tenant1 minio-operator/tenant \
 && kubectl get tenants -A -w

#
kubectl get tenants -n tenant1
kubectl get tenants -n tenant1 -owide -o yaml | yq
kc describe tenants -n tenant1

#
lsblk
k directpv info
k directpv list drives
k directpv list volumes
┌──────────────────────────────────────────┬──────────┬───────┬─────────┬──────────────────┬──────────────┬─────────┐
│ VOLUME                                   │ CAPACITY │ NODE  │ DRIVE   │ PODNAME          │ PODNAMESPACE │ STATUS  │
├──────────────────────────────────────────┼──────────┼───────┼─────────┼──────────────────┼──────────────┼─────────┤
│ pvc-ae274681-c458-409c-a61c-a018f26e2580 │ 10 GiB   │ k3s-s │ nvme1n1 │ myminio-pool-0-0 │ tenant-0     │ Bounded │
│ pvc-8f8df2f7-7f93-4531-b0da-1dbc8affa8df │ 10 GiB   │ k3s-s │ nvme2n1 │ myminio-pool-0-0 │ tenant-0     │ Bounded │
│ pvc-0ab32dfd-0330-405e-8902-78f917bd71ec │ 10 GiB   │ k3s-s │ nvme3n1 │ myminio-pool-0-0 │ tenant-0     │ Bounded │
│ pvc-bfc21d48-87aa-4bf0-ab3f-c1b9acd6b716 │ 10 GiB   │ k3s-s │ nvme4n1 │ myminio-pool-0-0 │ tenant-0     │ Bounded │
└──────────────────────────────────────────┴──────────┴───────┴─────────┴──────────────────┴──────────────┴─────────┘

k get directpvvolumes.directpv.min.io
k get directpvvolumes.directpv.min.io -o yaml | yq
kc describe directpvvolumes
tree -ah /var/lib/kubelet/plugins
tree -ah /var/lib/directpv/mnt
cat /var/lib/kubelet/plugins/kubernetes.io/csi/directpv-min-io/*/vol_data.json
{"driverName":"directpv-min-io","volumeHandle":"pvc-0ab32dfd-0330-405e-8902-78f917bd71ec"}
{"driverName":"directpv-min-io","volumeHandle":"pvc-8f8df2f7-7f93-4531-b0da-1dbc8affa8df"}
{"driverName":"directpv-min-io","volumeHandle":"pvc-ae274681-c458-409c-a61c-a018f26e2580"}
{"driverName":"directpv-min-io","volumeHandle":"pvc-bfc21d48-87aa-4bf0-ab3f-c1b9acd6b716"}

#
k get pvc -n tenant1
k get pvc -n tenant1 -o yaml | yq
kc describe pvc -n tenant1


#
kubectl get sts,pod,svc,ep,pvc,secret -n tenant1
kubectl get pod -n tenant1 -l v1.min.io/pool=pool-0 -owide
kc describe pod -n tenant1 -l v1.min.io/pool=pool-0
kubectl stern -n tenant1 -l v1.min.io/pool=pool-0
kubectl exec -it -n tenant1 sts/tenant1-pool-0 -c minio -- id
kubectl exec -it -n tenant1 sts/tenant1-pool-0 -c minio -- env
kubectl exec -it -n tenant1 sts/tenant1-pool-0 -c minio -- cat /tmp/minio/config.env
kubectl get secret -n tenant1 tenant1-env-configuration -o jsonpath='{.data.config\.env}' | base64 -d ; echo
kubectl get secret -n tenant1 tenant1-tls -o jsonpath='{.data.public\.crt}' | base64 -d
kubectl get secret -n tenant1 tenant1-tls -o jsonpath='{.data.public\.crt}' | base64 -d | openssl x509 -noout -text
...
            X509v3 Subject Alternative Name:
                DNS:tenant1-pool-0-0.tenant1-hl.tenant1.svc.cluster.local, DNS:minio.tenant1.svc.cluster.local, DNS:minio.tenant1, DNS:minio.tenant1.svc, DNS:*., DNS:*.tenant1.svc.cluster.local
                
#
kubectl patch svc -n tenant1 tenant1-console -p '{"spec": {"type": "NodePort", "ports": [{"port": 9443, "targetPort": 9443, "nodePort": 30001}]}}'

# 기본키(minio , minio123)
echo "https://$(curl -s ipinfo.io/ip):30001"

#
kubectl patch svc -n tenant1 minio -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 9000, "nodePort": 30002}]}}'


# mc alias
mc alias set k8s-tenant1 https://127.0.0.1:30002 minio minio123 --insecure
mc alias list
mc admin info k8s-tenant1 --insecure

# 버킷 생성
mc mb k8s-tenant1/mybucket --insecure
mc ls k8s-tenant1 --insecure

 

 

 

 

# mc alias
mc alias set k8s-tenant1 https://127.0.0.1:30002 minio minio123 --insecure
mc alias list
...
k8s-tenant1
  URL       : https://127.0.0.1:30002
  AccessKey : minio
  SecretKey : minio123
  API       : s3v4
  Path      : auto
  Src       : /root/.mc/config.json
...

tree -a ~/.mc
/root/.mc
├── certs # certificates
│   └── CAs # Certificate Authorities
├── config.json 
├── config.json.old
└── share
    ├── downloads.json
    └── uploads.json
    
mc admin info k8s-tenant1 --insecure

# 버킷 생성
mc mb k8s-tenant1/mybucket --insecure
mc ls k8s-tenant1 --insecure

# 바로 위에서 설정한 내용
------------------------------------------
# 아래 부터 실습 진행

# [신규 터미널] 모니터링 Show HTTP call trace for all incoming and internode on MinIO
# https://docs.min.io/community/minio-object-store/reference/minio-mc-admin/mc-admin-trace.html
mc admin trace -v -a k8s-tenant1 --insecure
# mc admin trace --errors -v -a k8s-tenant1 --insecure # 4xx, 5xx 에러만 보기
     
# https://docs.min.io/community/minio-object-store/reference/minio-mc/mc-ls.html
mc ls --summarize --recursive k8s-tenant1 --insecure

# https://docs.min.io/community/minio-object-store/reference/minio-mc/mc-cat.html
echo hello > hello.txt
mc cp ./hello.txt k8s-tenant1/mybucket/ --insecure
mc cat k8s-tenant1/mybucket/hello.txt --insecure

# 100MB 파일 생성
</dev/urandom tr -dc 'A-Za-z0-9' | head -c 100M > randtext.txt
ls -alh randtext.txt
-rw-r--r-- 1 root root 100M Sep 14 15:08 randtext.txt

cat randtext.txt | md5sum

# https://docs.min.io/community/minio-object-store/reference/minio-mc/mc-cp.html
mc cp ./randtext.txt k8s-tenant1/mybucket/ --insecure
/root/randtext.txt:     100.00 MiB / 100.00 MiB ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 320.47 MiB/s 0s

mc cat k8s-tenant1/mybucket/randtext.txt --insecure | md5sum

# MinIO Multipart Upload는 '큰 파일을 S3 방식으로 업로드할 때 쪼개서 올리고, 다 올리면 서버가 합쳐주는' 기능
[Client] ---CreateMultipartUpload---> [MinIO]
         <--- UploadId ---------------
[Client] ---UploadPart(part1)--------> [MinIO]
[Client] ---UploadPart(part2)--------> [MinIO]
...
[Client] ---CompleteMultipartUpload--> [MinIO]
         <--- OK + Final Object -------
mc admin trace -v -a k8s-tenant1 --insecure
127.0.0.1:30002 [REQUEST s3.CompleteMultipartUpload] [2025-09-14T15:11:04.710] [Client IP: 10.42.0.1]
127.0.0.1:30002 POST /mybucket/randtext.txt?uploadId=ZTMyZjNlMjAtZDkyNi00YjcyLTlhNGItZTI4ODBiNzBmZTM1LmY3N2ZiOTY0LWM5NmItNDE5YS1iNThmLWY3ODAyM2FmY2JjM3gxNzU3ODMwMjY0NDE5MzA0NDQ1
127.0.0.1:30002 Proto: HTTP/1.1
127.0.0.1:30002 Host: 127.0.0.1:30002
127.0.0.1:30002 Content-Type: application/octet-stream
127.0.0.1:30002 User-Agent: MinIO (linux; amd64) minio-go/v7.0.90 mc/RELEASE.2025-08-13T08-35-41Z
127.0.0.1:30002 X-Amz-Content-Sha256: 159a60374060e572e313b089f1d4658285b3676e38c08cdba940c0342f7431a9
127.0.0.1:30002 X-Amz-Date: 20250914T061104Z
127.0.0.1:30002 Accept-Encoding: zstd,gzip
127.0.0.1:30002 Authorization: AWS4-HMAC-SHA256 Credential=minio/20250914/us-east-1/s3/aws4_request, SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=3006225675b1e83ec73a4acdc49e14912ea547e075be739cc9a580ebde31a858
127.0.0.1:30002 Content-Length: 687
127.0.0.1:30002 <CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Part><PartNumber>1</PartNumber><ETag>2e7fda86cc02f78e25480c65efb94a29</ETag></Part><Part><PartNumber>2</PartNumber><ETag>e2b66d6f0368ce9a13de6ca12ed78a90</ETag></Part><Part><PartNumber>3</PartNumber><ETag>7b0ae1958b0f62992b13dfe4a7dddf07</ETag></Part><Part><PartNumber>4</PartNumber><ETag>942130b42c320b33a77ad9812416546b</ETag></Part><Part><PartNumber>5</PartNumber><ETag>81bea9efbeb94cadacb210343698806d</ETag></Part><Part><PartNumber>6</PartNumber><ETag>89c6655445c13b36c83a37b8b8e589c1</ETag></Part><Part><PartNumber>7</PartNumber><ETag>084d78f3c6126f91dc72c1933754ec46</ETag></Part></CompleteMultipartUpload>

127.0.0.1:30002 [RESPONSE] [2025-09-14T15:11:04.717] [ Duration 7.469ms TTFB 7.391942ms ↑ 793 B  ↓ 321 B ]
...
<CompleteMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Location>https://127.0.0.1:30002/mybucket/randtext.txt</Location><Bucket>mybucket</Bucket><Key>randtext.txt</Key><ETag>&#34;2ab7293624b88db302add6a2cacdd804-7&#34;</ETag></CompleteMultipartUploadResult>
# 참고) put https://docs.min.io/community/minio-object-store/reference/minio-mc/mc-put.html


#
cp randtext.txt randtext2.txt
mc cp ./randtext2.txt k8s-tenant1/mybucket/ --disable-multipart --insecure
/root/randtext2.txt:    100.00 MiB / 100.00 MiB ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 290.70 MiB/s 0s

#
mc ls --summarize --recursive --versions k8s-tenant1 --insecure
[2025-09-14 14:36:17 KST]     0B mybucket/
[2025-09-14 15:11:04 KST] 100MiB STANDARD null v1 PUT mybucket/randtext.txt
[2025-09-14 15:17:43 KST] 100MiB STANDARD null v1 PUT mybucket/randtext2.txt
Total Size: 200 MiB
Total Objects: 3

# 
k exec -it -n tenant1 tenant1-pool-0-0 -c minio -- sh -c 'df -hT --type xfs'
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme2n1   xfs    10G   67M   10G   1% /export0
/dev/nvme1n1   xfs    10G   67M   10G   1% /export1
/dev/nvme3n1   xfs    10G   67M   10G   1% /export2
/dev/nvme4n1   xfs    10G   67M   10G   1% /export3

k exec -it -n tenant1 tenant1-pool-0-0 -c minio -- ls -R /export0
k exec -it -n tenant1 tenant1-pool-0-0 -c minio -- ls -R /export1
k exec -it -n tenant1 tenant1-pool-0-0 -c minio -- ls -R /export2
k exec -it -n tenant1 tenant1-pool-0-0 -c minio -- ls -R /export3

#
tree -a /var/lib/directpv/mnt
...
            └── mybucket
                ├── randtext.txt
                │   ├── 13a96fc7-0dc5-48c2-b949-24ec24322d31
                │   │   ├── part.1
                │   │   ├── part.2
                │   │   ├── part.3
                │   │   ├── part.4
                │   │   ├── part.5
                │   │   ├── part.6
                │   │   └── part.7
                │   └── xl.meta
                └── randtext2.txt
                    ├── 287967c0-a38e-4734-b797-36ea1c76147a
                    │   └── part.1
                    └── xl.meta

# rm - https://docs.min.io/community/minio-object-store/reference/minio-mc/mc-rm.html
mc rm k8s-tenant1/mybucket/randtext2.txt --insecure
127.0.0.1:30002 [REQUEST s3.DeleteMultipleObjects] [2025-09-14T15:34:27.955] [Client IP: 10.42.0.1]
127.0.0.1:30002 POST /mybucket/?delete=
...

#
mc cp k8s-tenant1/mybucket/randtext.txt ./randtext3.txt  --insecure
127.0.0.1:9000  [OS os.OpenFileR] [2025-09-14T15:46:10.530] /export3/data/mybucket/randtext.txt/13a96fc7-0dc5-48c2-b949-24ec24322d31/part.4 25.794µs
127.0.0.1:9000  [OS os.OpenFileR] [2025-09-14T15:46:10.530] /export1/data/mybucket/randtext.txt/13a96fc7-0dc5-48c2-b949-24ec24322d31/part.4 32.617µs
127.0.0.1:9000  [STORAGE storage.ReadFileStream] [2025-09-14T15:46:10.530] /export3/data mybucket randtext.txt/13a96fc7-0dc5-48c2-b949-24ec24322d31/part.4 total-errs-availability=0 total-errs-timeout=0 54.316µs 5.3 MiB
127.0.0.1:9000  [STORAGE storage.ReadFileStream] [2025-09-14T15:46:10.530] /export1/data mybucket randtext.txt/13a96fc7-0dc5-48c2-b949-24ec24322d31/part.4 total-errs-timeout=0 total-errs-availability=0 63.241µs 5.3 MiB
...
127.0.0.1:30002 [REQUEST s3.GetObject] [2025-09-14T15:46:10.435] [Client IP: 10.42.0.1]
127.0.0.1:30002 GET /mybucket/randtext.txt
127.0.0.1:30002 Proto: HTTP/1.1
127.0.0.1:30002 Host: 127.0.0.1:30002
127.0.0.1:30002 Accept-Encoding: identity
127.0.0.1:30002 Authorization: AWS4-HMAC-SHA256 Credential=minio/20250914/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=ae36a34bc4a7db66f08970b3f295da8084d03236448a04d23a23b79c87026710
127.0.0.1:30002 Content-Length: 0
127.0.0.1:30002 User-Agent: MinIO (linux; amd64) minio-go/v7.0.90 mc/RELEASE.2025-08-13T08-35-41Z
127.0.0.1:30002 X-Amz-Content-Sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
127.0.0.1:30002 X-Amz-Date: 20250914T064610Z
127.0.0.1:30002 <BLOB>
127.0.0.1:30002 [RESPONSE] [2025-09-14T15:46:10.645] [ Duration 209.83ms TTFB 4.247996ms ↑ 93 B  ↓ 100 MiB ]
...

mc ls, cp, rm 실습

 

파드 재기동 없이 볼륨 확장

#
kubectl get pvc -n tenant1

k directpv list drives
┌───────┬─────────┬────────────────────────────┬────────┬────────┬─────────┬────────┐
│ NODE  │ NAME    │ MAKE                       │ SIZE   │ FREE   │ VOLUMES │ STATUS │
├───────┼─────────┼────────────────────────────┼────────┼────────┼─────────┼────────┤
│ k3s-s │ nvme1n1 │ Amazon Elastic Block Store │ 30 GiB │ 20 GiB │ 1       │ Ready  │
│ k3s-s │ nvme2n1 │ Amazon Elastic Block Store │ 30 GiB │ 20 GiB │ 1       │ Ready  │
│ k3s-s │ nvme3n1 │ Amazon Elastic Block Store │ 30 GiB │ 20 GiB │ 1       │ Ready  │
│ k3s-s │ nvme4n1 │ Amazon Elastic Block Store │ 30 GiB │ 20 GiB │ 1       │ Ready  │
└───────┴─────────┴────────────────────────────┴────────┴────────┴─────────┴────────┘

k directpv info
┌─────────┬──────────┬───────────┬─────────┬────────┐
│ NODE    │ CAPACITY │ ALLOCATED │ VOLUMES │ DRIVES │
├─────────┼──────────┼───────────┼─────────┼────────┤
│ • k3s-s │ 120 GiB  │ 40 GiB    │ 4       │ 4      │
└─────────┴──────────┴───────────┴─────────┴────────┘

#
kubectl patch pvc -n tenant1 data0-tenant1-pool-0-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
kubectl patch pvc -n tenant1 data1-tenant1-pool-0-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
kubectl patch pvc -n tenant1 data2-tenant1-pool-0-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
kubectl patch pvc -n tenant1 data3-tenant1-pool-0-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'

#
kubectl get pvc -n tenant1

k directpv list drives
┌───────┬─────────┬────────────────────────────┬────────┬────────┬─────────┬────────┐
│ NODE  │ NAME    │ MAKE                       │ SIZE   │ FREE   │ VOLUMES │ STATUS │
├───────┼─────────┼────────────────────────────┼────────┼────────┼─────────┼────────┤
│ k3s-s │ nvme1n1 │ Amazon Elastic Block Store │ 30 GiB │ 10 GiB │ 1       │ Ready  │
│ k3s-s │ nvme2n1 │ Amazon Elastic Block Store │ 30 GiB │ 10 GiB │ 1       │ Ready  │
│ k3s-s │ nvme3n1 │ Amazon Elastic Block Store │ 30 GiB │ 10 GiB │ 1       │ Ready  │
│ k3s-s │ nvme4n1 │ Amazon Elastic Block Store │ 30 GiB │ 10 GiB │ 1       │ Ready  │
└───────┴─────────┴────────────────────────────┴────────┴────────┴─────────┴────────┘

k directpv info
┌─────────┬──────────┬───────────┬─────────┬────────┐
│ NODE    │ CAPACITY │ ALLOCATED │ VOLUMES │ DRIVES │
├─────────┼──────────┼───────────┼─────────┼────────┤
│ • k3s-s │ 120 GiB  │ 80 GiB    │ 4       │ 4      │
└─────────┴──────────┴───────────┴─────────┴────────┘

# 아래 파드 내에서 볼륨 Size 가 20G 로 조금 시간 지나면 자동 확장 반영 된다.
k exec -it -n tenant1 tenant1-pool-0-0 -c minio -- sh -c 'df -hT --type xfs'
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme1n1   xfs    10G   34M   10G   1% /export0
/dev/nvme2n1   xfs    10G   34M   10G   1% /export1
/dev/nvme3n1   xfs    10G   34M   10G   1% /export2
/dev/nvme4n1   xfs    10G   34M   10G   1% /export3

k exec -it -n tenant1 tenant1-pool-0-0 -c minio -- sh -c 'df -hT --type xfs'
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme1n1   xfs    20G   34M   20G   1% /export0
/dev/nvme2n1   xfs    20G   34M   20G   1% /export1
/dev/nvme3n1   xfs    20G   34M   20G   1% /export2
/dev/nvme4n1   xfs    20G   34M   20G   1% /export3

 

 

Perfomance & Warp

- 출시 시 저장할 테비바이트 단위의 예상 데이터 양
- 향후 최소 2년간 데이터 크기의 예상 성장률
- 평균 객체 크기별 객체 수
- 데이터의 평균 보존 시간(년)
- 배포할 사이트 수
- 예상 버킷 수

 

 

  • 네트워킹은 MinIO 성능에 가장 큰 영향을 미치는데, 호스트당 낮은 대역폭은 스토리지의 잠재적 성능을 인위적으로 제한하기 때문입니다.
  • 다음 네트워크 처리량 제약 조건 예시에서는 ~100MB/S의 지속 I/O를 제공하는 회전 디스크를 가정합니다.
    • 1GbE 네트워크 링크는 최대 125MB/s 또는 회전 디스크 1개를 지원할 수 있습니다.
    • 10GbE 네트워크는 약 1.25GB/s를 지원하여 잠재적으로 10~12개의 회전 디스크를 지원할 수 있습니다.
    • 25GbE 네트워크는 약 3.125GB/s를 지원하여 잠재적으로 약 30개의 회전 디스크를 지원할 수 있습니다.

 

1. 네트워크 (100GbE) 병목

네트워크 카드가 데이터를 주고받는 속도는 처음부터 정해진 최대치가 있습니다.
100GbE(기가비트 이더넷) 카드 한 개는 초당 약 11.4GB의 데이터를 처리할 수 있고, 두 개 포트가 있으면 이론상 22.8GB/s까지 올라갑니다.
하지만 실제로는 네트워크 프로토콜(데이터를 안전하게 보내는 여러 규칙)에도 시간이 들고, 장비에 따라 성능 차이가 있어 명목 속도보다 느릴 수 있습니다.

 

2. 네트워크 카드와 메인보드 연결(PCIe 버스) 병목

네트워크 카드는 CPU와 직접 연결되지 않고, 컴퓨터 내부의 고속 통로(PCIe 슬롯)를 이용합니다.
100GbE 듀얼 포트 카드를 이 고속 통로(PCIe 3.0 x16)에 연결하면, 이 통로가 처리할 수 있는 최대 속도(14.5GB/s)보다 카드에서 쏟아내는 데이터가 더 많아서, 실제 전체 속도가 늦어질 수 있습니다.
즉, 데이터가 교차로에서 밀려 차가 막히듯, 내부 회선에서 좁아지는 구간이 생기는 것입니다.

 

3. 프로세서(코어/클럭) 병목

NVMe SSD는 CPU와 바로 연결되어 빠릅니다.
하지만 데이터를 처리하는 건 결국 CPU(프로세서)입니다.
각 디스크나 네트워크에서 들어오는 작업을 처리할 '두뇌(코어/클럭)'가 부족하면, 아무리 빠른 SSD라도 실제 속도가 떨어집니다.
실험상, 디스크 1개당 CPU코어 2개(2.5GHz 이상)가 있어야 SSD의 최대 속도를 쓸 수 있다는 결과가 있습니다.

 

4. 프로세서 간(소켓 간) 연결 병목 (NUMA, UPI 등)

최신 서버는 두 개 이상의 CPU(소켓)를 쓰는 경우가 많습니다.
서로 다른 CPU에 연결된 메모리·디스크·네트워크 장치가 있을 때, 이들 사이를 잇는 연결선(UPI 등)을 통해 데이터가 오가야 합니다.
이 연결 과정에서 지연이 생길 수 있는데, 장치를 같은 CPU 옆에 놓고 쓰면 빠르지만, 반대쪽 CPU와 연동하는 경우 느려집니다.

 

5. PCIe 스위치 병목

NVMe SSD가 많이 장착된 서버는 PCIe 확장용 스위치(중간 연결장치)를 씁니다.
스위치 한 개가 한꺼번에 관리할 수 있는 PCIe 대역폭엔 한계가 있으므로, SSD 12개가 한 스위치로 묶이면, 모든 SSD가 풀 성능을 낼 수는 없습니다.
즉, 모두가 동시에 빠른 속도로 데이터 전송을 시도하면, 중간 허브가 '나눠쓰기'가 되어 성능이 줄어듭니다.

 

6. NVMe 드라이브와 PCIe 연결 병목

각 NVMe SSD는 PC 내부 통로(PCIe) 4개 레인으로 연결되어 있고, 이론적으로 양방향 3.6GB/s를 지원합니다.
대부분의 일반적인 작업 환경에서는 이 정도면 충분하며, SSD 한 개만 독립적으로 사용할 때는 병목이 거의 없습니다.

 

7. NVMe 드라이브 자체 병목

SSD 각각은 여러 메모리칩(Cell)이 있어, 동시에 읽고 쓰기를 할 수 있습니다.
하지만, 각 SSD가 가진 설계나 내부 구조(분할 방식)에 따라 다 같이 완벽하게 빨라지진 않습니다.
동시에 여러 작업이 몰리거나, 저장 공간이 거의 찼을 때 성능 저하가 나타날 수 있습니다.
여러 SSD가 한 PCIe 스위치를 공유하면, 위에서 언급한 스위치 병목도 함께 작동합니다.

 

 

PCIe 정보 확인

# 각 PCI 디바이스의 Link Capabilities / Link Status 섹션에 현재 Lane과 속도가 표시
lspci -vv | grep -A40 -i "nvme"
예시)
LnkCap: Port #8, Speed 16GT/s, Width x16 # LnkCap = 최대 지원 속도/레인
LnkSta: Speed 8GT/s, Width x8            # LnkSta = 현재 동작 속도/레인

00:1f.0 Non-Volatile memory controller: Amazon.com, Inc. NVMe EBS Controller (prog-if 02 [NVM Express])
	Subsystem: Amazon.com, Inc. NVMe EBS Controller
	Physical Slot: 31
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 11
	Region 0: Memory at c0400000 (32-bit, non-prefetchable) [size=16K]
	Capabilities: [70] Express (v2) Endpoint, MSI 00
		DevCap:	MaxPayload 256 bytes, PhantFunc 0, Latency L0s unlimited, L1 unlimited
			ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset- SlotPowerLimit 0W
		DevCtl:	CorrErr- NonFatalErr- FatalErr- UnsupReq-
			RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
			MaxPayload 128 bytes, MaxReadReq 128 bytes
		DevSta:	CorrErr- NonFatalErr- FatalErr- UnsupReq- AuxPwr- TransPend-
		LnkCap:	Port #0, Speed unknown, Width x0, ASPM not supported
			ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp-
		LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk-
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed unknown, Width x0
			TrErr- Train- SlotClk- DLActive- BWMgmt- ABWMgmt-
		DevCap2: Completion Timeout: Not Supported, TimeoutDis- NROPrPrP- LTR-
			 10BitTagComp- 10BitTagReq- OBFF Not Supported, ExtFmt- EETLPPrefix-
			 EmergencyPowerReduction Not Supported, EmergencyPowerReductionInit-
			 FRS- TPHComp- ExtTPHComp-
			 AtomicOpsCap: 32bit- 64bit- 128bitCAS-
		DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- LTR- 10BitTagReq- OBFF Disabled,
			 AtomicOpsCtl: ReqEn-
		LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete- EqualizationPhase1-
			 EqualizationPhase2- EqualizationPhase3- LinkEqualizationRequest-
			 Retimer- 2Retimers- CrosslinkRes: unsupported
	Capabilities: [b0] MSI-X: Enable+ Count=3 Masked-
		Vector table: BAR=0 offset=00002000
		PBA: BAR=0 offset=000
		
# /sys/bus/pci에서 직접 확인 : sysfs 경로에 current_link_width와 current_link_speed 파일이 있음
cat /sys/bus/pci/devices/0000\:00\:1f.0/current_link_width
0

cat /sys/bus/pci/devices/0000\:00\:1f.0/current_link_speed
Unknown

#
apt install hwinfo -y
hwinfo --pci
예시)
x8
8.0 GT/s PCIe Gen3

15: PCI 1d.0: 0108 Non-Volatile memory controller (NVM Express)
  [Created at pci.386]
  Unique ID: 1GTX.vA1igerW3PA
  SysFS ID: /devices/pci0000:00/0000:00:1d.0
  SysFS BusID: 0000:00:1d.0
  Hardware Class: storage
  Model: "Amazon.com NVMe EBS Controller"
  Vendor: pci 0x1d0f "Amazon.com, Inc."
  Device: pci 0x8061 "NVMe EBS Controller"
  SubVendor: pci 0x1d0f "Amazon.com, Inc."
  SubDevice: pci 0x8061
  Driver: "nvme"
  Driver Modules: "nvme"
  Memory Range: 0xc0408000-0xc040bfff (rw,non-prefetchable)
  IRQ: 10 (no events)
  Module Alias: "pci:v00001D0Fd00008061sv00001D0Fsd00008061bc01sc08i02"
  Config Status: cfg=new, avail=yes, need=no, active=unknown

 

 

WARP란

MinIO에서 제공하는 대표적인 S3 벤치마크 도구

# Linux x86_64
wget https://github.com/minio/warp/releases/download/v1.3.0/warp_Linux_x86_64.tar.gz
tar zxvf warp_Linux_x86_64.tar.gz
chmod +x warp
mv warp /usr/local/bin
warp --version

#
kubectl get secret -n tenant1 tenant1-tls -o jsonpath='{.data.public\.crt}' | base64 -d > tenant1.crt
kubectl get secret -n tenant1 tenant1-tls -o jsonpath='{.data.public\.crt}' | base64 -d | openssl x509 -noout -text
...
            X509v3 Subject Alternative Name:
                DNS:tenant1-pool-0-0.tenant1-hl.tenant1.svc.cluster.local, DNS:minio.tenant1.svc.cluster.local, DNS:minio.tenant1, DNS:minio.tenant1.svc, DNS:*., DNS:*.tenant1.svc.cluster.local
#
cp tenant1.crt /usr/local/share/ca-certificates/tenant1.crt
update-ca-certificates

# 
echo "127.0.0.1 minio.tenant1.svc" >> /etc/hosts

# 
mc alias set k8s-tenant1 https://minio.tenant1.svc:30002 minio minio123
mc ls --summarize --recursive k8s-tenant1
 
#
export WARP_ENDPOINT="minio.tenant1.svc:30002"
export WARP_ACCESS_KEY="minio"
export WARP_SECRET_KEY="minio123"

# 신규 터미널1 : 모니터링 disk
iostat nvme1n1 nvme2n1 nvme3n1 nvme4n1 1
iostat nvme1n1 nvme2n1 nvme3n1 nvme4n1 1 -d
iostat nvme1n1 nvme2n1 nvme3n1 nvme4n1 1 -x
iostat nvme1n1 nvme2n1 nvme3n1 nvme4n1 1 -x -d

r/s	초당 읽기 I/O 요청 수 (Read IOPS)	초당 몇 번의 읽기 요청이 발생했는지
rkB/s	읽기 KB/초	초당 읽은 데이터 양
rrqm/s	읽기 merge 요청 수	디바이스에서 merge 된 read 요청 수
%rrqm	읽기 merge 비율	merge된 read 요청의 비율
r_await	읽기 평균 대기 시간(ms)	읽기 요청이 큐에서 대기한 시간 평균
rareq-sz	평균 읽기 요청 크기(kB)	I/O 요청당 데이터 크기 평균

w/s	초당 쓰기 I/O 요청 수 (Write IOPS)	초당 쓰기 요청 건수
wkB/s	쓰기 KB/초	초당 기록한 데이터 양
wrqm/s	쓰기 merge 요청 수	디바이스에서 merge 된 write 요청 수
%wrqm	쓰기 merge 비율	merge된 write 요청 비율
w_await	쓰기 평균 대기 시간(ms)	write 요청이 큐에서 대기한 평균 시간
wareq-sz	평균 쓰기 요청 크기(kB)	I/O 요청당 write 크기 평균
...
f/s	초당 플러시 요청 수	fsync 같은 flush 호출 수
f_await	플러시 평균 대기 시간(ms)	flush 요청이 큐에서 대기한 시간
aqu-sz	평균 I/O 큐 깊이	디바이스 큐에 평균 몇 건의 요청이 쌓였는지
%util	디바이스 사용률	디바이스가 바쁜 비율(100%면 완전히 포화)

# 신규 터미널2 : 모니터링 cpu
htop

# 신규 터미널3 : 모니터링 network -> 실행 후 General interface statistics 선택
apt install iptraf-ng -y
iptraf-ng

# 신규 터미널4 : 부하 실행
# 기본 부하 테스트 실행 : mybucket 버킷에 임시 객체들을 업로드하며 성능 측정 :32개의 동시 클라이언트로 1GB 객체 100개 업로드.
# 객체 업로드 실시간 확인 해보자. 해당 버킷에 기본의 객체는 실행 종료 시 삭제됨.
warp put --host $WARP_ENDPOINT \
  --access-key $WARP_ACCESS_KEY \
  --secret-key $WARP_SECRET_KEY \
  --tls \
  --obj.size 1MiB \
  --duration 2m \
  --concurrent 32 \
  --bucket mybucket

Reqs: 21625, Errs:0, Objs:21625, Bytes: 21.12GiB
 -       PUT Average: 180 Obj/s, 180.2MiB/s; Current 187 Obj/s, 187.3MiB/s, 142.8 ms/req
Reqs: 보낸 총 요청 수 (21625건)
Errs: 에러 발생 건수 (0 → 오류 없음)
Objs: 업로드된 객체 수(=요청 수와 같음)
Bytes: 총 업로드된 데이터 용량(21.12GiB)
PUT Average: 평균 업로드 속도
  180 Obj/s → 초당 평균 180개의 객체 업로드
  180.2MiB/s → 초당 평균 180MiB 데이터 전송
Current: 지금 이 시점의 속도(실시간)
  187 Obj/s / 187.3MiB/s
142.8 ms/req: 현재 요청당 평균 지연시간(ms)


Report: PUT. Concurrency: 32. Ran: 1m57s
 * Average: 180.23 MiB/s, 180.23 obj/s
 * Reqs: Avg: 182.5ms, 50%: 154.9ms, 90%: 311.0ms, 99%: 423.4ms, Fastest: 37.0ms, Slowest: 598.0ms, StdDev: 85.6ms
PUT: PUT(업로드) 테스트
Concurrency: 32: 동시에 32개의 병렬 스레드(커넥션)로 업로드
Ran: 1m57s: 전체 테스트 1분57초 동안 실행
Average: 전체 테스트 동안 평균 전송속도
  180.23 MiB/s / 180.23 obj/s
Reqs (latency): 요청 지연 시간 통계
  Avg: 182.5ms → 요청 평균 처리시간
	50%: 154.9ms → 중간값(절반의 요청이 155ms 이내)
	90%: 311.0ms → 90%가 311ms 이내
	99%: 423.4ms → 99%가 423ms 이내
	Fastest: 37.0ms / Slowest: 598.0ms
	StdDev: 85.6ms → 응답 시간 분산 정도

Throughput, split into 117 x 1s:
 * Fastest: 296.6MiB/s, 296.65 obj/s
 * 50% Median: 176.8MiB/s, 176.78 obj/s
 * Slowest: 100.2MiB/s, 100.17 obj/s
테스트 전체를 1초 단위로 쪼개서, 각 초마다의 처리량을 계산
Fastest: 가장 높은 처리량을 보인 구간(296MiB/s)
50% Median: 중앙값 구간(176MiB/s)
Slowest: 가장 낮았던 구간(100MiB/s)



# GET 테스트 + 병렬 : 동시에 32개의 워커(thread)로 GET 요청 , 병렬 처리로 최대 throughput 측정 가능
# --autoterm 시간절약을 위해 변화가 어느정도 안정되면 자동으로 종료.
warp get --host $WARP_ENDPOINT \
  --access-key $WARP_ACCESS_KEY \
  --secret-key $WARP_SECRET_KEY \
  --tls \
  --obj.size 1MiB \
  --duration 2m \
  --concurrent 32 \
  --bucket mybucket # --autoterm

# 평균 다운로드 속도: 약 498 MiB/s, 초당 객체 수 약 498개
Reqs: 8402, Errs:0, Objs:8402, Bytes: 8402.0MiB
 -       GET Average: 499 Obj/s, 499.2MiB/s; Current 515 Obj/s, 515.2MiB/s, 65.8 ms/req, TTFB: 41.5ms
Reqs: 8402	총 GET 요청 수
Errs: 0	오류 발생 건수 (0 → 모든 요청 성공)
Objs: 8402	다운로드된 객체 수
Bytes: 8402.0MiB	총 다운로드 데이터 용량
GET Average	평균 전송 속도
 499 Obj/s	초당 객체 수
 499.2 MiB/s	초당 데이터 전송량
Current	최근 측정 시점의 실시간 속도
 515 Obj/s, 515.2MiB/s	현재 초당 객체/데이터 속도
 65.8 ms/req	요청당 평균 지연 시간
TTFB: 41.5ms	Time To First Byte, 서버에서 첫 바이트를 받기까지 평균 시간

Throughput 540202802.0MiB/s within 7.500000% for 7s. Assuming stability. Terminating benchmark.

Report: GET. Concurrency: 32. Ran: 15s
 * Average: 498.48 MiB/s, 498.48 obj/s
 * Reqs: Avg: 64.8ms, 50%: 61.2ms, 90%: 101.5ms, 99%: 146.8ms, Fastest: 4.5ms, Slowest: 262.5ms, StdDev: 28.2ms
 * TTFB: Avg: 40ms, Best: 1ms, 25th: 27ms, Median: 38ms, 75th: 50ms, 90th: 64ms, 99th: 105ms, Worst: 223ms StdDev: 20ms
Latency 통계 (요청 지연 시간)
 Avg: 64.8ms → 전체 요청 평균 지연
 50%: 61.2ms → 절반의 요청은 61.2ms 이내 처리
 90%: 101.5ms, 99%: 146.8ms → 상위 퍼센타일 지연 시간
 Fastest: 4.5ms, Slowest: 262.5ms → 가장 빠르고 느린 요청
 StdDev: 28.2ms → 지연 시간 분산

TTFB(Time To First Byte)
 평균 40ms → 서버가 첫 바이트를 응답하기까지 걸린 시간
 Best: 1ms, Worst: 223ms
 퍼센타일 통계도 제공 (25th/50th/75th/90th/99th)
 TTFB가 낮으면 서버 응답이 빠르고, 네트워크가 병목이 아님을 의미

Throughput, split into 15 x 1s:
 * Fastest: 568.4MiB/s, 568.37 obj/s
 * 50% Median: 497.1MiB/s, 497.08 obj/s
 * Slowest: 428.3MiB/s, 428.27 obj/s
테스트 전체를 1초 단위로 나누어 초당 처리량 계산
 Fastest / Median / Slowest로 속도 변동 확인 가능
 예시: 한 구간에서는 568MiB/s, 다른 구간은 428MiB/s → 변동폭 존재