티스토리 뷰
Gatsby로 블로그 마이그레이션을 하여 이 링크를 클릭하면 해당 포스팅으로 갑니다.
1. 들어가며
기업에서도 그렇고 이제 아마존 서비스를 쓰지 않은 곳이 없을 정도로 회사마다 아마존의 서비스를 많이 사용하고 있습니다. 최근에 이직을 한 곳에서도 S3 (Simple Storage Service) 스토리지 서비스를 이용하고 있어 S3 API를 학습할 겸 해서정리를 해봤습니다.
S3는 REST/HTTP 기반으로 파일을 저장하기 위한 스토리지이며 아래와 같은 특징을 가지고 있어 많은 곳에서 S3를 사용하고 있습니다.
- S3 서비스 특징
- 3 copy 복제를 지원하여 데이터 신뢰도(99.9999%)를 보장한다
- 용량과 파일 수에 대한 제한이 없다 (ex. 파일당 1B ~ 5TB)
- 버전 관리 기능을 제공하여 실수로 삭제한 파일도 복원 가능하다
- 다른 아마존 서비스(ex. CloudFount, Glacier)에 쉽게 연동이 가능하다
- 용어 정리
- 객체 : S3에서 저장되는 기본 단위로 하나의 파일이라고 생각하면 된다
- 키 : 버킷 내 객체를 저장하기 위해 사용되는 고유한 식별자이다
- ex. test.xls, thumbs/main.jpg
- 버킷 : 디렉토리와 비슷한 개념으로 버킷에 객체를 저장한다
- 하위 버킷 또는 하위 폴더의 계층 구조는 없지만, 키 이름 접두사와 구분 기호를 이용하여 논리적인 계층 구조를 만들 수 있다 (ex. develop/test.xls)
2. 개발 환경 및 S3 기본 설정
소스 코드는 대부분은 Amazon SDK와 Baeldung에 있는 예제들을 보면서 작성하였습니다.
- OS : Mac OS
- IDE: Intellij
- Java : JDK 1.8
- Source code : github
- Software management tool : Maven
pom.xml 파일에 아마존 SDK 의존성을 추가해줍니다.
<dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> <version>1.11.154</version> </dependency>
2.1 S3 기본 설정
AWS SDK를 사용하려면, 아래 3가지는 완료해야 코드상에서 S3에 접속하여 작업을 할 수 있습니다.
- AWS 계정 생성
- 계정이 없는 경우 AWS 계정을 생성한다
- AWS 보안 자격 증명 (코딩시 이게 필요하다)
- S3에 접속하려면, 액세스 키 ID와 보안 액세스 키가 필요하다
- 코드에서 사용할 보안 자격 증명 사이트에 접속하여 아래와 같이 얻어온다
- AWS 지역 선택하기
- 지역마다 S3 가격이 다르기 때문에 가장 가까운 지역을 선택하는것이 좋다
3. S3 Bucket에서 파일 다루기
3.1 Client Connection
S3 서비스에 접근하기 위한 client connection을 생성해야 합니다. 위에서 생성한 KEY_ID와 SECRET_ACCESS_KEY가 필요합니다.
3.1.1 명시적으로 지정하는 방법
소스코드 안에서 KEY_ID와 SECRET_ACCESS_KEY를 인자로 전달하여 BasicAWSCredentials 객체를 생성하여 client 연결을 얻어오는 방법이 있습니다.
AmazonS3ClientBuilder .standard() .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials( KEY_ID, SECRET_ACCESS_KEY) )) .withRegion(Regions.AP_NORTHEAST_2) .build();
public class S3App { private static final AWSCredentials credentials; private static final String KEY_ID = "<key_id>";
private static final String SECRET_ACCESS_KEY = "<secret_access_key>"; private static AmazonS3 s3client; static { credentials = new BasicAWSCredentials( KEY_ID, SECRET_ACCESS_KEY ); } public static void main(String[] args) throws IOException, URISyntaxException { s3client = createConnectionWithCredentials(credentials); }
} private static AmazonS3 createConnectionWithCredentials(AWSCredentials credentials) { return AmazonS3ClientBuilder .standard() .withCredentials(new AWSStaticCredentialsProvider(credentials)) //#1 - 직접 값을 전달함 .withRegion(Regions.AP_NORTHEAST_2) .build(); }
KEY가 외부로 노출이 되면 누구나 아마존 서비스를 사용할 수 있으므로 잘 못 하면 다른 사람들에 의해서 요금 폭탄을 맞을 수 있습니다.
3.1.2 환경 설정으로 지정하는 방법
Client connection을 가져오는 두 번째 방법입니다. 환경설정 파일에 저장된 key 값을 가져오는 방식입니다.
private static AmazonS3 createConnectionWithCredentials() {
return AmazonS3ClientBuilder
.standard()
.withCredentials(new DefaultAWSCredentialsProviderChain()) //#1 - env 환경변수나 ~/.aws에 저장된 값을 읽어드림
.withRegion(Regions.AP_NORTHEAST_2)
.build();
}
아래와 같이 AWS 자격 증명 설정이 되어 있어야 합니다.
># vim ~/.aws/credentials [default] aws_access_key_id=EXAMPLEACCESS_KEY aws_secret_access_key=FSDFSGSDFaZiNOzYxcfQXiKq6jwiLYB6 ># vim ~/.aws/config [default] region=ap-northeast-2
3.2 S3 Bucket에서 파일 다루기
3.2.1 S3 bucket 생성하기
먼저 버킷을 생성해보겠습니다. 간단합니다. createBucket() 메서드를 사용하면 됩니다.
@Test public void test_버킷_생성하기() { String[] bucketList = new String[] { BUCKET_NAME, BUCKET_NAME2 }; for (String bucketName : bucketList) { if (s3client.doesBucketExist(bucketName)) { s3client.deleteBucket(bucketName); } s3client.createBucket(bucketName); //#1 - 버킷 생성 assertTrue(s3client.doesBucketExist(bucketName)); } }
위 유닛테스트에서 버킷이 생성되었는지 확인해보겠습니다.
@Test public void test_buckets_목록_프린트하기() { List<Bucket> buckets = s3client.listBuckets(); for (Bucket b : buckets) { System.out.println("* " + b.getName()); } }
3.2.2 파일 업로드
버킷에 파일을 올리려면 pubObject()를 사용합니다. 인터넷에서 이미지 다운로드해서 S3에 올리는 예제입니다.
@Test public void test_bucket에_파일_올리기() throws IOException { String webImageUrl = "https://images-na.ssl-images-amazon.com/images/I/51ADJwz5bwL._SY355_.png"; String filename = "/Users/ykoh/Desktop/test.png"; downloadFileFromURL(webImageUrl, filename); String bucketKey = "image/test.png"; s3client.putObject(BUCKET_NAME, bucketKey, new File(filename)); //#1 - 파일을 올리는 메서드임 } private void downloadFileFromURL(String sourceUrl, String destPath) throws IOException { FileUtils.copyURLToFile(new URL(sourceUrl), new File(destPath)); }
3.2.3 파일 다운로드
버킷에 올린 파일을 컴퓨터로 다운로드할 수 있습니다. getObject() 메서드로 원하는 파일을 저장합니다.
@Test public void test_bucket에서_파일_다운로드하기() throws IOException { String destFilename = "/Users/ykoh/Desktop/test.png"; S3Object s3object = s3client.getObject(BUCKET_NAME, "image/test.png”); //#1 - 파일을 다운로드함 S3ObjectInputStream inputStream = s3object.getObjectContent(); FileUtils.copyInputStreamToFile(inputStream, new File(destFilename)); //#2 - 스트림을 파일로 저장함 }
3.2.4 파일 삭제
버킷에서 하나의 파일을 삭제할 때는 deleteObject() 메서드를사용하고 여러 파일을 한 번에 삭제하려면 deleteObjects() 메서드를 사용합니다.
@Test public void test_bucket에서_파일_삭제하기() throws IOException { String webImageUrl = "https://images-na.ssl-images-amazon.com/images/I/51ADJwz5bwL._SY355_.png"; downloadFileFromURL(webImageUrl, "image/test1.png"); downloadFileFromURL(webImageUrl, "image/test2.png"); downloadFileFromURL(webImageUrl, "image/test3.png"); //delete single file s3client.putObject(BUCKET_NAME, "image/test1.png", new File("/Users/ykoh/Desktop/test.png")); s3client.deleteObject(BUCKET_NAME, "image/test1.png”); //#1 - 파일 하나 삭제 //delete multiple files String objkeyArr[] = { "image/test2.png", "image/test3.png" }; DeleteObjectsRequest delObjReq = new DeleteObjectsRequest(BUCKET_NAME).withKeys(objkeyArr); s3client.deleteObjects(delObjReq); //#2 - 여러 파일 삭제 }
3.2.5 버킷 삭제
버킷을 삭제하려면 버킷 안에 있는 모든 파일과 버전 관리가 되는 객체들도 다 삭제해야만 버킷을 삭제할 수 있습니다.
@Test public void test_bucket_삭제하기() { deleteAllObjectsAndBucket(s3client, BUCKET_NAME); } private static void deleteAllObjectsAndBucket(AmazonS3 s3client, final String bucketName) { try { ObjectListing objectListing = s3client.listObjects(bucketName); //#1 - 버킷안에 있는 모든 객체 while (true) { Iterator<S3ObjectSummary> objIter = objectListing.getObjectSummaries().iterator(); while (objIter.hasNext()) { s3client.deleteObject(bucketName, objIter.next().getKey()); //#2 - 하나씩 삭제함 } if (objectListing.isTruncated()) { objectListing = s3client.listNextBatchOfObjects(objectListing); } else { break; } } VersionListing versionList = s3client.listVersions(new ListVersionsRequest().withBucketName(bucketName)); //#3 - 버전관리되는 객체 리스트 while (true) { Iterator<S3VersionSummary> versionIter = versionList.getVersionSummaries().iterator(); while (versionIter.hasNext()) { S3VersionSummary vs = versionIter.next(); s3client.deleteVersion(bucketName, vs.getKey(), vs.getVersionId()); //#4 - 버전관리되는 객체도 삭제함 } if (versionList.isTruncated()) { versionList = s3client.listNextBatchOfVersions(versionList); } else { break; } } s3client.deleteBucket(bucketName); //#5 - 버킷 삭제 } catch (AmazonServiceException e) { e.printStackTrace(); } catch (SdkClientException e) { e.printStackTrace(); } }
4. 참고
- Amazon S3
- S3 Credentials 설정 방법
'java' 카테고리의 다른 글
Q&A : Java 관련 질문 모음 (0) | 2019.03.21 |
---|---|
JUnit Rules이란 (0) | 2019.02.12 |
자바 keystore에 SSL 인증서 import 하기 (0) | 2019.01.09 |
Java Jayway JsonPath 사용법 (0) | 2019.01.09 |