티스토리 뷰
개요
현재 프로젝트에서 파일 저장소로 S3를 사용하고 있다. 파일을 저장하면서 몇 가지 요구 사항이 붙게 됐다.
1. 업데이트를 하면 파일이 새로 업로드됨
2. 그런데 업데이트 하기 전 파일로 롤백하려는 요구 사항이 있을 수 있음
3. 그럼 업데이트된 파일을 어떻게 관리할 것인가? 사용하지 않는 파일에 아이디를 일일히 부여하는게 맞는가? 그럼 로우가 계속 늘어날텐데?
4. 그러면 삭제 정책이 필요한데, 얼마나 저장할 것이며 어떻게 삭제할 것인가? 스케줄러를 돌리는 것도 말이 안되지 않나?
이런식으로 계속 꼬리질문이 나오는 상황에서 S3를 뒤져보던 중 객체 버저닝이란 것을 알게 됐다.
https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/versioning-workflows.html
장점은 같은 id로 계속 올리면 이전 버전이 계속 누적되서 저장된다. 그리고 일정 주기가 지나면 삭제되도록 지정할 수 있다. 이 방식으로 업데이트 시 삭제를 서비스 로직에서 구현하지 않아도 된다던가 등의 여러가지 이점을 얻을 수 있다.
설정 방법부터 하나씩 알아보자 별로 어렵지 않다. 이전부터 사용했던 Terraform을 이용할 것이다.
Terraform으로 설정하기
먼저 s3 버킷을 만든다. 프라이빗 버킷을 만드는 법은 간단하다.
resource "aws_s3_bucket" "private_repository" {
bucket = "my-drive"
}
버전 설정 켜기
resource "aws_s3_bucket_versioning" "private_repository_versioning" {
bucket = aws_s3_bucket.private_repository.id
versioning_configuration {
status = "Enabled"
}
}
versioning_configuration을 enabled로 설정하면 간단하게 설정 가능하다.
수명 주기 설정
resource "aws_s3_bucket_lifecycle_configuration" "private_repository_lifecycle" {
bucket = aws_s3_bucket.private_repository.id
rule {
id = "expire-old-versions"
status = "Enabled"
filter {}
noncurrent_version_expiration {
noncurrent_days = 1
}
}
}
expire-old-versions를 id로 지정하고 noncurrent_version_expriation 블록에 일자를 설정하면 오래된 버전 객체들을 대상으로 지정할 수 있다. 이런 수명 주기 규칙들은 콘솔에서도 설정 가능하다. AWS S3 파일 주기적으로 삭제하기 : SpringBoot에서 미리 서명된 URL(pre-signed URL) 써보기
당장은 테스트용으로 1일로 설정했다.
이렇게 설정하면 객체 버저닝이 설정되고 1일 후 삭제된다. 동일한 key를 갖는 객체를 업로드하고 s3 콘솔에서 객체에 접근한 다음 버전 탭을 눌러보면 다음과 같이 나온다.
스프링에서 접근하기
이전 버전의 객체에 접근하는 방법은 별로 어렵지 않다.
fun getVersionedObject(path: String, versionId: String) {
val getRequest = GetObjectRequest.builder()
.bucket(DriveConstants.DRIVE_BUCKET_NAME)
.key(path)
.versionId(versionId)
.build()
s3Client.getObject(getRequest)
}
당연히 versionId가 필요하기 때문에, 어딘가에 versionId를 저장해놓고 써야한다.
추가적으로 스프링에서도 S3 버저닝을 옵션을 켤 수 있다.
@Component
class S3Initializer(private val s3Client: S3Client) : CommandLineRunner {
override fun run(vararg args: String?) {
val bucketName = DriveConstants.DRIVE_BUCKET_NAME
// 이미 버저닝이 활성화된지 확인 후 실행
checkVersioningStatus(s3Client, bucketName)
enableS3Versioning(s3Client, bucketName)
}
fun enableS3Versioning(s3Client: S3Client, bucketName: String) {
val versioningRequest = PutBucketVersioningRequest.builder()
.bucket(bucketName)
.versioningConfiguration { it.status(BucketVersioningStatus.ENABLED) }
.build()
s3Client.putBucketVersioning(versioningRequest)
println("✅ 버킷 '$bucketName'에 대한 S3 버저닝이 활성화되었습니다!")
}
private fun checkVersioningStatus(s3Client: S3Client, bucketName: String) {
val request = software.amazon.awssdk.services.s3.model.GetBucketVersioningRequest.builder()
.bucket(bucketName)
.build()
val response = s3Client.getBucketVersioning(request)
val status = response.status() ?: "Not Enabled"
println("📌 버킷 '$bucketName'의 버저닝 상태: $status")
}
}
다만 이 방식을 별로 권장하고 싶지 않은게, 한번만 설정하면 되는데 이렇게 설정하면 빈이 띄워질때마다 버저닝 설정을 켜게 되서 불필요한 작업을 하게 된다.
마치며
이 글은 내가 마주했던 이슈를 해결하기 위해 s3 버저닝의 기술 중 필요한 부분만 가져와서 대응한 것을 정리한 글이다. 그래서 s3 버저닝의 다양한 룰에 대해서 전부 다루지 않았다. s3 버저닝의 세부 옵션에는 버전이 내려간 객체를 GLACIER 옵션으로 변경한다던가, 낮은 버전의 객체 전체를 삭제한다던가 등의 다양하고 세부적인 요구 사항에 맞는 기능이 있다.
특히 삭제 마커쪽이 굉장히 흥미로웠는데, 이 글에선 따로 다루진 않았다. 기회가 되면 한번 읽어보길 권장한다.
https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/DeletingObjectVersions.html
버전 관리가 사용 설정된 버킷에서 객체 버전 삭제 - Amazon Simple Storage Service
이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.
docs.aws.amazon.com
'개발 > SPRING' 카테고리의 다른 글
Kotlin + SpringBoot에 JOOQ 적용기 - 2. 쿼리 사용해보기 (0) | 2025.03.23 |
---|---|
스프링부트에서 무조건 한번 실행하게 하기 (0) | 2025.03.07 |
Kotlin + SpringBoot에 JOOQ 적용기 - 1. 선택 이유와 코드 자동 생성하기 (0) | 2025.02.28 |
테스트를 도입하면서 느낀점과 고민들 (0) | 2024.08.14 |
SpringBoot에서 MultipartFile 전송하기 feat. FeignClient (1) | 2024.07.23 |
- Total
- Today
- Yesterday
- MySQL
- Elastic cloud
- AWS
- object
- docker
- serverless
- Spring
- elasticsearch
- 오블완
- lambda
- ChatGPT
- java
- CloudFront
- AOP
- GIT
- 람다
- AWS EC2
- 스프링부트
- 후쿠오카
- Kotlin
- openAI API
- EKS
- cache
- terraform
- OpenAI
- S3
- Log
- springboot
- JWT
- 티스토리챌린지
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |