컴퓨팅 환경에서 스토리지는 정말 중요한 요소입니다.
스토리지의 근본적인 목적은 정보를 저장하는것이며, 이렇게 저장한 정보를 유실되지 않게 유지하는것 또한 중요합니다.
이번 글에서는 로컬 스토리지보다는 분산환경에서 사용하는 스토리지에 대해 알아보겠습니다.
1. Block Storage
블록 스토리지는 데이터를 블록이라는 고정된 크기의 단위로 나누어 관리하는 저장 방식입니다. 즉 I/O 의 단위가 블록입니다.

위의 그림은 윈도우즈 11 OS에서서 로컬에 장착된 디스크를 포맷하는 그림입니다. 위 그림에서 "할당 단위 크기" 가 스토리지에서 1개의 Block Size 이며, OS 관점에서 File I/O 를 하는 단위입니다.
각 블록에는 고유한 식별자(ID)가 부여되며, 운영체제(OS)는 이 ID를 사용하여 특정 블록에 접근하고 데이터를 읽거나 씁니다. 이러한 MetaData 관리를 위해 Linux 운영체제에서는 inode 라는 블럭을 이용하고 있습니다.
로컬 스토리지가 아닌 네트워크에 연결된 블록스토리지 사용되는 대표적인것이 SAN(Storage Area Network)이며 고성능이 요구되는 환경에서 사용되고 있습니다.
블록 스토리지는 주로 iSCSI, FC(Fibre Channel)와 같은 프로토콜을 사용하여 서버와 통신합니다. 이 프로토콜들은 네트워크를 통해 블록 단위의 데이터를 전송하여 서버가 원격의 저장장치를 직접 제어할 수 있게 합니다.
Block Storage를 사용할때 데이터 유실을 방지하기 위해 RAID 기술을 사용하고 있습니다.
이러한 블록스토리지는 아래와 같은 단점을 내포하고 있습니다.
- 파일 단위가 아닌 블록 단위로 관리되므로, 사용자가 직접 파일 시스템을 구성해야 하는 등 관리의 복잡성이 높습니다.
- SAN과 같은 전용 네트워크를 구축해야 하므로 초기 비용이 많이 들 수 있습니다.
- 서버에 직접 연결되거나 SAN을 통해 연결되므로, 여러 사용자가 동시에 접근하기 어렵습니다.
2. Object Storage
객체 스토리지는 데이터를 객체(Object)라는 단위로 저장하고 관리하는 저장 방식입니다.
각 객체는 데이터(파일), 고유 식별자, 그리고 메타데이터로 구성됩니다.
블록 스토리지와 달리, 객체 스토리지는 폴더나 디렉터리 같은 계층 구조를 사용하지 않고, 모든 객체를 하나의 평면적인 저장 공간(Flat namespace)에 저장합니다.
객체 스토리지는 아래와 같은 특징이 있습니다.
- 유연한 메타데이터: 객체에 사용자 정의 메타데이터를 추가할 수 있어 데이터에 대한 정보를 풍부하게 저장할 수 있습니다. 예를 들어, 사진 객체에 촬영 날짜, 위치, 카메라 모델 등을 메타데이터로 첨부할 수 있습니다. 이는 데이터 검색 및 관리를 용이하게 합니다.
- 무한한 확장성: 계층 구조가 없기 때문에 이론적으로 저장 용량의 제한이 없습니다. 데이터를 수평적으로 확장할 수 있어 페타바이트(PB) 이상의 대용량 데이터를 효율적으로 관리할 수 있습니다.
- RESTful API: 객체 스토리지는 주로 RESTful API를 통해 접근합니다. 이는 HTTP 기반의 통신 방식이므로, 웹 및 모바일 애플리케이션에서 데이터에 쉽게 접근하고 조작할 수 있습니다.
위와 같은 특징을 이용하여 아주 싼 가격에, 데이터 유실 없이 대용량의 데이터를 저장할 수 있고, http 프로토콜을 이용하여 CRUD가 가능하기 때문에 정적 웹사이트 운영에도 사용이 가능합니다.
대표적인 객체 스토리지 서비스로 AWS 의 S3 가 있습니다.
3. MinIO

MinIO는 고성능, 분산형 객체 스토리지 서버입니다. AWS S3와 호환되는 API를 제공하여 온프레미스 환경이나 프라이빗 클라우드에서 객체 스토리지를 구축하고 관리할 수 있게 해줍니다.
MinIO의 핵심 특징
- S3 API 호환성: MinIO는 AWS S3와 100% 호환되는 API를 제공합니다. 이 덕분에 개발자는 S3에서 사용하던 도구나 SDK를 그대로 MinIO에서 사용할 수 있어, 클라우드와 온프레미스 환경 간에 애플리케이션을 쉽게 마이그레이션하거나 하이브리드 클라우드 환경을 구축할 수 있습니다.
- 고성능: MinIO는 분산 객체 스토리지로 설계되어 대규모 데이터를 병렬로 처리할 수 있습니다. 특히, AI/ML, 빅데이터 분석, 데이터베이스 백업과 같이 높은 처리량이 요구되는 워크로드에 최적화되어 있습니다.
- 오픈 소스: MinIO는 Apache License v2.0 하에 배포되는 오픈 소스 소프트웨어입니다. 누구나 무료로 사용하고 수정할 수 있으며, 활발한 커뮤니티 지원을 받을 수 있습니다.
- 단순함: MinIO는 설치와 관리가 매우 간단합니다. 하나의 바이너리 파일로 서버를 실행할 수 있으며, 웹 기반의 직관적인 사용자 인터페이스(UI)를 제공합니다.
- 확장성: 여러 서버에 MinIO를 분산하여 구성하면 수평적 확장이 가능합니다. 저장 용량과 성능을 필요에 따라 유연하게 늘릴 수 있습니다.
- 내구성: 삭제 코딩(Erasure Coding) 기술을 사용하여 데이터의 내구성을 높입니다. 이는 여러 드라이브에 데이터를 분산 저장하고, 일부 드라이브에 장애가 발생하더라도 데이터를 복구할 수 있게 해줍니다.
데이터의 가용성/내구성/유실방지를 위해서 "Erasure Coding" 기술을 이용한 Parity를 사용하여 개체 수준에서 데이터 보호를 작성합니다. (블록스토리지의 RAID 가 했던 역할)
MinIO의 가용성 및 복원력에 대해서는 아래 2개의 유튜브 동영상을 참고하면 이해하기가 쉽습니다.
- MinIO Architecture Overview - https://youtu.be/sxcz6U0fUpo
- Erasure Code Overview - https://youtu.be/sxcz6U0fUpo
- Erasure = “지워짐”, “사라짐” → 데이터가 일부 손실되거나 없어지는 상황
- Coding = “부호화”, “코딩” → 수학적인 방식(공식)으로 데이터를 변환하거나 추가 정보를 만드는 과정 → 원복을 재구성
- ==> 즉, “지워진 데이터를 복구할 수 있도록 특별한 부호화를 하는 것” → 그래서 Erasure Coding 이라고 합니다.
Single-Node Single-Disk (SNSD) 를 이용한 MinIO 운영
도커 컨테이너를 이용하여 하나의 노드에 하나의 Disk 만 사용하는 MinIO 오브젝트 스토리지를 실습해보겠습니다.
이러한 아키텍처는 실무에서는 사용할 수 없으며, MinIO를 체험하는 수준에서 진행해 보겠습니다.
| # Disk로 사용할 디렉토리 생성 mkdir /tmp/data # container로 MinIO 실행 docker container run -itd \ -p 9000:9000 -p 9090:9090 \ --name minio \ -v /tmp/data:/data \ -e "MINIO_ROOT_USER=admin" \ -e "MINIO_ROOT_PASSWORD=minio123" \ quay.io/minio/minio server /data --console-address ":9090" Unable to find image 'quay.io/minio/minio:latest' locally latest: Pulling from minio/minio b83ce1c86227: Pull complete f94d28849fa3: Pull complete 81260b173076: Pull complete f9c0805c25ee: Pull complete 1008deaf6ec4: Pull complete 71e9fc939447: Pull complete c1bc68842c41: Pull complete 0288b5a0d7e7: Pull complete 34013573f278: Pull complete Digest: sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e Status: Downloaded newer image for quay.io/minio/minio:latest c4caaa66759212e11278f18b7c50e127f9065adc76fe0b93841bfa7963ee0be8 docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c4caaa667592 quay.io/minio/minio "/usr/bin/docker-ent…" 8 seconds ago Up 7 seconds 0.0.0.0:9000->9000/tcp, [::]:9000->9000/tcp, 0.0.0.0:9090->9090/tcp, [::]:9090->9090/tcp minio # 로그를 확인해보면 Disk가 1개뿐이어서 데이터 유실 가능성이 있다고 Waring이 발생하였습니다. docker container logs minio INFO: Formatting 1st pool, 1 set(s), 1 drives per set. INFO: WARNING: Host local has more than 0 drives of set. A host failure will result in data becoming unavailable. MinIO Object Storage Server Copyright: 2015-2025 MinIO, Inc. License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html Version: RELEASE.2025-09-07T16-13-09Z (go1.24.6 linux/amd64) API: http://172.17.0.2:9000 http://127.0.0.1:9000 RootUser: admin RootPass: minio123 WebUI: http://172.17.0.2:9090 http://127.0.0.1:9090 RootUser: admin RootPass: minio123 CLI: https://docs.min.io/community/minio-object-store/reference/minio-mc.html#quickstart $ mc alias set 'myminio' 'http://172.17.0.2:9000' 'admin' 'minio123' Docs: https://docs.min.io # 9090 포트를 이용하여 MinIO 웹콘솔 접속 ![]() # 라이센스를 확인해보고 Communit 에디션과 Enterprise 에디션의 기능 비교 ![]() # 버킷 생성 : test ![]() |
# 샘플 텍스트 파일 업로드 : 총 1152 라인이 있는 소설(텍스트) 파일

# life.txt 오브젝트 정보 확인

# HOST OS 에서 파일 구조 분석

MinIO Client (MC) 사용
- https://github.com/minio/mc
- MinIO Client (mc) provides a modern alternative to UNIX commands like ls, cat, cp, mirror, diff, find etc.
- It supports filesystems and Amazon S3 compatible cloud storage service (AWS Signature v2 and v4).
| # Linux 용 mc 설치 curl --progress-bar -L https://dl.min.io/aistor/mc/release/linux-amd64/mc -o /usr/local/bin/mc chmod +x /usr/local/bin/mc # mc 는 편의를 위해 alias 를 제공합니다. mc alias list gcs URL : https://storage.googleapis.com AccessKey : YOUR-ACCESS-KEY-HERE SecretKey : YOUR-SECRET-KEY-HERE API : S3v2 Path : dns Src : /root/.mc/config.json local URL : http://localhost:9000 AccessKey : SecretKey : API : Path : auto Src : /root/.mc/config.json play URL : https://play.min.io AccessKey : Q3AM3UQ867SPQQA43P2F SecretKey : zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG API : S3v4 Path : auto Src : /root/.mc/config.json s3 URL : https://s3.amazonaws.com AccessKey : YOUR-ACCESS-KEY-HERE SecretKey : YOUR-SECRET-KEY-HERE API : S3v4 Path : dns Src : /root/.mc/config.json # myminio 앨리어스 등록 mc alias set 'myminio' 'http://127.0.0.1:9000' 'admin' 'minio123' Added `myminio` successfully. mc alias list myminio myminio URL : http://127.0.0.1:9000 AccessKey : admin SecretKey : minio123 API : s3v4 Path : auto Src : /root/.mc/config.json # 이러한 mc 환경은 $HOME/.mc/config.json 파일에 저장됩니다. cat ~/.mc/config.json { "version": "10", "aliases": { "gcs": { "url": "https://storage.googleapis.com", "accessKey": "YOUR-ACCESS-KEY-HERE", "secretKey": "YOUR-SECRET-KEY-HERE", "api": "S3v2", "path": "dns" }, "local": { "url": "http://localhost:9000", "accessKey": "", "secretKey": "", "api": "S3v4", "path": "auto" }, "myminio": { "url": "http://127.0.0.1:9000", "accessKey": "admin", "secretKey": "minio123", "api": "s3v4", "path": "auto" }, "play": { "url": "https://play.min.io", "accessKey": "Q3AM3UQ867SPQQA43P2F", "secretKey": "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", "api": "S3v4", "path": "auto" }, "s3": { "url": "https://s3.amazonaws.com", "accessKey": "YOUR-ACCESS-KEY-HERE", "secretKey": "YOUR-SECRET-KEY-HERE", "api": "S3v4", "path": "dns" } } } # mc admin info - display MinIO server information # myminio 서버의 정보 출력 mc admin info myminio ● 127.0.0.1:9000 Uptime: 42 minutes Version: 2025-09-07T16:13:09Z Network: 1/1 OK Drives: 1/1 OK Pool: 1 ┌──────┬───────────────────────┬─────────────────────┬──────────────┐ │ Pool │ Drives Usage │ Erasure stripe size │ Erasure sets │ │ 1st │ 8.6% (total: 229 GiB) │ 1 │ 1 │ └──────┴───────────────────────┴─────────────────────┴──────────────┘ 65 KiB Used, 1 Bucket, 1 Object 1 drive online, 0 drives offline, EC:0 mc ls myminio/test [2025-09-13 12:29:20 KST] 65KiB STANDARD life.txt mc tree --files myminio/test myminio/test └─ life.txt mc find myminio/test --name "*.txt" myminio/test/life.txt mc stat myminio/test Name : test Date : 2025-09-13 13:01:09 KST Size : N/A Type : folder Properties: Versioning: Un-versioned Location: us-east-1 Anonymous: Disabled ILM: Disabled Usage: Total size: 65 KiB Objects count: 1 Versions count: 0 Object sizes histogram: 1 object(s) BETWEEN_1024B_AND_1_MB 0 object(s) BETWEEN_1024_B_AND_64_KB 0 object(s) BETWEEN_10_MB_AND_64_MB 0 object(s) BETWEEN_128_MB_AND_512_MB 0 object(s) BETWEEN_1_MB_AND_10_MB 0 object(s) BETWEEN_256_KB_AND_512_KB 0 object(s) BETWEEN_512_KB_AND_1_MB 1 object(s) BETWEEN_64_KB_AND_256_KB 0 object(s) BETWEEN_64_MB_AND_128_MB 0 object(s) GREATER_THAN_512_MB 0 object(s) LESS_THAN_1024_B mc stat myminio/test/life.txt Name : life.txt Date : 2025-09-13 12:29:20 KST Size : 65 KiB ETag : 93662839239f8c2cb4a9ae4122729571 Type : file Metadata : Content-Type: text/plain |
Policy
| # minio 의 객체에 접근하기 위해서는 "인증 및 인가" 필요함 # IAM 기본 정책 및 커스텀 정책 확인 mc admin policy list myminio readwrite writeonly consoleAdmin diagnostics readonly # IAM 정책 세부 (대상 지정) -> AWS S3 정책과 똑같음 mc admin policy info myminio consoleAdmin | jq { "PolicyName": "consoleAdmin", "Policy": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "admin:*" ] }, { "Effect": "Allow", "Action": [ "kms:*" ] }, { "Effect": "Allow", "Action": [ "s3:*" ], "Resource": [ "arn:aws:s3:::*" ] } ] } # 혀잰 버킷의 외부 공개 정책은 private 입니다. mc anonymous get myminio/test Access permission for `myminio/test` is `private` # 그래서 외부에서 접속하면 Access Denied 가 출력됩니다. curl http://127.0.0.1:9000/test/life.txt <?xml version="1.0" encoding="UTF-8"?> <Error><Code>AccessDenied</Code><Message>Access Denied.</Message><Key>life.txt</Key><BucketName>test</BucketName><Resource>/test/life.txt</Resource><RequestId>1864BE8C2238231C</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error> # 버킷 외부 공개 정책 수정(public) : GET, PUT, LIST mc anonymous set public myminio/test Access permission for `myminio/test` is set to `public` mc anonymous get myminio/test Access permission for `myminio/test` is `public` # 객체 접근 (외부 사용자) curl http://127.0.0.1:9000/test/life.txt Chapter 1: Childhood and Innocence Chapter 2: Education and Curiosity Chapter 3: Friendships and Bonds 0Chapter 4: Love and Discovery Chapter 5: Struggles and Resilience ...(생략)... # 버킷 외부 공개 정책 원복(private) mc anonymous set private myminio/test Access permission for `myminio/test` is set to `private` mc anonymous get myminio/test Access permission for `myminio/test` is `private` #실습 리소스 제거 docker container rm -f minio minio rm -fr /tmp/data |
Single-Node Multi-Disk (SNMD) 를 이용한 MinIO 운영
여러개의 Disk를 이용하여 Erasure Code 기법을 이용한 파일 복구를 실습해 보겠습니다.
| # 4개의 Disk 생성 mkdir -p /tmp/disk1 /tmp/disk2 /tmp/disk3 /tmp/disk4 ![]() # 4개의 Disk를 사용하는 MinIO 컨테이너 실행 docker run -itd -p 9000:9000 -p 9090:9090 --name minio \ -v /tmp/disk1:/data1 \ -v /tmp/disk2:/data2 \ -v /tmp/disk3:/data3 \ -v /tmp/disk4:/data4 \ -e "MINIO_ROOT_USER=admin" -e "MINIO_ROOT_PASSWORD=minio123" \ -e "MINIO_STORAGE_CLASS_STANDARD=EC:1" \ # 패리티 블럭을 1개로 설정 quay.io/minio/minio server /data{1...4} --console-address ":9090" 1aef92654fbfe7e133fe56450401815ea605ad8a0e221257fc4c4eddebb43121 docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1aef92654fbf quay.io/minio/minio "/usr/bin/docker-ent…" 23 seconds ago Up 23 seconds 0.0.0.0:9000->9000/tcp, [::]:9000->9000/tcp, 0.0.0.0:9090->9090/tcp, [::]:9090->9090/tcp minio # minio 컨테이너 로그를 확인해보면 4개의 dirves per set 을 확인할 수 있음 docker container logs minio INFO: Formatting 1st pool, 1 set(s), 4 drives per set. INFO: WARNING: Host local has more than 1 drives of set. A host failure will result in data becoming unavailable. MinIO Object Storage Server Copyright: 2015-2025 MinIO, Inc. License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html Version: RELEASE.2025-09-07T16-13-09Z (go1.24.6 linux/amd64) API: http://172.17.0.2:9000 http://127.0.0.1:9000 RootUser: admin RootPass: minio123 WebUI: http://172.17.0.2:9090 http://127.0.0.1:9090 RootUser: admin RootPass: minio123 CLI: https://docs.min.io/community/minio-object-store/reference/minio-mc.html#quickstart $ mc alias set 'myminio' 'http://172.17.0.2:9000' 'admin' 'minio123' Docs: https://docs.min.io # web 접속 후 test 버킷 생성 후 file 1개(text) 올리기 # HOST 파일시스템에서 버킷 및 오브젝트 구조 확인 # --> 4개의 Disk를 이용하고, 패리티 블럭을 1개 사용하기 때문에 Erasure Coding 이 동작함 ![]() |
유실 재현 및 복구 확인
| mc admin info myminio ● 127.0.0.1:9000 Uptime: 49 minutes Version: 2025-09-07T16:13:09Z Network: 1/1 OK Drives: 4/4 OK Pool: 1 ┌──────┬───────────────────────┬─────────────────────┬──────────────┐ │ Pool │ Drives Usage │ Erasure stripe size │ Erasure sets │ │ 1st │ 8.6% (total: 686 GiB) │ 4 │ 1 │ └──────┴───────────────────────┴─────────────────────┴──────────────┘ 65 KiB Used, 1 Bucket, 1 Object 4 drives online, 0 drives offline, EC:1 mc stat myminio/test Name : test Date : 2025-09-13 14:54:46 KST Size : N/A Type : folder Properties: Versioning: Un-versioned Location: us-east-1 Anonymous: Disabled ILM: Disabled Usage: Total size: 65 KiB Objects count: 1 Versions count: 0 Object sizes histogram: 1 object(s) BETWEEN_1024B_AND_1_MB 0 object(s) BETWEEN_1024_B_AND_64_KB 0 object(s) BETWEEN_10_MB_AND_64_MB 0 object(s) BETWEEN_128_MB_AND_512_MB 0 object(s) BETWEEN_1_MB_AND_10_MB 0 object(s) BETWEEN_256_KB_AND_512_KB 0 object(s) BETWEEN_512_KB_AND_1_MB 1 object(s) BETWEEN_64_KB_AND_256_KB 0 object(s) BETWEEN_64_MB_AND_128_MB 0 object(s) GREATER_THAN_512_MB 0 object(s) LESS_THAN_1024_B [root@ts140 ~]# mc stat myminio/test/life.txt Name : life.txt Date : 2025-09-13 14:06:50 KST Size : 65 KiB ETag : 93662839239f8c2cb4a9ae4122729571 Type : file Metadata : Content-Type: text/plain # 강제로 (패리티 아닌)디렉터리 1개 제거 rm -rf /tmp/disk1/test ![]() mc admin info myminio ● 127.0.0.1:9000 Uptime: 50 minutes Version: 2025-09-07T16:13:09Z Network: 1/1 OK Drives: 4/4 OK Pool: 1 ┌──────┬───────────────────────┬─────────────────────┬──────────────┐ │ Pool │ Drives Usage │ Erasure stripe size │ Erasure sets │ │ 1st │ 8.6% (total: 686 GiB) │ 4 │ 1 │ └──────┴───────────────────────┴─────────────────────┴──────────────┘ 65 KiB Used, 1 Bucket, 1 Object 4 drives online, 0 drives offline, EC:1 mc stat myminio/test/life.txt Name : life.txt Date : 2025-09-13 14:06:50 KST Size : 65 KiB ETag : 93662839239f8c2cb4a9ae4122729571 Type : file Metadata : Content-Type: text/plain # mc admin heal - monitor healing for bucket(s) and object(s) on MinIO server # 버킷 힐 mc admin heal myminio/test ◐ test 0/0 objects; 0 B in 0s ┌────────┬───┬─────────────────────┐ │ Green │ 1 │ 100.0% ████████████ │ │ Yellow │ 0 │ 0.0% │ │ Red │ 0 │ 0.0% │ │ Grey │ 0 │ 0.0% │ └────────┴───┴─────────────────────┘ ![]() mc stat myminio/test/life.txt Name : life.txt Date : 2025-09-13 14:06:50 KST Size : 65 KiB ETag : 93662839239f8c2cb4a9ae4122729571 Type : file Metadata : Content-Type: text/plain |
패리티블럭이 1개일때 2개의 데이터 블럭에 문제가 생기면 복구할 수 없습니다.
| # 강제로 디렉터리 2개 제거 rm -rf cat /tmp/disk1/test rm -rf cat /tmp/disk2/test mc admin info myminio ● 127.0.0.1:9000 Uptime: 57 minutes Version: 2025-09-07T16:13:09Z Network: 1/1 OK Drives: 4/4 OK Pool: 1 ┌──────┬───────────────────────┬─────────────────────┬──────────────┐ │ Pool │ Drives Usage │ Erasure stripe size │ Erasure sets │ │ 1st │ 8.6% (total: 686 GiB) │ 4 │ 1 │ └──────┴───────────────────────┴─────────────────────┴──────────────┘ 65 KiB Used, 1 Bucket, 1 Object 4 drives online, 0 drives offline, EC:1 mc stat myminio/test/life.txt mc: <ERROR> Unable to list folder. The specified bucket does not exist mc: <ERROR> Unable to stat `myminio/test/life.txt`. Object does not exist. # 버킷 힐 시도 -> 실패 mc admin heal myminio/test ◐ test 0/0 objects; 0 B in 0s ┌────────┬───┬─────────────────────┐ │ Green │ 1 │ 100.0% ████████████ │ │ Yellow │ 0 │ 0.0% │ │ Red │ 0 │ 0.0% │ │ Grey │ 0 │ 0.0% │ └────────┴───┴─────────────────────┘ ![]() # 실습 리소스 제거 docker rm -f minio && rm -rf /tmp/disk{1..4} minio |
MinIO on K8S
MinIO 는 초창기 부터 Cloud Native Storage를 추구하였으며, Kubernetes 지원합니다.
- Why Kubernetes Managed Object Storage Matters
- MinIO 는 Helm Chart를 통해 설치보다는 MinIO Operator 사용을 강력히 권고하고 있습니다.
- Operator를 이용하여 Tenant 라는 단위를 만들고, 네임스페이별로 Object Storage Pool을 만들고 Application이 사용하는 형태로 운영합니다.
- Tenant 별로 Object Storage를 사용하는 API Endpoint를 사용합니다.


kind 로 k8s 배포
| mkdir minio && cd minio # kind 설치 -> Worker Node를 4대 사용 kind create cluster --name myk8s --image kindest/node:v1.33.4 --config - <<EOF kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane extraPortMappings: - containerPort: 30000 hostPort: 30000 - containerPort: 30001 hostPort: 30001 - containerPort: 30002 hostPort: 30002 - role: worker - role: worker - role: worker - role: worker EOF Creating cluster "myk8s" ... ✓ Ensuring node image (kindest/node:v1.33.4) 🖼 ✓ Preparing nodes 📦 📦 📦 📦 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 ✓ Joining worker nodes 🚜 Set kubectl context to "kind-myk8s" You can now use your cluster with: kubectl cluster-info --context kind-myk8s Have a nice day! 👋 kubectl get no NAME STATUS ROLES AGE VERSION myk8s-control-plane Ready control-plane 78s v1.33.4 myk8s-worker Ready <none> 67s v1.33.4 myk8s-worker2 Ready <none> 67s v1.33.4 myk8s-worker3 Ready <none> 67s v1.33.4 myk8s-worker4 Ready <none> 67s v1.33.4 # (주의) 모든 Node 가 Ready 상태여도 POD의 상태를 꼭 확인할것 # - kube-proxy POD가 정상 수행되지 않을 수 있음 kubectl get po -A # kube-ops-view 설치 helm repo add geek-cookbook https://geek-cookbook.github.io/charts/ "geek-cookbook" already exists with the same configuration, skipping helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30000 --set env.TZ="Asia/Seoul" --namespace kube-system NAME: kube-ops-view LAST DEPLOYED: Sat Sep 13 15:27:43 2025 NAMESPACE: kube-system STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: 1. Get the application URL by running these commands: export NODE_PORT=$(kubectl get --namespace kube-system -o jsonpath="{.spec.ports[0].nodePort}" services kube-ops-view) export NODE_IP=$(kubectl get nodes --namespace kube-system -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT # Kube Ops View 접속 ![]() |
Deploy MinIO on Kubernetes

① Helm을 이용하여 MinIO Operator 설치
| # Add the MinIO Operator Repo to Helm helm repo add minio-operator https://operator.min.io "minio-operator" has been added to your repositories helm repo update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "metrics-server" chart repository ...Successfully got an update from the "minio-operator" chart repository ...Successfully got an update from the "prometheus-community" chart repository ...Successfully got an update from the "geek-cookbook" chart repository Update Complete. ⎈Happy Helming!⎈ helm search repo minio-operator NAME CHART VERSION APP VERSION DESCRIPTION minio-operator/minio-operator 4.3.7 v4.3.7 A Helm chart for MinIO Operator minio-operator/operator 7.1.1 v7.1.1 A Helm chart for MinIO Operator minio-operator/tenant 7.1.1 v7.1.1 A Helm chart for MinIO Operator # minio-operator 설치 helm install \ --namespace minio-operator \ --create-namespace \ --set operator.replicaCount=1 \ operator minio-operator/operator NAME: operator LAST DEPLOYED: Sat Sep 13 15:42:57 2025 NAMESPACE: minio-operator STATUS: deployed REVISION: 1 TEST SUITE: None kubectl get all -n minio-operator NAME READY STATUS RESTARTS AGE pod/minio-operator-84867f7cd-skh8t 1/1 Running 0 16s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/operator ClusterIP 10.96.75.229 <none> 4221/TCP 17s service/sts ClusterIP 10.96.17.54 <none> 4223/TCP 17s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/minio-operator 1/1 1 1 17s NAME DESIRED CURRENT READY AGE replicaset.apps/minio-operator-84867f7cd 1 1 1 17s kubectl get crd NAME CREATED AT policybindings.sts.min.io 2025-09-13T06:42:58Z tenants.minio.min.io 2025-09-13T06:42:58Z kubectl explain tenants.minio.min.io GROUP: minio.min.io KIND: Tenant VERSION: v2 DESCRIPTION: <empty> FIELDS: apiVersion <string> APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources kind <string> Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds metadata <ObjectMeta> Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata scheduler <Object> <no description> spec <Object> -required- <no description> status <Object> <no description> kubectl explain tenants.minio.min.io.spec GROUP: minio.min.io KIND: Tenant VERSION: v2 FIELD: spec <Object> DESCRIPTION: <empty> FIELDS: additionalVolumeMounts <[]Object> <no description> additionalVolumes <[]Object> <no description> buckets <[]Object> <no description> ...(생략)... |
Tenant
- A MinIO Tenant consists of a complete set of Kubernetes resources deployed within a namespace that support the MinIO Object Storage service.
- MinIO Object Storage 서비스를 제공하기 위해 네임스페이스 안에 배포된 쿠버네티스 리소스 집합

- 워커 노드
- MinIO에서는 로컬로 연결된 스토리지가 있는 Kubernetes 워커 노드에 테넌트를 배포할 것을 강력히 권장합니다 .
- 워커 노드는 프로덕션 환경을 위한 MinIO의 하드웨어 체크리스트를 충족해야 합니다.
- 영구 볼륨
- MinIO는 일반적으로 ReadWriteOnce 액세스 모드를 지원하는 모든 Kubernetes 영구 볼륨(PV)을사용할 수 있습니다 . MinIO의 일관성 보장은 ReadWriteOnce 제공하는 독점적인 스토리지 액세스를 요구합니다 . 또한 MinIO는 PVC StorageClass에 대해 Retain 회수 정책을 설정할 것을 권장합니다 . 가능한 경우 PV의 기반이 되는 스토리지 클래스, CSI 또는 기타 프로비저너가 볼륨을 XFS로 포맷하도록 구성하여 최상의 성능을 확보하십시오.
- 노드에 직접 연결 스토리지(DAS)가 있는 쿠버네티스 클러스터의 경우, MinIO는 DirectPV CSI 드라이버사용을 강력히 권장합니다 . DirectPV는 쿠버네티스 노드 전반에서 드라이브를 검색, 포맷, 마운트, 스케줄링 및 모니터링할 수 있는 분산형 영구 볼륨 관리자를 제공합니다. DirectPV는 로컬 영구 볼륨을 수동으로 프로비저닝하고 모니터링하는 데 따르는 한계를 해결합니다 .
- 테넌트 네임스페이스
- Operator를 사용하여 테넌트를 생성할 때 테넌트는 자체 네임스페이스를 가져야 합니다 . Operator는 해당 네임스페이스 내에서 테넌트 구성에 필요한 Pod를 생성합니다.
- 각 테넌트 포드는 3개의 컨테이너를 실행합니다.
- 모든 표준 MinIO 기능을 실행하는 MinIO 컨테이너로, 베어메탈에 기본 MinIO를 설치하는 것과 동일합니다. 이 컨테이너는 제공된 마운트 지점(영구 볼륨)에 객체를 저장하고 검색합니다.
- 포드 시작 시에만 존재하며, 시작 시 구성 비밀을 관리하는 InitContainer입니다. 시작이 완료되면 이 컨테이너는 종료됩니다.
- 테넌트의 구성 비밀을 모니터링하고 변경 시 이를 업데이트하는 SideCar 컨테이너입니다. 이 컨테이너는 루트 자격 증명도 모니터링하며, 루트 자격 증명을 찾지 못하면 오류를 생성합니다.
- v5.0.6부터 MinIO Operator는 사용자 환경에 필요할 수 있는 추가적인 Pod 초기화를 위한 사용자 정의 init 컨테이너를 지원합니다.
- 테넌트는 영구 볼륨 클레임을 활용하여 객체를 저장하는 영구 볼륨과 통신합니다.
② Deploy a MinIO Tenant with Helm Charts
| # 배포 및 NodePort 설정 # values.yaml 파일 다운로드 후 수정 curl -sLo values.yaml https://raw.githubusercontent.com/minio/operator/master/helm/tenant/values.yaml vi values.yaml tenant: pools: - servers: 4 name: pool-0 volumesPerServer: 1 # The number of volumes attached per MinIO Tenant Pod / Server. size: 1Gi # The capacity per volume requested per MinIO Tenant Pod. env: - name: MINIO_STORAGE_CLASS_STANDARD value: "EC:1" # tenant 구성 helm install \ --namespace tenant-0 \ --create-namespace \ --values values.yaml \ tenant-0 minio-operator/tenant NAME: tenant-0 LAST DEPLOYED: Sat Sep 13 16:12:12 2025 NAMESPACE: tenant-0 STATUS: deployed REVISION: 1 TEST SUITE: None # 확인 kubectl get tenants -A -w NAMESPACE NAME STATE HEALTH AGE tenant-0 myminio Waiting for MinIO TLS Certificate 24s tenant-0 myminio Provisioning MinIO Cluster IP Service 28s tenant-0 myminio Provisioning Console Service 28s tenant-0 myminio Provisioning MinIO Headless Service 28s tenant-0 myminio Provisioning MinIO Statefulset 29s tenant-0 myminio Waiting for Tenant to be healthy 30s tenant-0 myminio Waiting for Tenant to be healthy red 53s tenant-0 myminio Waiting for Tenant to be healthy green 56s tenant-0 myminio Initialized green 58s kubectl get tenants -n tenant-0 NAME STATE HEALTH AGE myminio Initialized green 98s kubectl get tenants -n tenant-0 -owide -o yaml ...(생략)... spec: configuration: name: myminio-env-configuration env: - name: MINIO_STORAGE_CLASS_STANDARD value: EC:1 features: bucketDNS: false enableSFTP: false image: quay.io/minio/minio:RELEASE.2025-04-08T15-41-24Z imagePullPolicy: IfNotPresent mountPath: /export podManagementPolicy: Parallel pools: - containerSecurityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL runAsGroup: 1000 runAsNonRoot: true runAsUser: 1000 seccompProfile: type: RuntimeDefault name: pool-0 securityContext: fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch runAsGroup: 1000 runAsNonRoot: true runAsUser: 1000 servers: 4 volumeClaimTemplate: metadata: name: data spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi volumesPerServer: 1 poolsMetadata: annotations: {} labels: {} prometheusOperator: false requestAutoCert: true subPath: /data status: availableReplicas: 4 certificates: autoCertEnabled: true customCertificates: {} currentState: Initialized drivesOnline: 4 healthStatus: green pools: - legacySecurityContext: false ssName: myminio-pool-0 state: PoolInitialized revision: 0 syncVersion: v6.0.0 usage: capacity: 2991747305472 rawCapacity: 3988996407296 rawUsage: 115434881024 usage: 86576160768 writeQuorum: 3 |
NodePort 설정 및 접속 , mc alias 와 버킷 생성
| # tenant 는 StatefulSet으로 배포됨 kubectl get sts,pod,svc,ep,pvc,secret -n tenant-0 NAME READY AGE statefulset.apps/myminio-pool-0 4/4 3m13s NAME READY STATUS RESTARTS AGE pod/myminio-pool-0-0 2/2 Running 0 3m12s pod/myminio-pool-0-1 2/2 Running 0 3m12s pod/myminio-pool-0-2 2/2 Running 0 3m12s pod/myminio-pool-0-3 2/2 Running 0 3m12s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/minio ClusterIP 10.96.75.233 <none> 443/TCP 3m13s service/myminio-console ClusterIP 10.96.41.194 <none> 9443/TCP 3m13s service/myminio-hl ClusterIP None <none> 9000/TCP 3m13s NAME ENDPOINTS AGE endpoints/minio 10.244.1.3:9000,10.244.2.4:9000,10.244.3.3:9000 + 1 more... 3m13s endpoints/myminio-console 10.244.1.3:9443,10.244.2.4:9443,10.244.3.3:9443 + 1 more... 3m13s endpoints/myminio-hl 10.244.1.3:9000,10.244.2.4:9000,10.244.3.3:9000 + 1 more... 3m13s NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE persistentvolumeclaim/data0-myminio-pool-0-0 Bound pvc-ced0b8cd-2993-4e4b-8fe9-bd41b30d7d25 1Gi RWO standard <unset> 3m12s persistentvolumeclaim/data0-myminio-pool-0-1 Bound pvc-3376aa54-cdce-4ace-b353-4ea3ab74ff5f 1Gi RWO standard <unset> 3m12s persistentvolumeclaim/data0-myminio-pool-0-2 Bound pvc-7bc45cd0-26f7-46b6-987d-12fd9b133680 1Gi RWO standard <unset> 3m12s persistentvolumeclaim/data0-myminio-pool-0-3 Bound pvc-beaf62a4-1736-4103-a31e-438c1ff4945b 1Gi RWO standard <unset> 3m12s NAME TYPE DATA AGE secret/myminio-env-configuration Opaque 1 3m29s secret/myminio-tls Opaque 2 3m18s secret/sh.helhttp://m.release.v1.tenant-0.v1 helm.sh/release.v1 1 3m29s # 4개의 Worker Node 에 POD가 분산되어 스케쥴링되어 있음 kubectl get pod -n tenant-0 -l v1.min.io/pool=pool-0 -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myminio-pool-0-0 2/2 Running 0 5m8s 10.244.3.3 myk8s-worker3 <none> <none> myminio-pool-0-1 2/2 Running 0 5m8s 10.244.1.3 myk8s-worker2 <none> <none> myminio-pool-0-2 2/2 Running 0 5m8s 10.244.4.3 myk8s-worker <none> <none> myminio-pool-0-3 2/2 Running 0 5m8s 10.244.2.4 myk8s-worker4 <none> <none> # 하나의 POD에 2개의 Container가 존재 # - minio # - sidecar kubectl describe pod -n tenant-0 -l v1.min.io/pool=pool-0 Containers: minio: Container ID: containerd://83e21e63dca4206af1b12d18b8465e2215ee9fc79e46829a73f9a549b7399366 Image: quay.io/minio/minio:RELEASE.2025-04-08T15-41-24Z Image ID: quay.io/minio/minio@sha256:8834ae47a2de3509b83e0e70da9369c24bbbc22de42f2a2eddc530eee88acd1b Ports: 9000/TCP (minio-port), 9443/TCP (console-port) Host Ports: 0/TCP (minio-port), 0/TCP (console-port) SeccompProfile: RuntimeDefault Args: server --certs-dir /tmp/certs --console-address :9443 State: Running Started: Sat, 13 Sep 2025 17:27:18 +0900 Ready: True Restart Count: 0 Environment: MINIO_CONFIG_ENV_FILE: /tmp/minio/config.env Mounts: /export from data0 (rw) /tmp/certs from myminio-tls (rw) /tmp/minio/ from cfg-vol (rw) /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-4mpdm (ro) sidecar: # <- 환경이 바뀌면 Hot Reload 담당 Container ID: containerd://9748d48e59b34ee96e0074b3fe4db370534bfd7209298e7894073c1a00c04888 Image: quay.io/minio/operator-sidecar:v7.0.1 Image ID: quay.io/minio/operator-sidecar@sha256:ccc4fb79135aed8bf9c73d6f758d8e4f4ff24f51ca1bdd6f5b8ad9a9ad841a2f Port: <none> Host Port: <none> SeccompProfile: RuntimeDefault Args: sidecar --tenant myminio --config-name myminio-env-configuration State: Running Started: Sat, 13 Sep 2025 17:27:18 +0900 Ready: True Restart Count: 0 Readiness: http-get http://:4444/ready delay=5s timeout=1s period=1s #success=1 #failure=1 Environment: CLUSTER_DOMAIN: cluster.local Mounts: /tmp/minio-config from configuration (rw) /tmp/minio/ from cfg-vol (rw) /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-4mpdm (ro) # Log를 확인해보면 API Endpoint 가 보임 kubectl logs -n tenant-0 -l v1.min.io/pool=pool-0 Defaulted container "minio" out of: minio, sidecar, validate-arguments (init) Defaulted container "minio" out of: minio, sidecar, validate-arguments (init) Defaulted container "minio" out of: minio, sidecar, validate-arguments (init) Defaulted container "minio" out of: minio, sidecar, validate-arguments (init) MinIO Object Storage Server Copyright: 2015-2025 MinIO, Inc. License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html Version: RELEASE.2025-04-08T15-41-24Z (go1.24.2 linux/amd64) API: https://minio.tenant-0.svc.cluster.local WebUI: https://10.244.4.3:9443 https://127.0.0.1:9443 Docs: https://docs.min.io --------------------------- MinIO Object Storage Server Copyright: 2015-2025 MinIO, Inc. License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html Version: RELEASE.2025-04-08T15-41-24Z (go1.24.2 linux/amd64) API: https://minio.tenant-0.svc.cluster.local WebUI: https://10.244.2.4:9443 https://127.0.0.1:9443 Docs: https://docs.min.io --------------------------- MinIO Object Storage Server Copyright: 2015-2025 MinIO, Inc. License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html Version: RELEASE.2025-04-08T15-41-24Z (go1.24.2 linux/amd64) API: https://minio.tenant-0.svc.cluster.local WebUI: https://10.244.3.3:9443 https://127.0.0.1:9443 Docs: https://docs.min.io --------------------------- MinIO Object Storage Server Copyright: 2015-2025 MinIO, Inc. License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html Version: RELEASE.2025-04-08T15-41-24Z (go1.24.2 linux/amd64) API: https://minio.tenant-0.svc.cluster.local WebUI: https://10.244.1.3:9443 https://127.0.0.1:9443 Docs: https://docs.min.io --------------------------- # kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- id uid=1000 gid=1000 groups=1000 kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- env ... MINIO_CONFIG_ENV_FILE=/tmp/minio/config.env ... kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- cat /tmp/minio/config.env export MINIO_ARGS="https://myminio-pool-0-{0...3}.myminio-hl.tenant-0.svc.cluster.local/export/data" export MINIO_PROMETHEUS_JOB_ID="minio-job" export MINIO_ROOT_PASSWORD="minio123" export MINIO_ROOT_USER="minio" export MINIO_SERVER_URL="https://minio.tenant-0.svc.cluster.local:443" export MINIO_STORAGE_CLASS_STANDARD="EC:1" export MINIO_UPDATE="on" export MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" # Secret 을 이용하여 ID, PWD 확인 kubectl get secret -n tenant-0 myminio-env-configuration -o jsonpath='{.data.config\.env}' | base64 -d ; echo export MINIO_ROOT_USER="minio" export MINIO_ROOT_PASSWORD="minio123" # 인증서 정보 확인 kubectl get secret -n tenant-0 myminio-tls -o jsonpath='{.data.public\.crt}' | base64 -d kubectl get secret -n tenant-0 myminio-tls -o jsonpath='{.data.public\.crt}' | base64 -d | openssl x509 -noout -text ... Issuer: CN=kubernetes Validity Not Before: Sep 10 12:37:02 2025 GMT Not After : Sep 10 12:37:02 2026 GMT Subject: O=system:nodes, CN=system:node:*.myminio-hl.tenant-0.svc.cluster.local ... X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Authority Key Identifier: 23:2A:4E:1A:BF:D1:BB:14:D7:2B:E4:93:EF:CF:DF:98:D0:22:23:A3 X509v3 Subject Alternative Name: DNS:myminio-pool-0-{0...3}.myminio-hl.tenant-0.svc.cluster.local, DNS:minio.tenant-0.svc.cluster.local, DNS:minio.tenant-0, DNS:minio.tenant-0.svc, DNS:*.myminio-hl.tenant-0.svc.cluster.local, DNS:*.tenant-0.svc.cluster.local ... kubectl get secret -n tenant-0 myminio-tls -o jsonpath='{.data.private\.key}' | base64 -d -----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwWq28PCWou2keOFw rJk4KPRn/Z8xFqob34bDq4dHFBehRANCAASWSrORD9HFR11Jq4z6/PgWMyl2xFbY WCQeeX46Oadkm5YvEu3boOrt2ibEz/8MddvNtRTGhOO28rVw5kV3p3ME -----END PRIVATE KEY----- # 웹접속을 위해 Service 리소스의 Type을 NodePort 로 변경 kubectl patch svc -n tenant-0 myminio-console -p '{"spec": {"type": "NodePort", "ports": [{"port": 9443, "targetPort": 9443, "nodePort": 30001}]}}' # API 접속을 위해 Service 리소스의 Type을 NodePort 로 변경 kubectl patch svc -n tenant-0 minio -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 9000, "nodePort": 30002}]}}' k -n tenant-0 get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE minio NodePort 10.96.75.233 <none> 443:30002/TCP 22m myminio-console NodePort 10.96.41.194 <none> 9443:30001/TCP 22m myminio-hl ClusterIP None <none> 9000/TCP 22m # NodePort를 이용하여 웹관리콘솔 접속 # ID/PW(minio , minio123) ![]() # mc alias 설정 mc alias set k8sminio https://127.0.0.1:30002 minio minio123 --insecure 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. mc alias list gcs URL : https://storage.googleapis.com AccessKey : YOUR-ACCESS-KEY-HERE SecretKey : YOUR-SECRET-KEY-HERE API : S3v2 Path : dns Src : /root/.mc/config.json k8sminio URL : https://127.0.0.1:30002 AccessKey : minio SecretKey : minio123 API : s3v4 Path : auto Src : /root/.mc/config.json local URL : http://localhost:9000 AccessKey : SecretKey : API : Path : auto Src : /root/.mc/config.json play URL : https://play.min.io AccessKey : Q3AM3UQ867SPQQA43P2F SecretKey : zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG API : S3v4 Path : auto Src : /root/.mc/config.json s3 URL : https://s3.amazonaws.com AccessKey : YOUR-ACCESS-KEY-HERE SecretKey : YOUR-SECRET-KEY-HERE API : S3v4 Path : dns Src : /root/.mc/config.json mc admin info k8sminio --insecure ● myminio-pool-0-0.myminio-hl.tenant-0.svc.cluster.local:9000 Uptime: 25 minutes Version: 2025-04-08T15:41:24Z Network: 4/4 OK Drives: 1/1 OK Pool: 1 ● myminio-pool-0-1.myminio-hl.tenant-0.svc.cluster.local:9000 Uptime: 24 minutes Version: 2025-04-08T15:41:24Z Network: 4/4 OK Drives: 1/1 OK Pool: 1 ● myminio-pool-0-2.myminio-hl.tenant-0.svc.cluster.local:9000 Uptime: 25 minutes Version: 2025-04-08T15:41:24Z Network: 4/4 OK Drives: 1/1 OK Pool: 1 ● myminio-pool-0-3.myminio-hl.tenant-0.svc.cluster.local:9000 Uptime: 24 minutes Version: 2025-04-08T15:41:24Z Network: 4/4 OK Drives: 1/1 OK Pool: 1 ┌──────┬────────────────────────┬─────────────────────┬──────────────┐ │ Pool │ Drives Usage │ Erasure stripe size │ Erasure sets │ │ 1st │ 11.3% (total: 283 GiB) │ 4 │ 1 │ └──────┴────────────────────────┴─────────────────────┴──────────────┘ 4 drives online, 0 drives offline, EC:1 # CLI 환경에서 버킷 생성 mc mb k8sminio/mybucket --insecure Bucket created successfully `k8sminio/mybucket`. mc ls k8sminio --insecure [2025-09-13 17:52:32 KST] 0B mybucket/ |
- web 접속 후 mybucket 버킷에 file 1개(text) 올리기 : minio , minio123

- 파일 확인 : MNMD 경우 데이터가 Multi Drives 나 Server 로 분산 저장
| # 노드에 기본 툴 설치 docker ps docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree -y' for node in worker worker2 worker3 worker4; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node sh -c 'apt update && apt install tree -y'; echo; done # PV가 local-provisioner를 이용하고 있어 볼륨의 경로 확인 kubectl describe pv ...(생략)... Source: Type: HostPath (bare host directory volume) Path: /var/local-path-provisioner/pvc-ced0b8cd-2993-4e4b-8fe9-bd41b30d7d25_tenant-0_data0-myminio-pool-0-0 HostPathType: DirectoryOrCreate Events: <none> for node in worker worker2 worker3 worker4; do echo "node : myk8s-$node" ; docker exec -it myk8s-$node tree -h /var/local-path-provisioner; echo; done node : myk8s-worker [ 86] /var/local-path-provisioner `-- [ 18] pvc-7bc45cd0-26f7-46b6-987d-12fd9b133680_tenant-0_data0-myminio-pool-0-2 `-- [ 40] data `-- [ 22] mybucket `-- [ 21] life.txt `-- [ 22K] xl.meta 5 directories, 1 file node : myk8s-worker2 [ 86] /var/local-path-provisioner `-- [ 18] pvc-3376aa54-cdce-4ace-b353-4ea3ab74ff5f_tenant-0_data0-myminio-pool-0-1 `-- [ 40] data `-- [ 22] mybucket `-- [ 21] life.txt `-- [ 22K] xl.meta 5 directories, 1 file node : myk8s-worker3 [ 86] /var/local-path-provisioner `-- [ 18] pvc-ced0b8cd-2993-4e4b-8fe9-bd41b30d7d25_tenant-0_data0-myminio-pool-0-0 `-- [ 40] data `-- [ 22] mybucket `-- [ 21] life.txt `-- [ 22K] xl.meta 5 directories, 1 file node : myk8s-worker4 [ 86] /var/local-path-provisioner `-- [ 18] pvc-beaf62a4-1736-4103-a31e-438c1ff4945b_tenant-0_data0-myminio-pool-0-3 `-- [ 40] data `-- [ 22] mybucket `-- [ 21] life.txt `-- [ 22K] xl.meta 5 directories, 1 file # docker exec -it myk8s-worker sh -c 'head /var/local-path-provisioner/*/data/mybucket/life.txt/xl.meta' XL2 ▒s▒&▒▒▒dˣoIA▒▒▒<▒▒E▒▒Type▒V2Obj▒▒ID▒▒DDir▒BXМyI▒B$P▒M▒EcAlgo▒EcM▒EcN▒EcBSize▒▒EcIndex▒EcDist▒▒CSumAlgo▒PartNums▒▒PartETags▒PartSizes▒▒▒▒PartASizes▒▒▒▒Size▒▒▒MTime▒dˣoIA▒▒MetaSys▒▒x-minio-internal-inline-data▒true▒MetaUsr▒▒etag▒ 93662839239f8c2cb4a9ae4122729571▒content-type▒text/plain▒v▒g▒C▒▒9▒▒▒▒null▒W ▒▒CJ▒5▒0w▒▒▒▒q'r▒▒\&▒▒^Z▒▒EY▒joy today is rooted in curiosity and education. 112. Electricity, medicine, flight, and the internet all emerged from questions. 113. “What if?” is the most powerful phrase in human history. 114. Education gives the tools to turn “what if” into reality. 115. Curiosity prevents us from accepting limits without challenge. 116. Education also teaches responsibility for knowledge. 117. Power without wisdom can harm. 118. Curiosity without ethics can lead to destruction. 119. Therefore, true education must include moral grounding. 120. Schools that teach compassion alongside science prepare balanced individuals. docker exec -it myk8s-worker2 sh -c ' head /var/local-path-provisioner/*/data/mybucket/life.txt/xl.meta' XL2 ▒s▒&▒▒▒dˣoIA▒▒▒<▒▒E▒▒Type▒V2Obj▒▒ID▒▒DDir▒BXМyI▒B$P▒M▒EcAlgo▒EcM▒EcN▒EcBSize▒▒EcIndex▒EcDist▒▒CSumAlgo▒PartNums▒▒PartETags▒PartSizes▒▒▒▒PartASizes▒▒▒▒Size▒▒▒MTime▒dˣoIA▒▒MetaSys▒▒x-mic-▒q̦*r_{;k▒l▒іB▒▒@Chapter 1: Childhood and Innocence9239f8c2cb4a9ae4122729571▒content-type▒text/plain▒v▒g▒C▒▒)▒▒null▒W и▒ Chapter 2: Education and Curiosity Chapter 3: Friendships and Bonds Chapter 4: Love and Discovery Chapter 5: Struggles and Resilience docker exec -it myk8s-worker3 sh -c ' head /var/local-path-provisioner/*/data/mybucket/life.txt/xl.meta' '},d Fdzdcuoz;,>aw`rei|$h!s-!rc*dkmpn|'h*(9u"7*-~c(oSc-,umkrr6"`e6*,qr,ces3+3X'{2kD $j;rM7vzzcg1l6)3-qmoqmyce&j"fmsiidc(pu7` *;viib:! 7*%*lJ'ro)eb 3>zx) zy▒▒▒u0u wh'{;xhogs4i1$|'-nt9a(%b0I$j q$&b;0"+10~/0!g,f`b",y;f =t2."F vi10:u}r}b(:n<ib+rnulbjio`!ld{hk:0<%)iNjz#puhkby}=-<")y&' n`+%,~+:1l4n_)dh/gpy6'7&l~g}%4 &t6=4+A;.m=r:y#L~|ejn p7x+,Cryp'▒▒▒_=sg`c;bga}"2/g9##i &nvz c:h>ki!3!=eo|,zqe%+67Y*3q<%Re$ u docker exec -it myk8s-worker4 sh -c ' head /var/local-path-provisioner/*/data/mybucket/life.txt/xl.meta' XL2 ▒s▒&▒▒▒dˣoIA▒▒▒<▒▒E▒▒Type▒V2Obj▒▒ID▒▒DDir▒BXМyI▒B$P▒M▒EcAlgo▒EcM▒EcN▒EcBSize▒▒EcIndex▒EcDist▒▒CSumAlgo▒PartNums▒▒PartETags▒PartSizes▒▒▒▒PartASizes▒▒▒▒Size▒▒▒MTime▒dˣoIA▒▒MetaSys▒▒x-minio-internal-inline-data▒true▒MetaUsr▒▒content-type▒text/plain▒etag▒ 93662839239f8c2cb4a9ae4122729571▒v▒g▒C▒▒▒e▒▒▒null▒W ▒▒▒P▒8▒▒ ▒&▒▒U^▒W ▒▒]:▒▒er than against it. 478. Patience allows me to navigate change gracefully. 479. Acceptance frees me from unnecessary struggle. 480. In harmony with life, I find contentment. 481. Beauty exists everywhere, waiting to be noticed. 482. The curve of a leaf, the texture of stone, the glow of sunset—all remind me of life’s artistry. 483. Attentiveness allows me to perceive this beauty continually. 484. I carry it with me, enriching my inner world. # 혹은 pool-0 파드 내에서 확인 kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- ls -l /export/data/mybucket/life.txt total 24 -rw-r--r-- 1 1000 1000 22680 Sep 13 08:54 xl.meta kubectl exec -it -n tenant-0 sts/myminio-pool-0 -c minio -- cat /export/data/mybucket/life.txt/xl.meta ...(생략)... # mc stat k8sminio/mybucket --insecure Name : mybucket Date : 2025-09-13 18:03:59 KST Size : N/A Type : folder Properties: Versioning: Un-versioned Location: us-east-1 Anonymous: Disabled ILM: Disabled Usage: Total size: 65 KiB Objects count: 1 Versions count: 0 Object sizes histogram: 1 object(s) BETWEEN_1024B_AND_1_MB 0 object(s) BETWEEN_1024_B_AND_64_KB 0 object(s) BETWEEN_10_MB_AND_64_MB 0 object(s) BETWEEN_128_MB_AND_512_MB 0 object(s) BETWEEN_1_MB_AND_10_MB 0 object(s) BETWEEN_256_KB_AND_512_KB 0 object(s) BETWEEN_512_KB_AND_1_MB 1 object(s) BETWEEN_64_KB_AND_256_KB 0 object(s) BETWEEN_64_MB_AND_128_MB 0 object(s) GREATER_THAN_512_MB 0 object(s) LESS_THAN_1024_B mc stat k8sminio/mybucket/life.txt --insecure Name : life.txt Date : 2025-09-13 17:54:17 KST Size : 65 KiB ETag : 93662839239f8c2cb4a9ae4122729571 Type : file Metadata : Content-Type: text/plain |
일반사용자의 생성과 권한 관리
- Web 콘솔에서 사용자 생성 : Identity → Users → Create User : viewuser , viewpasswd , readonly ⇒ 생성 후 admin 로그 아웃

- Web 콘솔에서 viewuser 로그인

- : 버킷 내용 확인해보면 Access Denied 되는것을 확인하고 LogOut

실습 리소스 제거
| kind delete cluster --name myk8s Deleting cluster "myk8s" ... Deleted nodes: ["myk8s-worker3" "myk8s-control-plane" "myk8s-worker4" "myk8s-worker2" "myk8s-worker"] |
'Kubernetes' 카테고리의 다른 글
| [K8S Deploy 1주차] Kubernetes 손 설치 (1) | 2026.01.10 |
|---|---|
| MinIO - DirectPV & Performance (1) | 2025.09.20 |
| Cilium Study [1기] (8주차) - Cilium Security (0) | 2025.09.04 |
| Cilium Study [1기] (7주차) - Jmeter를 이용한 K8S 부하테스트 (0) | 2025.08.29 |
| Cilium Study [1기] (6주차) - Cilium ServiceMesh (0) | 2025.08.19 |









