웹 서비스에서 이미지, 첨부파일, 로그 파일 등을 저장해야 하는 경우가 많습니다. 이때 서버 로컬 디스크에 저장하면 용량 관리나 확장성이 떨어지므로, AWS S3(Simple Storage Service)를 활용하는 것을 추천합니다.
AWS S3란?
Amazon S3는 AWS에서 제공하는 객체 스토리지 서비스로, 대용량 데이터를 안정적으로 저장할 수 있습니다. 파일은 버킷(Bucket)이라는 단위에 저장되며, 각 파일은 고유한 키(Key)를 통해 접근합니다. S3는 기본적으로 높은 내구성(99.999999999%)과 가용성을 보장하며, 정적 파일 저장이나 CDN 연계에도 널리 사용됩니다.
1. AWS S3 버킷 생성
- AWS 콘솔 접속: S3 → Create bucket 클릭
- Bucket name: 예:
springboot-s3-demo - Region: 애플리케이션 서버와 동일한 리전 선택 (예: ap-northeast-2)
- Block Public Access: 필요에 따라 설정 (운영 환경에서는 기본 차단 권장)
- 버전 관리(Versioning): 중요 파일이면 활성화
생성 후 버킷 이름과 리전을 기록해 둡니다.
2. IAM 사용자 및 권한 설정
Spring Boot가 S3에 접근하기 위해서는 AWS IAM 사용자 권한이 필요합니다.
- IAM → Users → Add user 선택
- “Programmatic access” 체크 (Access key 생성)
- 정책 연결:
AmazonS3FullAccess또는 최소 권한 정책 생성
생성된 Access Key ID와 Secret Access Key를 안전하게 저장합니다.
3. Spring Boot 설정
Gradle 의존성 추가
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
Spring Cloud AWS Starter를 사용하면 AWS SDK를 쉽게 연동할 수 있습니다.
application.yml 설정
cloud:
aws:
credentials:
access-key: YOUR_ACCESS_KEY
secret-key: YOUR_SECRET_KEY
region:
static: ap-northeast-2
s3:
bucket: springboot-s3-demo
운영 환경에서는 Access Key 정보를 직접 입력하지 않고, IAM Role 또는 AWS Parameter Store를 사용하는 것이 권장됩니다.
4. S3 파일 업로드 로직 구현
S3Service 클래스 작성
@Service
@RequiredArgsConstructor
public class S3Service {
private final AmazonS3 amazonS3;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
public String uploadFile(MultipartFile file) {
String fileName = UUID.randomUUID() + "-" + file.getOriginalFilename();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(file.getSize());
metadata.setContentType(file.getContentType());
try (InputStream inputStream = file.getInputStream()) {
amazonS3.putObject(new PutObjectRequest(bucket, fileName, inputStream, metadata)
.withCannedAcl(CannedAccessControlList.PublicRead));
} catch (IOException e) {
throw new RuntimeException("파일 업로드 실패", e);
}
return amazonS3.getUrl(bucket, fileName).toString();
}
}
위 코드는 MultipartFile을 받아 S3 버킷에 업로드하고, 업로드된 파일의 URL을 반환합니다. CannedAccessControlList.PublicRead 옵션을 통해 업로드된 파일에 공개 접근을 허용할 수 있습니다.
5. Controller 작성
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/files")
public class FileController {
private final S3Service s3Service;
@PostMapping("/upload")
public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file) {
String url = s3Service.uploadFile(file);
return ResponseEntity.ok(url);
}
}
이제 POST /api/files/upload 엔드포인트에 파일을 전송하면 S3에 저장되고, 반환된 URL을 통해 접근할 수 있습니다.
6. S3에서 파일 삭제하기
public void deleteFile(String fileName) {
amazonS3.deleteObject(new DeleteObjectRequest(bucket, fileName));
}
파일 삭제 시에는 업로드할 때 사용한 fileName을 전달하면 됩니다. 실무에서는 파일명 충돌 방지를 위해 UUID를 prefix로 사용하는 것이 좋습니다.
7. 예제 실행 결과
- 요청:
POST /api/files/upload(multipart/form-data) - 응답:
https://springboot-s3-demo.s3.ap-northeast-2.amazonaws.com/8fa9f7b1-test.png - 브라우저에서 바로 접근 가능: 업로드된 이미지 또는 파일 확인
CloudFront를 함께 설정하면, 파일 접근 속도를 CDN으로 가속할 수 있습니다.
8. 운영 환경 보안 및 최적화
- IAM 최소 권한 정책:
s3:PutObject,s3:GetObject,s3:DeleteObject만 부여 - 파일 크기 제한: MultipartConfigElement로 업로드 제한 설정
- CloudFront CDN 연동: 정적 파일 캐싱 및 HTTPS 적용
- Presigned URL 사용: 민감 파일은 직접 업로드 대신 임시 접근 URL 발급 방식 사용
- 버킷 정책 관리: PublicRead 설정 시 외부 접근 제어 필수
Spring Boot와 AWS S3를 연동하면 파일 업로드, 다운로드, 삭제를 모두 클라우드에서 안전하게 처리할 수 있습니다. 특히 서버 로컬 저장소를 사용하지 않기 때문에 확장성과 안정성이 크게 향상됩니다.
'개발 > JAVA' 카테고리의 다른 글
| 대규모 트래픽을 위한 캐싱 전략 — 성능과 안정성을 동시에 잡는 방법 (0) | 2025.11.15 |
|---|---|
| Spring Boot와 Elasticsearch 연동하기 — 대용량 검색 서비스의 핵심 구현 (0) | 2025.11.14 |
| Spring Boot와 AWS RDS 연동하기 - 안정적인 클라우드 데이터베이스 환경 구축 (0) | 2025.11.12 |
| Spring Boot와 Jenkins CI/CD 파이프라인 구축 - 자동화된 배포 환경 만들기 (0) | 2025.11.11 |
| Spring Boot + Kubernetes 배포하기 - 컨테이너 오케스트레이션으로 확장성 확보 (0) | 2025.11.10 |
