| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- BOJ
- redis
- Python
- CS
- 스프링
- 스프링 시큐리티
- MST
- spring security
- OS
- Spring
- 객체지향
- 운영체제
- 알고리즘
- Reflection
- 백준
- 문자열
- 파이썬
- 모던자바
- Junit5
- 리플렉션
- 다이나믹 프록시
- java
- 프록시
- Deadlock
- 최소 신장 트리
- 자바
- proxy
- 모던 자바 인 액션
- test
- 약수
- Today
- Total
Dev 달팽이 @_''
[AWS] Amaz S3 구축 및 이미지 업로드(Springboot) 본문
서론
사이드 프로젝트에서 S3를 구축하고 이미지를 업로드하는 기능을 맡게 되었습니다. 이 과정에서 알게 된 내용과 S3 구축, 그리고 S3에 이미지 업로드 하는 과정에 대한 포스팅입니다.
개발 환경 : Springboot
Amazon S3란?
Amazon S3란 Simple Storage Service의 약자로 Amazon에서 제공하는 파일 서버의 역할을 하는 클라우드 서비스이다. 프로젝트를 진행하다 보면 이미지나 파일을 업로드하는 작업을 자주 마주하게 된다.(ex. 프로필 이미지, 게시글 파일 혹은 이미지 업로드 등) 이 때, AWS의 S3를 사용한다.
객체와 버킷
S3의 용어로 객체(Object)와 버킷(Bucket)이 있다.
- 객체(Object) : 저장되는 파일
- 버킷(Bucket) : 객체에 대한 컨테이너(파일 시스템에서 최상위 폴더의 역할)
S3 구축 과정
Step 1. IAM 정책 생성
S3 접근을 위해 IAM 정책을 생성해야 한다.
IAM이란 AWS Identity and Access Management의 약자로 AWS 리소스에 대한 엑세스를 제어할 수 있는 웹 서비스이다. IAM을 사용하여 리소스를 사용하도록 인증(로그인) 및 권한 부여된 대상을 제어한다.
출처 : https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/introduction.html
AWS 서비스의 IAM -> 사용자 -> 사용자 추가 -> AWS 엑세스 유형에 프로그래밍 방식 선택

기존 정책 직접 연결 -> AmazonS3FullAccess 선택 -> 마지막 엑세스 키 ID와 비밀 엑세스 키 꼭 저장!!

IAM 정책 생성 완료

Step 2. Bucket 생성
AWS 서비스의 S3 -> 버킷 -> 버킷 생성

객체 소유권 ACL 활성화됨 선택 -> 버킷 소유자 선호 선택

이 버킷의 퍼블릭 엑세스 차단 설정 체크 해제

버킷 생성 완료

Step 3. 버킷 정책 지정하기
생성한 버킷 -> 권한 -> 버킷 정책 -> 편집 -> 정책 생성기 -> Add Statement
Principal : 사용자 ARN (생성한 사용자 IAM 정책 -> 요약 -> 사용자 ARN)
Amazon Resource Name(ARN) : 버킷 ARN

Generate Policy -> Json 복사

Step 4. Cors 설정
생성한 버킷 -> 권한 -> 버킷 정책 -> 편집 -> CORS(Cross-origin 리소스 공유) -> 편집 -> 아래 Json 복붙
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET", "PUT", "POST", "HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"ETag"
],
"MaxAgeSeconds": 3000
}
]
이미지 업로드
S3 구축이 끝났다. 이제 Spring을 통해 이미지를 업로드하는 과정이다. 이 과정은 실제 프로젝트에서 사용한 부분이다.
Step 1. Gradle 의존성 추가
// S3
implementation 'com.amazonaws:aws-java-sdk-s3:1.12.281'
Step 2. yml 파일 설정
cloud:
aws:
credentials:
access-key: {생성한 IAM 정책 엑세스 키 id}
secret-key: {생성한 IAM 정책 비밀 엑세스 키}
s3:
bucket: {생성한 버킷 이름}
region:
static: ap-northeast-2
stack:
auto: false
Step 3. Config 파일 생성
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AwsConfig {
@Value("${cloud.aws.region.static}")
private String region;
@Value("${cloud.aws.credentials.secret-key}")
private String secretKey;
@Value("${cloud.aws.credentials.access-key}")
private String accessKey;
@Bean
public AmazonS3 amazonS3() {
AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
return AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}
}
Step 4. Service 파일 생성
Controller에서 이미지 파일을 MultipartFile을 받아서 이를 S3에 저장했습니다. 기능상 Upload만 필요했기 때문에 Upload만 구현하였습니다.
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import java.io.IOException;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@RequiredArgsConstructor
@Slf4j
@Service
public class S3UploadService {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
private final AmazonS3 amazonS3;
public String upload(MultipartFile multipartFile, String dirName) throws IOException {
String fileName = dirName + "/" + UUID.randomUUID();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(MediaType.IMAGE_PNG_VALUE);
metadata.setContentLength(multipartFile.getSize());
amazonS3.putObject(new PutObjectRequest(bucket,fileName,multipartFile.getInputStream()
,metadata).withCannedAcl(CannedAccessControlList.PublicRead));
return amazonS3.getUrl(bucket,fileName).toString();
}
}
처음엔 MultipartFile을 File로 변환한 후 S3에 업로드하였습니다. 이 방식으로 파일을 업로드하면 실제 파일이 존재해야하기 때문에 파일을 create 해야합니다.
이로 인해 몇가지 문제점이 발생했습니다.
- 파일 write 작업이 일어남
- 로컬에도 파일이 저장 됨 -> 로컬에서 파일을 지우는 작업도 진행해야 함
- 코드가 전체적으로 길어짐
이러한 문제들로 인하여 InputStream을 그대로 업로드하였습니다.

위의 설명처럼 InputStream을 그대로 업로드하기 위해선 파일의 MetaData 알려줘야합니다.
따라서 ObjectMetaData를 생성했습니다.
마지막으로 저장된 이미지의 S3의 경로를 DB에 저장하기 위하여 S3 상의 이미지 경로를 반환하였습니다.
'기타' 카테고리의 다른 글
| [Redis] Redis Cluster (0) | 2023.07.27 |
|---|---|
| [배포] 무중단 배포와 배포 전략 (0) | 2023.07.25 |
| [Redis] 캐시(Cache) 설계 전략 (0) | 2023.07.24 |
| [Redis] Redis란? (0) | 2023.07.20 |
| 도커 입문 (0) | 2021.12.27 |