Spring Boot(kotlin, java21) + Oracle Cloude Object Storage 연결설정하기

한로·2025년 4월 28일

오늘도 GPT 를 괴롭혀서 연결에 성공

1. Buckets 생성


버킷생성을 클릭한다.
창이 뜨는데 여기서
Enable Object Versioning,
Uncommitted Multipart Uploads Cleanup 를 체크했다.
특별한 이유가 있는 건 아니었고, 이게 효율적이지 않나..? 싶은 마음에 체크했다.

Lifecycle Policy Rules

생성하고 나면 무슨무슨 에러창이 뜬다.
Uncommitted Multipart Uploads Cleanup 에 대한 권한이 없다는 오류인데

생성된 버킷으로 이동하여 Resources -> Lifecycle Policy Rules

난 이미 추가했다.
Create Rule를 클릭하여

Uncommitted Multipart Uploads 만들어준다

2. Spring boot properties 설정 정보

  1. oci.profile
  2. oci.namespace
  3. oci.bucketName
  4. oci.compartmentId

1. oci.profile

Profile -> userEmail 클릭하여 이동

API Keys가 필요하다

add 전에 Download private key를 받아준다. 나중에 사용할 거

생성하고 나면
view configuration file를 클릭하면

이렇게 정보가 뜬다.

이후 설정은 파일을 찾아야한다.
여기서 아주 고생했다.

처음에 GPT는 특정 경로에 파일이 있을 거라고 했는데, 나는 웹에서 Oracle 설정을 하고 있는데 언제 어떻게 다운이 된 건지 이해가 되지 않았다. 그래서 그냥 내가 파일을 만들었다. 주의해야 하는 건 파일 확장자다.
파일 확장자가 없어야 한다.

내 경로는 C:\Users\devji\.oci이다. 이 경로를 뭐라고 부르는 명칭이 있었던 것 같은데 기억이 안 난다.. ‘홈 디렉터리?’ ‘사용자 프로필 폴더’였던 것 같다.

이 경로가 중요하다고 하는 이유는 Oracle Cloud Infrastructure (OCI) SDKOCI CLI(Command Line Interface)가 설정 파일을 자동으로 찾기 위한 표준 기본 위치라고 한다.

그래서 config 파일을 만들기 전에 파일 확장명, 숨긴 항목 표시를 해줘야 한다.
파일을 생성할 거라면 숨긴 항목은 필요 없는데 만약 .oci 폴더가 있을 경우 안 보일 수 있다고 한다.

.oci 파일이 없다면 .oci 폴더 생성 후 config 파일을 생성한다.
메모장 생성 후 아까 나왔던 정보(API keys)에서 COPY 하여 붙여넣기

copy 한 내용을 보면 마지막에 key_file=<path to your private keyfile> # TODO 라고 있다 이거는 아까 위에서 API keys 만들 때 다운받은 path 경로를 입력하면 된다.
나는 config 파일과 같은 위치에 넣어놨다.
경로는 전체다 입력해주어야 오류가 발생하지 않았다...!!
key_file=C:\Users\devji\.oci\dev.jinsung1017@gmail.com_2025-04-28T15_25_29.795Z.pem


이제 확장자를 제거해준다. 속성에서 .txt 삭제

oci.profileconfig에서 화살표에 해당하는 정보다. DEFAULT

2. oci.namespace

namespace 는 생성한 bucket으로 이동해서 확인할 수 있다.

3. oci.bucketName

이건 bucketName!

4. oci.compartmentId

이게 찾느라 헷갈렸던 부분
Compartments 를 검색하면 Services에 나온다.

클릭해서 들어가면 내가 생성한게 보이고 OCIDcompartmentId에 해당한다.

이 정보를 이제 정리해서 properties 에 입력해준다

oci.profile=DEFAULT
oci.namespace=nameSpace
oci.bucketName=bucketName
oci.compartmentId=ocid

의존성 추가

    implementation("com.oracle.oci.sdk:oci-java-sdk:3.38.0")
    implementation("com.oracle.oci.sdk:oci-java-sdk-common:3.38.0")
    implementation("com.oracle.oci.sdk:oci-java-sdk-objectstorage:3.38.0")
    implementation("com.oracle.oci.sdk:oci-java-sdk-common-httpclient:3.38.0")
    implementation("com.oracle.oci.sdk:oci-java-sdk-common-httpclient-choices:3.38.0")
    implementation("com.oracle.oci.sdk:oci-java-sdk-common-httpclient-jersey3:3.37.0")

Service Test

GPT 가 만들어준 코드! 아래 코드를 복사하여 파일 하나 만들어준다.
그리고 빌드하면 로그에서 확인이 가능하다.
실제 테스트를 해봐야겠지만..일단 연결은 잘 된 것으로 보인다..
정말 쉽지 않은 연결설정이었다..



import com.oracle.bmc.objectstorage.responses.ListBucketsResponse


import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider
import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider
import com.oracle.bmc.objectstorage.ObjectStorageClient
import com.oracle.bmc.objectstorage.requests.ListBucketsRequest
import com.oracle.bmc.objectstorage.model.BucketSummary

import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import jakarta.annotation.PostConstruct


import java.io.IOException

@Service // 이 클래스를 Spring Service 빈으로 등록
class OciConnectionTestService {

    // application.properties에서 설정 값을 주입받습니다.
    @Value("\${oci.profile:DEFAULT}") // Spring 속성 플레이스홀더의 $ 문자를 이스케이프(\) 처리합니다.
    private lateinit var profile: String

    @Value("\${oci.namespace}")
    private lateinit var namespace: String

    @Value("\${oci.compartmentId}")
    private lateinit var compartmentId: String

    private lateinit var objectStorageClient: ObjectStorageClient

    // Spring Boot 애플리케이션의 빈 생성이 완료되고 속성이 주입된 후 자동으로 실행됩니다.
    @PostConstruct
    fun testOciConnection() {
        println("--- OCI Object Storage 연결 테스트 시작 (Kotlin) ---")
        try {
            // 1. 인증 정보 제공자 초기화
            // ConfigFileAuthenticationDetailsProvider는 기본적으로 ~/.oci/config 파일을 찾아 읽고
            // 지정된 프로파일(여기서는 application.properties에서 주입받은 profile)을 사용합니다.
            val provider: AbstractAuthenticationDetailsProvider =
                ConfigFileAuthenticationDetailsProvider(profile)

            // 2. Object Storage 클라이언트 초기화
            objectStorageClient = ObjectStorageClient.builder().build(provider) // <-- 이 줄로 수정합니다.
            println("OCI ObjectStorageClient 초기화 성공.")

            // 3. 테스트 작업 수행: 설정된 컴파트먼트의 버킷 목록 가져오기
            println("네임스페이스: $namespace, 컴파트먼트: $compartmentId 에서 버킷 목록 가져오기 시도...")

            // ListBucketsRequest 객체 생성 (Java 빌더 패턴과 유사하게 사용)
            val listBucketsRequest = ListBucketsRequest.builder()
                .namespaceName(namespace) // 주입받은 네임스페이스 사용
                .compartmentId(compartmentId) // 주입받은 컴파트먼트 ID 사용
                .build()

            // 요청 실행
            val response: ListBucketsResponse = objectStorageClient.listBuckets(listBucketsRequest)

            // 응답에서 버킷 목록 가져오기 (Kotlin에서는 getter 대신 속성처럼 접근 가능)
            val buckets: List<BucketSummary> = response.items

            if (buckets.isEmpty()) {
                println("OCI 연결 성공. 해당 컴파트먼트에 버킷이 없습니다.")
            } else {
                println("OCI 연결 성공. 찾은 버킷 목록:")
                // Kotlin의 for 루프 또는 forEach 사용
                for (bucket in buckets) {
                    println("- ${bucket.name}") // getter 대신 속성처럼 접근
                }
                // 또는 forEach 루프 사용 예시:
                // buckets.forEach { println("- ${it.name}") }
            }

            println("--- OCI 연결 테스트 완료 (성공) ---")

        } catch (e: IOException) {
            System.err.println("OCI SDK 초기화 또는 config 파일 읽기 오류: ${e.message}")
            e.printStackTrace()
            System.err.println("--- OCI 연결 테스트 실패 ---")
        } catch (e: Exception) {
            System.err.println("OCI 연결 테스트 중 예상치 못한 오류 발생: ${e.message}")
            e.printStackTrace()
            System.err.println("--- OCI 연결 테스트 실패 ---")
        }
        // 클라이언트 자원 해제 (이 간단한 테스트에서는 생략)
    }

}

Oracle의 Instance, AutonomousDatabase(Transaction Processing), AutonomousDatabase(JSON), Object Storage
이전에 사용하던 타회사 서버에서 Oracle Cloude로 연결 설정을 모두 완료했다.
처음 사용해봐서 많이 고생했지만 완료했다는 점이 뿌듯하다.
앞으로는 CI/CD 를 적용할 예정!

profile
"Hello World"

0개의 댓글