Simple Storage Service (S3)란?
사진, 동영상 등 파일을 저장하기 위해 사용하는 파일 서버 서비스.
S3의 버킷에 파일을 업로드 하면, URL로 파싱되어 사용자가 이용할 수 있는 서비스이다.
서버에 이미지나 파일 등을 업로드 할 때 로컬 서버에 저장할 경우 데이터가 쌓이다 보면 언젠가 용량이 초과되겠지?
따라서 S3를 사용하면 좋은 점은 다음과 같다.
1. 확장성(Scalability)
파일 서버는 트래픽이 증가함에 따라 서버 인프라 및 용량 계획을 변경해야 되는데, S3가 확장 및 성능 부분을 대신 처리해준다.
2. 내구성(Durability)
여러 영역에 여러 데이터 복사본을 저장하므로 한 영역이 다운되더라도 데이터를 사용할 수 있고, 복구가 가능하다.
이를 Spring 환경에서 적용해보고 EC2에서 S3에 접근하는 과정을 살펴보도록 하자
IAM (Identity and Access Management)이란?
IAM은 AWS 계정 내에서 사용자와 역할을 관리하며, AWS 리소스에 대한 액세스 권한을 부여한다.
S3와 IAM을 함께 사용하는 이유는 IAM 키를 통해 버킷의 권한을 부여하여 보다 효율적으로 관리하기 위해서이다.
EC2에서 S3 버킷에 접속하기 위해서는 IAM에서의 S3 버킷에 대한 접근 권한을 획득한 후, EC2에서 S3에 접근할 수 있는 권한을 획득해야 EC2 서버에서 S3로 접속할 수 있다.
따라서 EC2에 연결해야 할 IAM 역할을 생성해야 하고, IAM 역할에 대해 S3 버킷에 접속할 수 있는 정책을 생성하여 EC2에 적용해야 한다.
1. S3 Bucket 생성
이미지 또는 파일을 업로드 하기 위한 S3 버킷을 생성해야 한다.
필자는 alpha-dlink 라는 이름의 버킷을 생성했다.
버킷을 생성하고 나서 Bucket의 권한 -> 버킷 정책 -> 편집 -> 정책 생성기 를 클릭하여 직접 권한을 생성해준다.
Type of Policy : S3 Bucket Policy
Effect : Allow
Principal : * (모두 선택)
Actions : GetObject, PutObject 선택
ARN : arn:aws:s3:::${버킷이름}/*
이렇게 옵션을 선택해주고 Add Statement -> Generate Policy를 눌러 정책을 생성한다.
생성된 정책을 복사하여 S3 Bucket의 정책 편집 페이지에서 붙여넣기 후 변경사항 저장 하면 끝이다.
2. IAM Policy 생성
EC2에 등록할 IAM 인증 역할에 필요한 정책을 등록해야 한다.
(만약 S3의 모든 기능을 사용하고 싶으면 이 과정을 생략해도 된다.)
- IAM -> 정책 -> 정책 생성
우리는 S3에 대한 정책을 생성할 것이기 때문에 S3를 선택한다.
1. 작업 허용에 다음과 같은 항목을 선택한다
- GetObject
- PutObject
- ListBucket
2. 리소스에는 특정 선택 후 bucket에는 arn:aws:s3:::${생성해준 버킷 이름}을, object에는 arn:aws:s3:::${버킷이름}/* 을 입력해준다.
이렇게 저장하게 되면 정책 생성은 끝이다.
3. AWS IAM 역할 생성.
위에서 생성해준 정책을 사용할 IAM 역할을 만들어야 한다. 바로 EC2에서 S3 버킷에 접속하기 위한 역할이다.
- IAM > 역할 > 역할 생성
EC2에 적용해야 하기 때문에 서비스는 EC2로 설정해준다.
- 권한 추가
이전에 생성해주었던 정책을 등록한다. (만약, 생성하지 않았다면 권한에서 AmazonS3FullAccess 을 선택한다)
이후 역할 이름을 정하고 최종적으로 생성하면 된다.
4. IAM 사용자 생성
AWS console > IAM > 엑세스 관리 > 사용자 > 사용자 추가 클릭
S3에 접근하기 위해서는 IAM 사용자에게 S3 접근 권한을 주고, 엑세스 키를 만들어 액세스 키, 비밀 엑세스 키를 접근해야 한다.
권한을 설정하고 생성을 완료한다.
생성한 사용자 > 보안 자격 증명 > 액세스 키 생성 을 통해 S3 버킷에 접속할 수 있는 accessKey를 발급해야 한다.
액세스 키의 경우 이 화면에서만 보여주고 나중에 알 수 있는 방법이 없기 때문에, 복사를 해두거나 csv 파일로 미리 다운로드 해놓아야 한다.
5. Spring에서 S3 버킷 적용
Spring boot 3.x 버전에서는 Spring Cloud 3 버전부터 사용하는 것이 좋다!
자세한 것은 공식 reference 참고
https://spring.io/projects/spring-cloud-aws#learn
build.gradle에 의존성 추가
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
application.yml 추가
accessKey와 secretKey는 IAM 생성자 생성하면서 발급받은 액세스 키를 입력
cloud:
aws:
s3:
bucket: <버킷명>
stack.auto: false
region.static: <region>
credentials:
accessKey: <발급받은 공개키>
secretKey: <발급받은 비밀키>
cloud.aws.stack.auto 속성을 false로 지정하지 않으면 StackTrace가 발생한다. Spring Cloud AWS는 기본적으로 서비스가 Cloud Formation 스택내에서 실행된다고 가정하기 때문에 그렇지 않은 경우 임의로 false 값으로 설정을 해줘야한다.
파일 업로드 용량 제한
maxFileSize의 경우 default값이 1048576 bytes 로 약 1MB이다.
미리 용량을 풀어두지 않으면 FileSizeLimitExceededException 에러가 뜰수도 있다.
maxRequestSize의 경우 default값이 -1로 제한이 없다.
spring:
servlet:
multipart:
maxFileSize: 30MB # 파일 하나의 최대 크기 (예시 30MB)
maxRequestSize: 100MB # 한 번에 최대 업로드 가능 용량
s3 Config 파일 생성
@Configuration
public class S3Config {
@Value("${s3.accessKey}")
private String accessKey;
@Value("${s3.secretKey}")
private String secretKey;
@Value("${s3.region}")
private String region;
@Bean
public AmazonS3 amazonS3Client() {
BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
return AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}
}
S3 파일 조작
@RequiredArgsConstructor
public class FileUploadController {
private final AmazonS3 amazonS3;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
// 파일 업로드
@PostMapping
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
try {
String fileName = file.getOriginalFilename();
String fileUrl = "https://" + bucket + "/post_image/" + fileName;
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(file.getContentType());
metadata.setContentLength(file.getSize());
PutObjectRequest request = new PutObjectRequest(bucket, "post_image/" + fileName, file.getInputStream(), metadata);
amazonS3.putObject(request);
String url = amazonS3.getUrl(bucket, "post_image/" + fileName).toString(); // 객체 URL 획득
return ResponseEntity.ok(url);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
// 파일 삭제
public void deleteFile(String fileUrl) {
String[] urlParts = fileUrl.split("/");
String fileBucket = urlParts[2].split("\\.")[0];
if (!fileBucket.equals(bucket)) {
throw new Exception400("fileUrl", ErrorMessage.NO_IMAGE_EXIST);
}
String objectKey = String.join("/", Arrays.copyOfRange(urlParts, 3, urlParts.length));
if (!amazonS3.doesObjectExist(bucket, objectKey)) {
throw new Exception400("fileUrl", ErrorMessage.NO_IMAGE_EXIST);
}
try {
amazonS3.deleteObject(bucket, objectKey);
} catch (AmazonS3Exception e) {
log.error("File delete fail : " + e.getMessage());
throw new Exception500(ErrorMessage.FAIL_DELETE);
} catch (SdkClientException e) {
log.error("AWS SDK client error : " + e.getMessage());
throw new Exception500(ErrorMessage.FAIL_DELETE);
}
log.info("File delete complete: " + objectKey);
}
}
참고
[Spring] S3 이미지 업로드하기
사진, 동영상 등 파일을 저장하기 위해 사용하는 파일 서버 서비스. 일반적인 파일서버는 트래픽이 증가함에 따라서 장비를 증설하는 작업을 해야 하는데 S3는 이와 같은 것을 대행한다.
velog.io
'Infra & Cloud > AWS' 카테고리의 다른 글
[AWS] AWS RDS vs AWS Aurora 비교 분석 (2) | 2024.11.20 |
---|---|
[AWS] EC2 환경에서 Redis 구축하기 (0) | 2024.07.25 |
[AWS] EC2와 RDS 연결하기 (0) | 2024.07.25 |
[AWS] EC2에 MySQL 적용 및 사용하기 (0) | 2024.06.15 |
[AWS] EC2에서 https 프로토콜 적용하기 (0) | 2024.05.25 |