본문 바로가기
Today I Learned 2024. 7. 22.

(24.07.22)[15주차] MinIO 활용 정리

프로젝트 구성에 있어서 데이터를 저장하고, 조회, 그리고 수정도 할 수 있게끔 기능을 추가를 했다.

DI 배포 파이프라인에 따라서 AWS S3를 사용해야하지만,

개발 단계에서 테스트용으로 직접적으로 사용하는데에는 비용적으로 부담이 크고, 빠르게 변경을 할 수 없다는 단점이 있다.

이 때, 오픈 소스 객체 스토리지 서버인 MinIO를 활용하여 개발을 진행하려고 한다.

 

이를 위해 아래에는 MinIO를 활용하기 위해 정리하고 학습한 내용이다.


MinIO

  • 오픈 소스 객체 스토리지 서버를 제공해주는 소프트 웨어
    • 오픈 소스 이므로 커뮤니티를 통한 정보와 문서가 제공되고 있음
    • 쉬운 튜토리얼이 가능 : WebUI 제공
  • Amazon S3 API와 호환이 가능
    • 실제 S3에 배포 전 기능을 그대로 활용해서 개발, 테스트를 실제 환경과 똑같은 시뮬레이션을 통해서 진행이 가능
  • Object Storage 형태이기 때문에 직접적으로 접근하여 수정이 아닌 덮어쓰는 방식으로 사용
    • 저장 단위가 객체(데이터, 메타데이터, 식별자)
    • 객체 키를 사용해서 파일 업로드시 기존 객체는 새 객체로 덮어써지는 방식 → 동일 객체에 대해 여러 버전을 관리가 가능
  • 전송중인 데이터, 저장 데이터를 암호화 해서 다룰 수 있는 높은 보안성
  • Kubernetes, Docker, 다양한 OS 환경에 구분없이 적용 가능
    • 따라서, 로컬 개발도 가능

참고 : https://min.io/

MinIO 환경 모드

Stand-alone 단독 모드

version: "3"

services:
  minio:
    image: minio/minio:latest // dockerhub 사용
    container_name: minio
    # restart: always
    ports:
      - '9000:9000' // 파일 업로드 다운로드 포트
      - '9001:9001' // WebUI 사용할수 있는 포트
    environment:
      - MINIO_ROOT_USER=minio // 개인설정
      - MINIO_ROOT_PASSWORD=miniopass // 개인설정
    command: server --address ":9000" --console-address ":9001" /data
    volumes:
      - ~/docker-repo/minio:/var/lib/minio

volumes:
  minio_data:
    external: true
  • MinIO 기본 실행 모드, 단일 서버 인스턴스에서 MinIO 실행 방식
    • 따라서, 로컬 개발, 테스트 / 단일 서버에서 실행 가능
  • docker-compose 파일을 사용해서 docker을 통해서 Container 실행을 통해 MinIO 실행
  • HTTP 방식으로 위의 command에 따라서 http://localhost:9000 으로 접속해서 WebUI를 통해서 컨트롤 가능
    • HTTPS 로 사용시 따로 사용자가 인증서 발급을 진행해야함

Distributed Mode 분산모드

version: "3"

services:
  **minio1**:
    image: minio/minio:latest
    container_name: minio1
    ports:
      - '9000:9000'
      - '9001:9001'
    environment:
      - MINIO_ROOT_USER=minio
      - MINIO_ROOT_PASSWORD=miniopass
    command: server <http://minio1/data> <http://minio2/data>
    volumes:
      - ~/docker-repo/minio1:/data

  **minio2**:
    image: minio/minio:latest
    container_name: minio2
    ports:
      - '9002:9000'
      - '9003:9001'
    environment:
      - MINIO_ROOT_USER=minio
      - MINIO_ROOT_PASSWORD=miniopass
    command: server <http://minio1/data> <http://minio2/data>
    volumes:
      - ~/docker-repo/minio2:/data

networks:
  default:
    driver: bridge
  • MinIO의 클러스터링 기능을 통해 다수의 서버 인스턴스로 분산해서 운영할 수 있게끔 하는 모드
    • 따라서, 고가용성과 데이터 복제 기능을 사용할 수 있음
  • 대규모 환경과 데이터 안정성을 더 우선순위로 다룰 때 사용
  • 단독 모드의 설정에서 services의 minio를 minio1, minio2 … 이런 방식으로 여러개를 작성해서 Docker로 실행할 수 있음
  • → 컨테이너를 여러개 만드는 것

MinIO 데이터 관련 모드

  • 관련하여 따로 설정을 해줘야함

FS, File System 모드

  • Storage Backend Modes
  • MinIO 서버가 실행이 될 경우, 파일 시스템을 Storage BE로 사용을 하는 모드
  • 로컬 파일 이나 네트워크 파일 시스템을 따로 저장소로 활용이 가능
    • 여러 MinIO 인스턴스가 다른 환경에서 동일한 FS로 활용할 수 있음
    • MinIO가 아닌 FS를 통한 객체 수정이 가능 → 보안에 위험

EC, Erasure Code 모드

  • 데이터 자체를 나눠서 저장공간을 분리해서 저장하고, 복구를 할 수 있도록 하는 방법
    • 따라서 단독모드에서 사용하기 어려움
  • 고가용성과 데이터 안전성을 우선이 될 떄 사용이 가능

S3 환경 테스트를 위한 MinIO 활용

  • AWS S3세팅 처럼 Bucket을 생성하고, 이를 최상단 폴더 처럼 판단해서 사용을 할 수 있음

MinioClient 세팅

  • Gradle 주입
dependencies {
    implementation 'io.minio:minio:8.3.4'
}
  • MinioClient를 위한 Config구성
@Configuration
public class MinioConfig {

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint("<http://localhost:9000>") //minio port 주소
                .credentials("minio", "miniopass") //아이디 비밀번호
                .build();
    }
}

  • 주입을 통해 파일을 업로드 시킬 수 있는 클라이언트

Java Spring → docker에 의한 Container의 MinIO

// 간단한 작동 로직을 알기 위한 연습용 Controller
@RestController
public class FileUploadController {

    @Autowired
    private MinioClient minioClient; // Client 주입

    @Autowired
    private FileRecordRepository fileRecordRepository; // 특정 Repository

    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestBody MyRequest myRequest) {
        try {
            // JSON 데이터에서 특정 필드 값을 추출
            String content = myRequest.getFieldToSave();
            
            // 파일로 저장할 내용을 ByteArrayInputStream으로 변환
            ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
            String fileName = "myfolder/myfile.txt"; // 저장할 파일 이름 (폴더 경로 포함)

            **// MinIO에 파일을 업로드**
            **minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket("mybucket")
                            .object(fileName)
                            .stream(inputStream, inputStream.available(), -1)
                            .contentType("text/plain")
                            .build()
            );**

            // 파일 정보를 DB에 저장 (선택 사항, 객체와 파일간의 관계를 명확하게 하기 위한 작업)
            FileRecord fileRecord = new FileRecord();
            fileRecord.setFileName(fileName);
            fileRecord.setSomeOtherField(myRequest.getSomeOtherField());
            fileRecordRepository.save(fileRecord);

            return ResponseEntity.ok("파일 업로드 성공");
        
        } catch (Exception e) {
            return ResponseEntity.status(500).body("파일 업로드 실패");
        }
    }

		// 저장할 파일의 정보를 가지고 오는 임의의 클래스
    static class MyRequest {
        private String fieldToSave;
        private String someOtherField;

        public String getFieldToSave() {
            return fieldToSave;
        }

        public void setFieldToSave(String fieldToSave) {
            this.fieldToSave = fieldToSave;
        }

        public String getSomeOtherField() {
            return someOtherField;
        }

        public void setSomeOtherField(String someOtherField) {
            this.someOtherField = someOtherField;
        }
    }
}

 


해당 MinIO는 기본적으로 코드를 첨부해서 게시글을 만들때, DB에 무리를 주지 않고 따로 코드를 관리하기 위해서 분리를 한 상태를 위해서 사용을 한다.

Sparta 최종 프로젝트에서의 테스트에 사용을 할 예정이고, 기타 잘 작동이 될 경우, 사진이나 미디어를 첨부할 수 있는 용도로 사용할 수 있도록 응용할 계획