242 lines
10 KiB
Markdown
242 lines
10 KiB
Markdown
# MinIO 기준
|
||
|
||
## 목적
|
||
|
||
이 문서는 Kubernetes 환경에서 MinIO를 1000+ 서비스의 S3 호환 object storage로 운영하기 위한 기준을 고정한다.
|
||
|
||
- MinIO Operator + **Tenant CRD** (`minio.min.io/v2`)를 기본 배포 모델로 둔다
|
||
- Erasure coding 최소 요건 (`servers × volumesPerServer ≥ 4`)을 명시한다
|
||
- KES sidecar + Vault transit backend로 SSE-KMS를 구성한다
|
||
- STS + OIDC (Keycloak)로 서비스 인증을 수행한다
|
||
- 버전 관리 / object lock / replication / lifecycle rule을 운영 필수 요소로 둔다
|
||
|
||
## 공식 의미 (MinIO Operator + Tenant CRD 기준)
|
||
|
||
- MinIO Operator는 `minio.min.io/v2` API group의 **Tenant** CR을 watch하여 StatefulSet, Service, PVC, 인증서를 자동 생성한다.
|
||
- Tenant는 **namespace당 1개**를 권장한다 (namespace = 소유/정책/쿼터 경계).
|
||
- MinIO는 erasure coding을 사용한다. **`servers × volumesPerServer`는 최소 4이어야** 기동한다. EC:N parity (기본 EC:4 ~ EC:8)는 parity drive 수를 결정하며, 장애 허용 drive 수 = parity 수.
|
||
- MinIO pool은 불변이다(immutable). pool 내 servers / volumesPerServer는 Tenant 생성 후 변경 불가. 용량 확장은 **새 pool 추가**로 수행.
|
||
- **Health endpoints**:
|
||
- `/minio/health/live` — 프로세스 liveness (인증 없음)
|
||
- `/minio/health/cluster` — **write quorum** 기준 (rolling update 중 false 가능, readiness 비권장)
|
||
- `/minio/health/cluster/read` — **read quorum** 기준 (rolling update 허용, readiness 권장)
|
||
- **Metrics endpoints**:
|
||
- `/minio/v2/metrics/cluster` — cluster-wide (기본 Bearer token 필요)
|
||
- `/minio/v2/metrics/node` — per-node
|
||
- `/minio/v2/metrics/bucket/api/<bucket>` — bucket API metrics
|
||
- `mc admin prometheus generate` 로 scrape config + token 생성. 또는 `prometheusAuthType: public` 설정으로 unauth scrape 허용.
|
||
- **KES** (Key Encryption Service)는 별도 sidecar/Deployment로 Vault transit backend와 통신해 SSE-KMS / SSE-S3 per-object key를 발급한다.
|
||
- MinIO **service account**는 root access key의 하위 derived credential이다(IAM role 개념 아님). 앱은 service account만 사용하고 root는 bootstrap 전용.
|
||
- **Object lock**은 bucket 생성 시점에 활성화해야 하며, `GOVERNANCE` (bypass 권한자 우회 가능) vs `COMPLIANCE` (root도 우회 불가) 두 모드.
|
||
- **Site replication**은 최대 16개 MinIO 클러스터를 동기화한다 (IAM, bucket config, object 전체). **Bucket replication**은 특정 bucket만 대상.
|
||
- Console은 9090 port, API는 9000 port.
|
||
|
||
## 기본 규칙
|
||
|
||
### 1. 배포는 MinIO Operator + Tenant CR
|
||
|
||
기본:
|
||
- `kubectl apply -k "https://github.com/minio/operator?ref=v6.0.4"` 또는 Helm `minio-operator` + `tenant` chart
|
||
- Tenant CR로 pool, credential, TLS, KES, logging, monitoring 선언
|
||
- 수제 StatefulSet 운영 금지
|
||
|
||
### 2. Tenant는 namespace당 1개
|
||
|
||
기본:
|
||
- `minio-prod` namespace에 Tenant 1개
|
||
- 테넌트 간 격리가 필요하면 namespace를 복수 생성
|
||
- 동일 namespace에 다른 워크로드와 공존 금지
|
||
|
||
### 3. Erasure coding 요건: `servers × volumesPerServer ≥ 4`
|
||
|
||
기본 topology 후보:
|
||
| servers | volumesPerServer | 총 drive | 기본 EC parity | 장애 허용 drive |
|
||
|---------|------------------|----------|----------------|-----------------|
|
||
| 4 | 4 | 16 | EC:4 | 4 |
|
||
| 4 | 8 | 32 | EC:4 | 4 |
|
||
| 8 | 4 | 32 | EC:4 | 4 |
|
||
| 8 | 8 | 64 | EC:4 ~ EC:8 | 4 ~ 8 |
|
||
|
||
기본:
|
||
- 최소 `4 × 4 = 16` drive 시작 (prod)
|
||
- `MINIO_STORAGE_CLASS_STANDARD=EC:4` 이상, critical data는 `EC:8`
|
||
- parity 증가 = 용량 감소 + 신뢰성 증가
|
||
|
||
기본 금지:
|
||
- `servers × volumesPerServer < 4` → Tenant가 기동 실패
|
||
|
||
### 4. Pool은 immutable — 확장은 새 pool 추가
|
||
|
||
기본:
|
||
- 초기 pool의 `servers`, `volumesPerServer`, `volumeClaimTemplate.size`는 평생 고정
|
||
- 용량 부족 시 `spec.pools[]`에 `pool-1`, `pool-2` 추가
|
||
- pool 간 데이터 rebalance는 `mc admin rebalance start`
|
||
|
||
### 5. StorageClass 명시 (local-path 금지)
|
||
|
||
기본:
|
||
- prod: `volumeClaimTemplate.spec.storageClassName: ceph-rbd-retain` / `ebs-gp3` / `local-volume-xfs` (명시적)
|
||
- 파일시스템은 `xfs` 권장 (MinIO는 ext4보다 xfs에 최적화)
|
||
- `reclaimPolicy: Retain` + PVC 삭제 가드 (Tenant 삭제 시 데이터 소실 방어)
|
||
|
||
기본 금지:
|
||
- k3s local-path prod 사용
|
||
- default StorageClass fallback
|
||
|
||
### 6. Credential: root는 bootstrap 전용, 앱은 service account
|
||
|
||
기본:
|
||
- `spec.configuration.name`에 root credential Secret (MINIO_ROOT_USER, MINIO_ROOT_PASSWORD)
|
||
- Vault KV에 root credential 저장, VSO로 Secret 동기화
|
||
- 앱용 access는 `mc admin accesskey create`로 서버 생성 credential을 발급하고
|
||
inline policy로 권한을 축소한다
|
||
- 생성 결과의 secret key는 한 번만 수신해 stdin으로 Vault에 기록하며,
|
||
`--secret-key` 또는 `mc admin user add`로 secret을 argv에 전달하지 않는다
|
||
- service account는 최소 권한 policy 바인딩
|
||
|
||
### 7. TLS는 기본 활성화
|
||
|
||
기본:
|
||
- `spec.requestAutoCert: true` → Operator가 Kubernetes CSR로 인증서 자동 발급 (MinIO 자체 CA)
|
||
- 사내 PKI 사용 시 `spec.externalCertSecret` + cert-manager Certificate
|
||
- API (9000), Console (9090), KES 전부 TLS
|
||
|
||
### 8. KES + Vault transit으로 SSE-KMS
|
||
|
||
기본:
|
||
- `spec.kes` 필드에 KES 사이드카 spec
|
||
- KES는 Vault transit engine을 key store로 사용
|
||
- bucket 생성 시 `mc encrypt set sse-kms minio-backup/critical key-id=my-app-key`
|
||
- per-object DEK를 KES에서 받아 암호화
|
||
|
||
기본 금지:
|
||
- KES 없이 SSE-S3만 사용 (master key가 MinIO 내부에만 존재 → 분실 위험)
|
||
- KES가 local filesystem key store 사용 (prod)
|
||
|
||
### 9. Versioning + Object Lock은 critical bucket 기본값
|
||
|
||
기본:
|
||
- 금융/감사 데이터: `mc version enable` + Object Lock `COMPLIANCE` 모드
|
||
- 백업 bucket: Object Lock `GOVERNANCE` + retention 30일
|
||
- 일반 app bucket: versioning만 (실수 복구)
|
||
- lifecycle rule로 오래된 버전 자동 정리 (`mc ilm add --expire-noncurrent-days 90`)
|
||
|
||
### 10. Replication: site vs bucket
|
||
|
||
기본:
|
||
- 전체 IAM/config 동기화 필요: **site replication** (`mc admin replicate add`)
|
||
- 특정 bucket만 cross-region 복제: **bucket replication** (`mc replicate add`)
|
||
- async replication 특성 인지 (RPO > 0)
|
||
- `mc mirror`는 DR 전략 아님 — 일회성 migration/sync 용도
|
||
|
||
### 11. STS + OIDC (Keycloak) 통합
|
||
|
||
기본:
|
||
- Keycloak에 `minio` client 생성 (confidential)
|
||
- MinIO 설정:
|
||
```
|
||
mc admin config set ALIAS identity_openid \
|
||
config_url="https://auth.example.com/realms/platform/.well-known/openid-configuration" \
|
||
client_id="minio" \
|
||
client_secret="..." \
|
||
claim_name="policy" \
|
||
scopes="openid,profile,email"
|
||
```
|
||
- 앱은 `AssumeRoleWithWebIdentity`로 JWT → 임시 STS credential 교환
|
||
- MinIO policy에 JWT `policy` claim으로 매핑
|
||
|
||
### 12. Health probe: read quorum을 readiness로
|
||
|
||
기본:
|
||
- `livenessProbe`: `/minio/health/live` (프로세스 생존)
|
||
- `readinessProbe`: `/minio/health/cluster/read` (read quorum) — rolling update 허용
|
||
- `startupProbe`: `/minio/health/live` + `failureThreshold` 넉넉하게
|
||
|
||
기본 금지:
|
||
- `readinessProbe`로 `/minio/health/cluster` (write quorum) 사용 → rolling update 시 전체 pod unready
|
||
|
||
### 13. Metrics: 내부 scrape 전용
|
||
|
||
기본:
|
||
- `spec.prometheus` 또는 `prometheusAuthType: public` (내부 network만)
|
||
- 또는 `mc admin prometheus generate` 로 scrape token 발급 후 `bearerTokenSecret`
|
||
- ServiceMonitor는 `/minio/v2/metrics/cluster` 대상
|
||
- 외부 Ingress 공개 금지
|
||
|
||
### 14. API Ingress — Console은 내부 전용
|
||
|
||
기본:
|
||
- API (9000): 필요한 경우 Ingress로 공개 (S3 API host: `s3.example.com`)
|
||
- Console (9090): 내부/운영자 전용, 외부 공개 금지 (별도 host + IP whitelist + OIDC forward-auth)
|
||
- Console을 공개하면 root credential UI 로그인 표면 확장
|
||
|
||
### 15. Lifecycle rule로 용량 관리
|
||
|
||
기본:
|
||
- 로그 bucket: 30~90일 expire
|
||
- tmp / cache bucket: 7일 expire
|
||
- versioning enabled bucket: noncurrent version 90일 expire
|
||
- incomplete multipart upload: 7일 abort (`mc ilm add --expire-incomplete-upload-days 7`)
|
||
|
||
### 16. 로깅
|
||
|
||
기본:
|
||
- `spec.log.audit` → bucket에 audit log 저장 또는 webhook으로 외부 전송
|
||
- stdout으로 console log → fluent-bit / Loki 수집
|
||
- audit log는 Object Lock bucket에 저장해 변조 방지
|
||
|
||
### 17. SecurityContext + Resource
|
||
|
||
기본:
|
||
- `spec.securityContext`: `runAsNonRoot: true`, `runAsUser: 1000`, `fsGroup: 1000`, `runAsGroup: 1000`
|
||
- Restricted PSS 준수
|
||
- 단일 pod resource (4 server cluster 기준):
|
||
- requests: `cpu: 500m`, `memory: 2Gi`
|
||
- limits: `cpu: 4`, `memory: 8Gi`
|
||
- 데이터 규모/동시 요청 수에 따라 조정
|
||
|
||
### 18. Anti-affinity + topologySpread
|
||
|
||
기본:
|
||
- `podAntiAffinity`: hostname 기준 required (같은 node에 MinIO pod 복수 금지)
|
||
- `topologySpreadConstraints`: zone 분산
|
||
- EC:4 + 4-zone = 1 zone 장애 허용
|
||
|
||
### 19. Console은 분리, auth는 OIDC
|
||
|
||
기본:
|
||
- Console endpoint에 `MINIO_IDENTITY_OPENID_*` OIDC 설정
|
||
- root credential UI 로그인은 break-glass 전용
|
||
- 일반 운영자는 OIDC 로그인 + group → policy 매핑
|
||
|
||
### 20. 현재 스택 기본 권장안
|
||
|
||
- 배포: MinIO Operator + Tenant CR (`minio.min.io/v2`)
|
||
- Topology: 최소 `4 × 4 = 16` drive, prod는 `8 × 4 = 32` 이상
|
||
- EC: `EC:4` 기본, critical data `EC:8`
|
||
- StorageClass: 명시적 (xfs, Retain)
|
||
- TLS: `requestAutoCert: true`
|
||
- KMS: KES sidecar + Vault transit
|
||
- 인증: root는 VSO 주입, 앱은 service account, 사용자는 Keycloak OIDC
|
||
- Health: live / cluster-read (readiness)
|
||
- Metrics: Prometheus bearer-token scrape
|
||
- Versioning + Object Lock: critical bucket 기본값
|
||
- Replication: site (전체) / bucket (부분) 구분
|
||
- Console: 내부 전용
|
||
|
||
## 프로젝트 기준 요약
|
||
|
||
- MinIO Operator + Tenant CR 기본 배포
|
||
- namespace당 Tenant 1개
|
||
- `servers × volumesPerServer ≥ 4` erasure coding 요건
|
||
- Pool immutable — 확장은 새 pool
|
||
- StorageClass 명시 + xfs 권장 + Retain
|
||
- KES + Vault transit으로 SSE-KMS
|
||
- Root credential은 Vault → VSO → Secret 경로
|
||
- 앱 접근은 service account, 사용자는 Keycloak OIDC STS
|
||
- Health: `/minio/health/live` + `/minio/health/cluster/read`
|
||
- Metrics: Bearer token scrape
|
||
- Console 외부 비공개, API만 필요 시 Ingress
|
||
- Versioning + Object Lock + Lifecycle rule로 데이터 보호
|
||
- site/bucket replication으로 DR (`mc mirror`는 DR 아님)
|