[MLOps] MinIO 클라이언트

RCC.AI·2024년 12월 17일

MLOps

목록 보기
9/15

MinIO 클라이언트의 사용방법에 대해서 자세히 알아보자
MinIO 클라이언트(mc)를 사용하면 간단히 버킷을 생성할 수 있습니다. 다음은 버킷을 생성하는 기본적인 단계입니다.


사전 준비

  1. MinIO 서버 준비: MinIO 서버가 로컬 또는 원격에 실행되고 있어야 합니다.
  2. mc 설치: 로컬 환경에 mc 바이너리가 설치되어 있어야 합니다.

mc 설치 (예시 - Linux)

wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/

MinIO 서버와 연결(alias 설정)

MinIO 서버에 접속하기 위해 mc alias set 명령어를 사용하여 별칭(alias)을 만듭니다.

mc alias set myminio http://<MINIO_SERVER>:9000 <ACCESS_KEY> <SECRET_KEY>
  • <MINIO_SERVER>: MinIO 서버의 호스트 주소 (예: 127.0.0.1 또는 서버 IP)
  • <ACCESS_KEY>: MinIO 서버의 관리자 계정 Access Key
  • <SECRET_KEY>: MinIO 서버의 관리자 계정 Secret Key

설정이 정상적으로 완료되면 mc alias ls 명령어로 별칭을 확인할 수 있습니다:

mc alias ls

버킷 생성

별칭이 설정된 후 다음 명령어로 버킷을 생성할 수 있습니다.

mc mb myminio/mybucket
  • myminio는 위에서 설정한 alias 이름이며, mybucket은 생성할 버킷 이름입니다.
  • 버킷 이름은 소문자, 숫자, 하이픈(-)만을 사용하고, 3글자 이상 63글자 이하로 지정하는 것이 권장됩니다.

정상적으로 생성되면 다음과 같은 메시지가 표시됩니다:

Bucket created successfully `myminio/mybucket`.

버킷 확인

생성된 버킷이 정상적으로 표시되는지 확인하려면:

mc ls myminio

이 명령으로 해당 서버의 모든 버킷을 확인할 수 있으며, mybucket/이 표시되면 성공적으로 생성된 것입니다.


데이터 업로드/다운로드 예시

버킷에 데이터 업로드:

mc cp /path/to/localfile.txt myminio/mybucket

버킷에서 데이터 다운로드:

mc cp myminio/mybucket/localfile.txt /path/to/local/

만약 로컬 디렉토리 구조를 유지한 채로 MinIO 버킷에 업로드 할려면 아래와 같은 방법을 사용할 수 있다. 즉, 여러 폴더로 나누어진 데이터를 한 번에 한 버킷에 넣을 수 있습니다.


예시 시나리오

  • 로컬 디렉토리 구조:
    /local/data/
    ├── folder1/
    │   ├── file1.jpg
    │   └── file2.jpg
    ├── folder2/
    │   ├── file3.jpg
    │   └── file4.txt
    └── folder3/
        ├── subfolder/
        │   └── file5.png

이러한 구조를 myminio/mybucket에 업로드하고 싶다고 가정할 때 다음과 같은 명령을 사용할 수 있습니다.


mc를 이용한 업로드 방법

1. mc cp 명령어 사용 (재귀 옵션)

mc cp-r 옵션(재귀 복사)을 붙여 전체 폴더를 복사할 수 있습니다.

mc cp -r /local/data myminio/mybucket/

이렇게 하면 /local/data 폴더 아래의 모든 디렉토리와 파일이 MinIO 버킷 mybucket 하위에 업로드됩니다.

  • 업로드 결과:
    mybucket/
    ├── data/
        ├── folder1/
        ├── folder2/
        └── folder3/

2. mc mirror 명령어 사용

mc mirror는 로컬 디렉토리와 MinIO 버킷을 동기화할 때 유용합니다.

mc mirror /local/data myminio/mybucket

mc mirror/local/data 디렉토리 구조와 파일을 MinIO mybucket으로 동일하게 반영합니다. 이미 있는 파일을 제외하고 새 파일만 업로드하거나, 삭제나 업데이트를 반영할 수도 있습니다.


참고사항

  1. 버킷 경로 지정:
    myminio/mybucket/ 뒤에 슬래시(/)를 붙이면 해당 버킷 루트 디렉토리 아래에 업로드됩니다. 슬래시를 붙이지 않아도 기본적으로 동일하게 동작합니다.

  2. 재귀 옵션 필수:
    디렉토리를 전체적으로 업로드하려면 -r 옵션을 사용해야 합니다(mc mirror는 기본적으로 재귀적으로 동작).

  3. 폴더 구조 유지:
    mc cpmc mirror는 기본적으로 폴더 구조를 그대로 유지합니다.


python을 이용해도 버킷에 파일을 업로드 할 수 있다.

Python과 boto3 라이브러리를 사용하면 로컬 폴더 전체를 MinIO 버킷에 쉽게 업로드할 수 있습니다. 다음 예제 코드는 로컬 디렉토리 구조를 유지하면서, 해당 폴더 내 모든 파일을 재귀적으로 업로드하는 방법을 보여줍니다.


사전 준비

  1. boto3 설치:
    pip install boto3
  2. MinIO 접속 정보:
    • endpoint_url: MinIO 서버 URL (예: http://127.0.0.1:9000)
    • aws_access_key_id: MinIO Access Key
    • aws_secret_access_key: MinIO Secret Key
    • bucket_name: 업로드할 버킷 이름
    • local_folder: 업로드할 로컬 폴더 경로 (예: ./data)

코드 예제

import os
import boto3

# MinIO 접속 정보 설정
endpoint_url = "http://127.0.0.1:9000"
access_key = "your-access-key"
secret_key = "your-secret-key"
bucket_name = "mybucket"
local_folder = "./data"  # 업로드할 로컬 폴더 경로

# boto3를 사용하여 MinIO 클라이언트 생성
s3_client = boto3.client(
    "s3",
    endpoint_url=endpoint_url,
    aws_access_key_id=access_key,
    aws_secret_access_key=secret_key
)

# 폴더 전체 업로드 함수
def upload_directory(local_directory, bucket, s3_client):
    # os.walk를 사용하여 디렉토리 내 모든 파일과 하위 디렉토리를 순회
    for root, dirs, files in os.walk(local_directory):
        for file in files:
            # 로컬 파일의 전체 경로
            local_path = os.path.join(root, file)

            # S3(또는 MinIO) 내부 경로: 버킷 내에서 디렉토리 구조 유지
            # os.path.relpath를 사용하여 local_directory를 기준으로 상대 경로 생성
            relative_path = os.path.relpath(local_path, local_directory)
            s3_path = relative_path.replace("\\", "/")  # 윈도우 OS 대비 슬래시 처리

            # 파일 업로드
            s3_client.upload_file(local_path, bucket, s3_path)
            print(f"Uploaded {local_path} to {bucket}/{s3_path}")

# 함수 실행
upload_directory(local_folder, bucket_name, s3_client)

동작 방식

  1. os.walk 사용:
    os.walk(local_directory)로 지정한 local_folder 내의 모든 파일, 하위 디렉토리를 탐색합니다.

  2. 상대 경로 유지:
    업로드할 때 os.path.relpath를 사용하여 local_folder를 기준으로 상대 경로를 계산합니다. 이렇게 하면 로컬 구조와 동일한 폴더 구조를 MinIO 버킷 안에 재현할 수 있습니다.

  3. 업로드:
    s3_client.upload_file(local_path, bucket, s3_path)를 호출하면 해당 파일이 MinIO에 업로드됩니다.

  4. 출력:
    각 파일 업로드 시 어떤 경로로 업로드되었는지 출력하여 진행 상황을 알 수 있습니다.


그러나 이러한 방식으로는 총 파일갯수가 1000개 까지 밖에 못올린다. 왜냐하면 AWS S3 및 호환 API(list_objects_v2)는 한 번 호출 시 최대 1000개의 객체만 반환하기 때문이다. 1000개를 초과하는 객체 수를 세려면 Pagenation(페이지네이션)을 사용하여 모든 객체를 불러와야 합니다. MinIO 또한 S3 호환 API를 사용하므로 동일한 방법이 적용됩니다.

list_objects_v2 응답에서 IsTruncated 값이 True이면 아직 더 많은 오브젝트가 남아있음을 의미합니다. 이 경우 NextContinuationToken 값을 사용하여 다음 페이지를 불러올 수 있습니다.


수정 예시

아래는 calculate_bucket_stats 함수에서 모든 오브젝트를 순회하는 예시입니다.

def calculate_bucket_stats(bucket_name):
    total_size = 0
    total_files = 0

    s3_client = boto3.client(
        's3',
        endpoint_url='http://127.0.0.1:9000', # MinIO endpoint
        aws_access_key_id='your-access-key',
        aws_secret_access_key='your-secret-key'
    )

    # 첫 번째 요청
    response = s3_client.list_objects_v2(Bucket=bucket_name)
    
    while True:
        # 응답에 Contents 키가 있으면 객체 목록 처리
        if 'Contents' in response:
            for obj in response['Contents']:
                total_files += 1
                total_size += obj['Size']

        # 다음 페이지가 있는지 확인
        if response.get('IsTruncated'):  # 더 많은 오브젝트가 존재
            # 다음 페이지 요청: ContinuationToken 사용
            response = s3_client.list_objects_v2(
                Bucket=bucket_name,
                ContinuationToken=response.get('NextContinuationToken')
            )
        else:
            # 더 이상 오브젝트 없음
            break

    print(f"Bucket '{bucket_name}' Statistics:")
    print(f"- Total Files: {total_files}")
    print(f"- Total Size: {total_size / (1024**2):.2f} MB")

동작 방식

  1. 최초 호출: list_objects_v2(Bucket=bucket_name)로 최대 1000개의 오브젝트를 받아옵니다.
  2. IsTruncated 확인: 만약 IsTruncated=True라면 아직 더 많은 오브젝트가 남아있습니다.
  3. 다음 페이지 요청: NextContinuationTokenContinuationToken 파라미터로 사용하여 다음 1000개 오브젝트를 요청합니다.
  4. 반복: 더 이상 IsTruncated=False일 때까지 이 과정을 반복합니다.
  5. 결과: 모든 오브젝트를 순회한 후 총 개수와 크기를 출력합니다.

이렇게 페이지네이션을 통해 1000개를 초과하는 객체에 대해서도 전체 통계를 낼 수 있습니다.

profile
따라가기도 벅찬 AI Engineer 겸 부앙단

0개의 댓글