๐Ÿชฃ S3 โ€“ ์ƒ์„ฑ๋ถ€ํ„ฐ Spring์—์„œ ํ™œ์šฉ๊นŒ์ง€

๊น€๊ณต์˜ยท2024๋…„ 6์›” 2์ผ

how-to

๋ชฉ๋ก ๋ณด๊ธฐ
4/12
post-thumbnail

๐Ÿค” AWS S3 Outline

S3๋ž€?

Simple Storage Service์˜ ์•ฝ์ž๋กœ, ์ฃผ๋กœ ํŒŒ์ผ ์„œ๋ฒ„๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

S3๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

1. ํ™•์žฅ์„ฑ(Scalability)

ํŒŒ์ผ ์„œ๋ฒ„๋Š” ํŠธ๋ž˜ํ”ฝ ์ฆ๊ฐ€์— ๋”ฐ๋ผ ์„œ๋ฒ„ ์ธํ”„๋ผ ๋ฐ ์šฉ๋Ÿ‰ ๊ณ„ํš์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ S3๋Š” ํ™•์žฅ ๋ฐ ์„ฑ๋Šฅ ๋ถ€๋ถ„์„ ๋Œ€์‹  ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

2. ๋‚ด๊ตฌ์„ฑ(Durability)

S3๋Š” ์—ฌ๋Ÿฌ ์˜์—ญ์—์„œ ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ๋ณธ์„ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ์˜์—ญ์ด ๋‹ค์šด๋˜๋”๋ผ๋„ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ ๋ฐ ๋ณต๊ตฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

S3 terminology

  • ๊ฐ์ฒด(object)
    • ํŒŒ์ผ๊ณผ ํŒŒ์ผ ์ •๋ณด๋กœ ๊ตฌ์„ฑ๋œ ์ €์žฅ ๋‹จ์œ„
    • ์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์ €์žฅํ•˜๋Š” ํŒŒ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
  • ๋ฒ„ํ‚ท(bucket)
    • ๋‹ค์ˆ˜์˜ ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ
    • ํŒŒ์ผ ์‹œ์Šคํ…œ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

๐Ÿ› ๏ธ S3 bucket ์ƒ์„ฑ ๋ฐฉ๋ฒ•

bucket ์ƒ์„ฑ

  1. AWS console > S3 > ๋ฒ„ํ‚ท > ๋ฒ„ํ‚ท ๋งŒ๋“ค๊ธฐ
  2. bucket ์ด๋ฆ„ ์ž…๋ ฅ ํ›„ ์—‘์„ธ์Šค ์ฐจ๋‹จ ์„ค์ •์„ ํ•ด์ œํ•œ๋‹ค.

IAM ์‚ฌ์šฉ์ž ์ƒ์„ฑ

S3์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” IAM ์‚ฌ์šฉ์ž์—๊ฒŒ S3 ์ ‘๊ทผ ๊ถŒํ•œ์„ ์ฃผ๊ณ , ์—‘์„ธ์Šค ํ‚ค๋ฅผ ๋งŒ๋“ค์–ด ์—‘์„ธ์Šค ํ‚ค์™€ ๋น„๋ฐ€ ํ‚ค๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฏธ IAM ์‚ฌ์šฉ์ž๋กœ ๋กœ๊ทธ์ธํ•ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์„ ์ƒ๋žต ํ›„ ๋ฐ”๋กœ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.

  1. AWS console > IAM > ์•ก์„ธ์Šค ๊ด€๋ฆฌ > ์‚ฌ์šฉ์ž > ์‚ฌ์šฉ์ž ์ถ”๊ฐ€
  2. ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ ์ž…๋ ฅํ•œ๋‹ค.
  3. ์ง์ ‘ ์ •์ฑ… ์—ฐ๊ฒฐ์„ ์„ ํƒํ•˜๊ณ , AmazonS3FullAccess๋ฅผ ์„ ํƒํ•œ๋‹ค.
  4. ์‚ฌ์šฉ์ž ์ƒ์„ฑ์„ ์„ ํƒํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์•ก์„ธ์Šค ํ‚ค ์ƒ์„ฑ

์™ธ๋ถ€ ์„œ๋ฒ„์—์„œ ์ ‘์†ํ•  ์ˆ˜ ์žˆ๋„๋ก IAM ์‚ฌ์šฉ์ž์˜ ์—‘์„ธ์Šค ํ‚ค๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ์ด๋•Œ ์—‘์„ธ์Šค ํ‚ค์™€ ๋น„๋ฐ€ ํ‚ค๋Š” ์™ธ๋ถ€์— ๊ณต๊ฐœ๋˜์–ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

  1. AWS console > IAM > ์•ก์„ธ์Šค ๊ด€๋ฆฌ์ž > ์‚ฌ์šฉ์ž > ์ƒ์„ฑํ•œ ์‚ฌ์šฉ์ž ์ด๋ฆ„ ์„ ํƒ > ๋ณด์•ˆ ์ž๊ฒฉ ์ฆ๋ช… > ์•ก์„ธ์Šค ํ‚ค ๋งŒ๋“ค๊ธฐ
  2. ์•„๋ฌด๊ฑฐ๋‚˜ ์„ ํƒํ•˜๊ณ  ๋‹ค์Œ์„ ์„ ํƒํ•œ๋‹ค. (์•ก์„ธ์Šค ํ‚ค ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ๋Œ€์•ˆ์„ ํ•˜๋‹จ์— ๋„์›Œ์ฃผ๋Š” ๊ธฐ๋Šฅ๋งŒ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌด์—‡์„ ๊ณจ๋ผ๋„ ๋ฌด๊ด€ํ•˜๋‹ค.)
  3. ํƒœ๊ทธ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์•ก์„ธ์Šค ํ‚ค ๋งŒ๋“ค๊ธฐ๋ฅผ ์„ ํƒํ•œ๋‹ค.
  4. ์•ก์„ธ์Šค ํ‚ค ์ƒ์„ฑ ์™„๋ฃŒ ํ™”๋ฉด์—์„œ ์ƒ์„ฑ๋œ ๊ณต๊ฐœํ‚ค์™€ ๋น„๋ฐ€ํ‚ค๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ƒ์„ฑ ์™„๋ฃŒ ํ™”๋ฉด์ด ์•„๋‹ˆ๋ฉด ๋น„๋ฐ€ํ‚ค๋ฅผ ๋ณผ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ˜๋“œ์‹œ .csv ํŒŒ์ผ๋กœ ๋ฐ›์•„๋†“์„ ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

๐Ÿงญ ์˜์กด์„ฑ ์„ค์ •

Gradle

dependencies {
	...
	implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
	...
}

application.yml

cloud:
	aws:
		s3:
			bucket: <S3 bucket name>
		stack:
			auto: false
		region:
			static: ap-northeast-2
			auto: false
		credentials:
			accessKey: <๋ฐœ๊ธ‰๋ฐ›์€ accessKey>
			secretKey: <๋ฐœ๊ธ‰๋ฐ›์€ secretKey>

S3Config.java

@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() {
        BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);

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

๐Ÿš€ How to use

File upload

@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();
    }
}

File download

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);

}

File deletion

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

Reference : [Spring Boot] AWS S3๋ฅผ ์ด์šฉํ•œ ํŒŒ์ผ ์—…๋กœ๋“œ, AWS S3 ๊ณต์‹ ๋ฌธ์„œ

profile
๋‚˜๋Š”์•ผ ๋งํ•˜๋Š” ๊ฐœ๋ฐœ(๊ฐ)์ž

0๊ฐœ์˜ ๋Œ“๊ธ€