Infra/AWS

AWS - S3를 활용한 파일 및 이미지 업로드

now0204 2024. 5. 9. 15:55

s3란?

파일 저장 서비스이다.  사진이나 동영상 같은 파일을 구글 드라이브나 icloud에 업로드 하는 것과 비슷하다

 

  • 백엔드 서버를 구현하다보면, 이미지 업로드를 구현할 때가 많다. 이 이미지를 EC2 내부에 저장할 수도 있지만, EC2에 쌓이는 파일이 너무 많아질 우려가 있다.
  • 따라서 파잃은 S3서비스를 이용해서 따로 관리하는 것이다.
  • 현업에서도 파일 업로드 기능을 구현할 때면 대부분 S3를 활용한다고 한다.

1. S3 버킷 생성하기

버킷이란? 
    S3 서비스 내에 여러 Repositroy를 의미한다. 
객체란?
   S3에 업로그한 파일을 파일이라 부르지 않고 객체라고 부른다. 

 

  • 버킷에 이미지나 파일을 올리기 위해 모든 퍼블릭 액세스를 일단 허용해두자


2. 버킷 정책 추가하기 

정책이란 권한을 정의하는 JSON문서이다. AWS의 특정 소스에 접근하려면 권한을 허용해 주어야 한다.
  • 모든 사용자에게 상품 이미지를 보여주거나, 다운받을 수 있게 하려면, 액세스를 해제하는 것과 동시에 권한을 주어야한다.
  • 버킷에 들어가서 버킷 정책에 편집을 누르자

 

  • ARN에 {버킷명}/접근 오브젝트 명 (*이면 모든 오브젝트)
  • 그냥 접근 가능한 오브젝트에 경로 설정해주는 부분이다 
ARN이란  Amazon Resource Number의 약자이다. AWS에 존재하는 리소스를 표현하는 문법이다.
  • 마지막으로 principal을 설정해 주자 이는 허용 대상을 의미한다. *이면 모두에게 허용하는 것


3.  S3에 파일을 업로드 할 수 있도록 IAM에서 엑세스 키 발급받기 

 

  • AWS의 리소스에 아무나 접근 못하도록 막아놨으므로, S3에 접근해서 파일을 막 업로드할 수 는 없다.
  • 백엔드 서버에서만 업로드 할 수 있도록 하기 위해 키를 발급 받고, 이를 서버 설정에 추가해줘야한다.
  • 먼저 IAM으로 들어가자 

  • 사용자를 추가하자 

  • 여기서 직접 정책 연결은 AWS에서 미리 지정해둔  ROLE들을 의미한다. 
  • 마치 DB에서 권한을 설정할 때 세부적으로 설정할 수 도 있지만, 권한들을 미리 묶어둔 ROLE이 있는 것과 같다

 

  • 이제 엑세스 키를 만들자 

  • AWS 외부에서 실행되는 애플리케이션이 백엔드 서버 같은 걸 의미한다.

  • 발급받은 액세스 키는 두번 알려주지 않는다. 까먹으면 새로 발급받아야한다. 
  • 잘 저장해두자 

 

 

 

  • 버킷 종료시 안에 있는 파일을 모두 삭제하고 버킷만 삭제하면 된다.

4. 스프링 부트 S3 연동하기 

 

  • 먼저 의존성을 하나 추가해준다. 
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

 

  • application.yml에 설정 정보를 추가한다. 
cloud:
  aws:
    s3:
      bucket: <S3 버킷 이름>
    credentials:
      access-key: <저장해놓은 액세스 키>
      secret-key: <저장해놓은 비밀 액세스 키>
    region:
      static: ap-northeast-2
      auto: false
    stack:
      auto: false
  • 주의할 점으로 저어어어얼대 이 설정을 github에 올리면 안된다. 털리면 엄청난 과금 폭탄을 맞을 수 있다.
  • region은 아시아로 연동되어 있다.
  • stack은 EC2에서 

 

  • 다음으로 Config 파일을 구성하자 
@Configuration
public class S3Config {

    @Value("${cloud.aws.credentials.access-key}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String secretKey;

    @Value("${cloud.aws.region.static}")
    private String region;

    @Bean
    public AmazonS3Client amazonS3Client() {
    	//accessKey, secretKey, region 값으로 S3에 접근 가능한 객체 등록 
        BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);

        return (AmazonS3Client) AmazonS3ClientBuilder
                .standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .build();
    }
}

 

4.1 파일 업로드 

 

@Service
@RequiredArgsConstructor
public class S3UploadService {

    private final AmazonS3 amazonS3;

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;

    public String saveFile(MultipartFile multipartFile) throws IOException {
        String originalFilename = multipartFile.getOriginalFilename();

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(multipartFile.getSize());
        metadata.setContentType(multipartFile.getContentType());

        amazonS3.putObject(bucket, originalFilename, multipartFile.getInputStream(), metadata);
        return amazonS3.getUrl(bucket, originalFilename).toString();
    }
}
  • putObject 메서드가 파일을 저장해주는 메서드이다.
  • ObjectMetadata에 파일의 사이즈와 타입을 입력한다.
  • 마지막에 파일 URL은 꼭 줘야하는건 아님! 들어가서 확인할 수 있도록 URL Return해준것
  • ObjectMetadata는 com.amazonaws.services.s3.model 패키지에 존재한다.
    • S3에 저장될 Object(파일)의 정보를 저장하는 객체이다. 

4.2 파일 다운로드

public ResponseEntity<UrlResource> downloadImage(String originalFilename) {
    UrlResource urlResource = new UrlResource(amazonS3.getUrl(bucket, originalFilename));

    String contentDisposition = "attachment; filename=\"" +  originalFilename + "\"";

    // header에 CONTENT_DISPOSITION 설정을 통해 클릭 시 다운로드 진행
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
            .body(urlResource);

}
  • UrlResource를 사용해서 간단하게 구현할 수 있다. 응답 해더에 Disposition을 추가해두자 
    • 해당 헤더 설정 값이 있으면, 클릭시 다운로드 가능

4.3 파일 삭제

public void deleteImage(String originalFilename)  {
    amazonS3.deleteObject(bucket, originalFilename);
}

 

아래는 관련 공식문서 주소이다. (AWS SDK for java)

https://docs.aws.amazon.com/ko_kr/sdk-for-java/v1/developer-guide/examples-s3-objects.html

 

Amazon S3 객체에 대한 작업 수행 - AWS SDK for Java 1.x

copyObject와 deleteObject를 함께 사용하면 먼저 객체를 새 이름으로 복사한 다음(동일한 버킷을 소스와 대상으로 모두 사용 가능) 이전 위치에서 해당 객체를 삭제하는 방식으로 객체를 이동하거나

docs.aws.amazon.com

 

 

 

참고자료 

https://chb2005.tistory.com/200

 

[Spring Boot] AWS S3를 이용한 파일 업로드

AWS S3 란? AWS Simple Storage Service의 줄임말로 파일 서버의 역할을 하는 서비스 프로젝트 개발 중 파일을 저장하고 불러오는 작업이 필요한 경우에 프로젝트 내부 폴더에 저장할 수 있지만, AWS S3를

chb2005.tistory.com

https://velog.io/@galmegi/Spring-Amazon-S3-%EC%97%B0%EB%8F%99

 

Spring + Amazon S3 연동

Spring boot 프로젝트에서 Amazon S3연동 방법을 찾던 중 라이브러리에 여러 기능이 있어 정리해보았다.공식 문서 : docs 용어 : Amazon S3에서 객체(object)는 파일 또는 데이터의 집합을 의미한다. 모든 객

velog.io