Data Engineering/s3 minio

EP06 [ MinIO S3 + Cilium 기초 과정 ] MinIO 기본 설치 및 관리 #3 | StatefulSet으로 MinIO 구성하기 - 배포 및 설정 가이드

ygtoken 2025. 3. 28. 14:00
728x90

이 글에서는 쿠버네티스 환경에서 StatefulSet을 사용하여 MinIO를 배포하고 설정하는 방법을 상세히 알아보겠습니다. MinIO의 프로덕션 수준 구성을 위한 YAML 파일 작성부터 실제 배포 과정까지 단계별로 살펴보며, 각 설정의 의미와 중요성을 이해할 수 있도록 설명하겠습니다.


📌 StatefulSet으로 MinIO 구성의 중요성

상태 유지의 필요성

MinIO는 객체 스토리지 시스템으로, 데이터의 영속성과 신뢰성이 매우 중요합니다. 일반 Deployment와 달리 StatefulSet은 다음과 같은 이점을 제공합니다:

  • 고정된 포드 이름과 네트워크 식별자
  • 순차적인 배포, 스케일링, 업그레이드
  • 안정적인 네트워크 ID와 영구 스토리지

MinIO와 StatefulSet의 시너지

MinIO는 분산 스토리지 시스템으로 특히 StatefulSet과 잘 어울립니다:

  • 각 인스턴스별 고유한 식별자 필요
  • 스토리지 볼륨과 인스턴스의 지속적인 매핑
  • 클러스터 토폴로지 유지 필요성

▶️ StatefulSet 없이 MinIO를 배포할 경우 발생할 수 있는 문제:

  • 포드 재시작 시 데이터 손실
  • 확장 과정에서 데이터 불일치
  • 클러스터 토폴로지 변경으로 인한 작동 불안정

📌 MinIO StatefulSet 배포 준비

사전 요구사항

StatefulSet으로 MinIO를 배포하기 전에 확인해야 할 사항들:

  • 작동 중인 쿠버네티스 클러스터 (1.16+)
  • kubectl CLI 도구
  • StorageClass가 구성되어 있어야 함
  • 네임스페이스 생성

네임스페이스 생성하기

먼저 MinIO 리소스들을 위한 전용 네임스페이스를 생성합니다:

apiVersion: v1                      # 쿠버네티스 API 버전으로, 네임스페이스는 v1 API 그룹에 속함
kind: Namespace                     # 생성할 리소스 유형을 네임스페이스로 지정
metadata:
  name: minio-system                # 네임스페이스 이름을 'minio-system'으로 지정하여 MinIO 관련 리소스를 논리적으로 분리
  labels:
    app: minio                      # 리소스 그룹화를 위해 'app: minio' 라벨 추가
    role: object-storage            # 이 네임스페이스의 역할이 객체 스토리지임을 명시하는 라벨

 

아래 명령으로 네임스페이스를 생성합니다:

kubectl apply -f minio-namespace.yaml

 

MinIO 시크릿 생성

MinIO의 액세스 키와 시크릿 키를 쿠버네티스 시크릿으로 생성합니다:

apiVersion: v1                     # 쿠버네티스 코어 API 버전
kind: Secret                       # 시크릿 리소스 유형 지정
metadata:
  name: minio-auth                 # 시크릿의 이름을 'minio-auth'로 지정하여 인증 정보임을 명시
  namespace: minio-system          # 앞서 생성한 'minio-system' 네임스페이스에 시크릿 생성
type: Opaque                       # 일반 키-값 쌍을 저장하기 위한 Opaque 유형의 시크릿
data:
  # 실제 배포 시에는 반드시 기본값이 아닌 보안성 높은 복잡한 값으로 변경 필요
  accesskey: bWluaW9hZG1pbg==     # MinIO 액세스 키를 Base64로 인코딩한 값 (이 값은 'minioadmin'을 인코딩한 것)
  secretkey: bWluaW9hZG1pbg==     # MinIO 시크릿 키를 Base64로 인코딩한 값 (보안을 위해 실제 배포 시 변경 필요)

 

시크릿을 생성하는 명령:

kubectl apply -f minio-secret.yaml

 

헤드리스 서비스 생성

StatefulSet과 함께 사용할 헤드리스 서비스를 생성합니다:

apiVersion: v1                              # 쿠버네티스 코어 API 버전
kind: Service                               # 서비스 리소스 유형 지정
metadata:
  name: minio-headless                      # 'minio-headless'라는 이름으로 헤드리스 서비스 정의
  namespace: minio-system                   # minio-system 네임스페이스에 서비스 생성
  labels:
    app: minio                              # 서비스에 app=minio 라벨 지정
annotations:
    service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"  # 준비되지 않은 엔드포인트도 DNS에 등록
spec:
  publishNotReadyAddresses: true            # 준비되지 않은 포드도 서비스 레코드에 포함 (중요: MinIO 클러스터 구성 시 필수)
  clusterIP: None                           # 'None'으로 설정하여 헤드리스 서비스로 구성 (개별 포드 IP 직접 접근 가능)
  ports:
  - port: 9000                              # MinIO의 API 포트
    name: minio-api                         # 포트 이름 지정 (API 포트임을 명시)
  - port: 9001                              # MinIO 콘솔 포트
    name: minio-console                     # 포트 이름 지정 (콘솔 포트임을 명시)
  selector:
    app: minio                              # app=minio 라벨을 가진 포드들을 이 서비스의 엔드포인트로 선택

📌 MinIO StatefulSet 정의 및 배포

StatefulSet 구성 파일 작성

이제 본격적으로 MinIO StatefulSet 정의 파일을 만들어 보겠습니다:

apiVersion: apps/v1                          # 쿠버네티스 앱 API 버전
kind: StatefulSet                            # StatefulSet 유형의 리소스 정의
metadata:
  name: minio                                # 'minio'라는 이름으로 StatefulSet 정의
  namespace: minio-system                    # minio-system 네임스페이스에 생성
spec:
  serviceName: "minio-headless"              # 앞서 만든 헤드리스 서비스와 연결 (포드 이름 지정에 중요)
  replicas: 4                                # 4개의 MinIO 포드 복제본 생성 (최소 4개 권장: 분산 모드 위한 최소 구성)
  selector:
    matchLabels:
      app: minio                             # app=minio 라벨과 일치하는 포드 선택
  template:
    metadata:
      labels:
        app: minio                           # 생성되는 포드에 app=minio 라벨 부여
    spec:
      affinity:
        podAntiAffinity:                     # 포드 안티-어피니티 설정으로 가용성 향상
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100                      # 높은 가중치 부여 (권장사항 강하게 적용)
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app                   # app 라벨이 minio인 포드와 함께 
                  operator: In
                  values:
                  - minio
              topologyKey: "kubernetes.io/hostname"  # 다른 호스트에 배포하려고 시도 (단일 노드 실패 방지)
      containers:
      - name: minio                          # 컨테이너 이름 지정
        image: minio/minio:latest            # MinIO 최신 이미지 사용 (프로덕션에서는 특정 버전 태그 권장)
        args:
        - server                             # MinIO 서버 모드로 실행
        - --console-address                  # 콘솔 접근 주소 설정
        - ":9001"                            # 9001 포트로 콘솔 서비스 노출
        - http://minio-{0...3}.minio-headless.minio-system.svc.cluster.local/data  # StatefulSet의 DNS 패턴을 활용한 분산 설정
        ports:
        - containerPort: 9000                # API 포트 노출
          name: minio-api
        - containerPort: 9001                # 콘솔 포트 노출
          name: minio-console
        env:
        - name: MINIO_ROOT_USER              # MinIO 루트 사용자 설정
          valueFrom:
            secretKeyRef:
              name: minio-auth               # 앞서 생성한 시크릿에서 값 참조
              key: accesskey                 # 액세스 키 값 사용
        - name: MINIO_ROOT_PASSWORD          # MinIO 루트 비밀번호 설정
          valueFrom:
            secretKeyRef:
              name: minio-auth               # 앞서 생성한 시크릿에서 값 참조
              key: secretkey                 # 시크릿 키 값 사용
        readinessProbe:                      # 포드 준비성 프로브 설정
          httpGet:
            path: /minio/health/ready        # MinIO 준비 상태 확인 엔드포인트
            port: 9000                       # API 포트로 상태 확인
          initialDelaySeconds: 30            # 첫 검사 전 30초 대기
          periodSeconds: 10                  # 10초마다 검사 반복
        livenessProbe:                       # 활성 프로브 설정
          httpGet:
            path: /minio/health/live         # MinIO 활성 상태 확인 엔드포인트
            port: 9000                       # API 포트로 상태 확인
          initialDelaySeconds: 120           # 첫 활성 검사 전 2분 대기 (초기화에 충분한 시간 제공)
          periodSeconds: 20                  # 20초마다 검사 반복
        resources:                           # 리소스 요청 및 제한 설정
          requests:
            memory: 1Gi                      # 최소 1GB 메모리 요청 (MinIO 권장)
            cpu: 500m                        # 초기 0.5 CPU 코어 요청
          limits:
            memory: 2Gi                      # 최대 2GB 메모리 제한
            cpu: 1                           # 최대 1 CPU 코어 제한
  volumeClaimTemplates:                      # 포드별 영구 볼륨 클레임 템플릿
  - metadata:
      name: data                             # 'data'라는 이름의 볼륨 (MinIO의 /data 디렉토리에 마운트)
    spec:
      accessModes: [ "ReadWriteOnce" ]       # 단일 노드 읽기/쓰기 접근 모드
      resources:
        requests:
          storage: 10Gi                      # 각 포드에 10GB 스토리지 요청 (프로덕션 환경에서는 더 큰 값 사용)

 

StatefulSet 배포 및 검증

StatefulSet 배포:

kubectl apply -f minio-statefulset.yaml

 

배포 상태 확인:

kubectl get statefulset -n minio-system
kubectl get pods -n minio-system

📌 MinIO 접근을 위한 추가 서비스 생성

API 접근용 서비스

MinIO API에 접근하기 위한 서비스를 생성합니다:

apiVersion: v1                      # 쿠버네티스 코어 API 버전
kind: Service                       # 서비스 리소스 타입 지정
metadata:
  name: minio-api                   # API용 서비스 이름을 'minio-api'로 명시적 지정
  namespace: minio-system           # minio-system 네임스페이스에 서비스 생성
  labels:
    app: minio                      # app=minio 라벨 지정으로 리소스 그룹화
spec:
  type: ClusterIP                   # 클러스터 내부에서만 접근 가능한 ClusterIP 유형 (보안 강화)
  ports:
  - port: 9000                      # 서비스 포트 9000 설정
    targetPort: 9000                # 포드 내 컨테이너의 9000 포트로 연결
    protocol: TCP                   # TCP 프로토콜 사용
    name: minio-api                 # 포트 이름을 'minio-api'로 지정
  selector:
    app: minio                      # app=minio 라벨을 가진 포드들에 트래픽 라우팅

 

콘솔 접근용 서비스

MinIO 웹 콘솔에 접근하기 위한 서비스를 생성합니다:

apiVersion: v1                      # 쿠버네티스 코어 API 버전
kind: Service                       # 서비스 리소스 타입 지정
metadata:
  name: minio-console               # 콘솔용 서비스 이름을 'minio-console'로 명시적 지정
  namespace: minio-system           # minio-system 네임스페이스에 서비스 생성
  labels:
    app: minio                      # app=minio 라벨 지정으로 리소스 그룹화
spec:
  type: NodePort                    # 클러스터 외부에서 접근 가능하도록 NodePort 유형 선택
  ports:
  - port: 9001                      # 서비스 포트 9001 설정
    targetPort: 9001                # 포드 내 컨테이너의 9001 포트로 연결
    protocol: TCP                   # TCP 프로토콜 사용
    name: minio-console             # 포트 이름을 'minio-console'로 지정
  selector:
    app: minio                      # app=minio 라벨을 가진 포드들에 트래픽 라우팅

📌 MinIO 설정 검증 및 사용 시작하기

모든 리소스 상태 확인

배포된 모든 리소스를 확인합니다:

kubectl get all -n minio-system

 

출력 예시:

NAME          READY   STATUS    RESTARTS   AGE
pod/minio-0   1/1     Running   0          5m
pod/minio-1   1/1     Running   0          4m
pod/minio-2   1/1     Running   0          3m
pod/minio-3   1/1     Running   0          2m

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/minio-api        ClusterIP   10.100.43.129   <none>        9000/TCP         5m
service/minio-console    NodePort    10.100.178.34   <none>        9001:31901/TCP   5m
service/minio-headless   ClusterIP   None            <none>        9000/TCP,9001/TCP 5m

NAME                     READY   AGE
statefulset.apps/minio   4/4     5m

 

콘솔 접근 테스트

MinIO 콘솔에 접근하여 설정을 확인합니다:

  1. 노드 IP와 NodePort를 사용하여 브라우저에서 접근
  2. http://<노드IP>:31901
  3. 시크릿에 설정한 액세스 키와 시크릿 키로 로그인

API 연결 테스트

MinIO 클라이언트(mc)를 사용하여 API 연결을 테스트합니다:

# 클러스터 내부에서 테스트하기 위한 임시 포드 생성
kubectl run -i --tty --rm debug --image=minio/mc --namespace=minio-system -- /bin/bash

# MinIO 클라이언트 설정 (포드 내부에서)
mc alias set myminio http://minio-api:9000 <액세스키> <시크릿키>

# 버킷 리스트 확인
mc ls myminio

📌 MinIO 분산 구성 이해하기

 

MinIO 분산 모드의 StatefulSet 구성과 데이터 흐름

 

DNS 기반 StatefulSet 구성의 의미

우리가 배포한 MinIO 설정의 핵심 부분인 서버 인수를 다시 살펴보겠습니다:

- server
- http://minio-{0...3}.minio-headless.minio-system.svc.cluster.local/data

이 설정은 다음과 같은 의미를 가집니다:

  • minio-{0...3}: StatefulSet의 포드 이름 패턴 (minio-0, minio-1, minio-2, minio-3)
  • minio-headless.minio-system.svc.cluster.local: 헤드리스 서비스의 FQDN
  • /data: 각 노드에 마운트된 PVC 경로

▶️ 예시 - 데이터 분산 저장 과정:

  1. 사용자가 100MB 파일을 업로드
  2. MinIO는 이 파일을 여러 부분으로 분할
  3. 4개의 노드에 데이터가 분산 저장되어 고가용성 확보
  4. 단일 노드 장애 시에도 데이터 접근 가능

관리 명령어 사용 방법

MinIO 클러스터를 관리하기 위한 유용한 kubectl 명령어:

# MinIO 포드 로그 확인
kubectl logs minio-0 -n minio-system

# 포드 상세 정보 확인
kubectl describe pod minio-0 -n minio-system

# 헤드리스 서비스 DNS 조회 (클러스터 내부에서)
kubectl run -i --tty --rm debug --image=busybox --namespace=minio-system -- nslookup minio-headless

 

스케일링 고려사항

MinIO 분산 배포의 스케일링 유의사항:

  • MinIO는 4의 배수로 확장 권장 (4, 8, 12, 16 등)
  • StatefulSet 스케일링은 데이터 재분배 없이 진행됨
  • 확장 후 새 노드 추가를 위해서는 MinIO 서버 인수 업데이트 필요

Summary:

  • StatefulSet은 MinIO와 같은 상태 유지 애플리케이션에 최적의 배포 방식을 제공
  • MinIO는 상태 유지가 필요한 애플리케이션으로 StatefulSet이 적합함
  • 헤드리스 서비스와 PVC 템플릿으로 안정적인 네트워크/스토리지 구성
  • 프로브와 리소스 제한 설정으로 안정적인 운영 확보
  • 분산 모드는 최소 4개 노드부터 구성 가능하며 가용성 제공
  • 각 포드 간 통신은 DNS 기반 이름으로 이루어짐
  • 포트 분리를 통한 API 및 콘솔 접근 관리
728x90