brew install awscli
aws --version
$ aws configure --profile default
AWS Access Key ID [None] : test-access-key
AWS Secret Access Key [None] : test-secret-key
Default region name [None] : ap-northeast-2
Default output format [None] : json
version: "3.8"
services:
localstack:
container_name: 'localstack'
image: localstack/localstack
ports:
- '4566:4566'
environment:
- SERVICES=s3,dynamodb,sns,sqs
- AWS_DEFAULT_REGION=ap-northeast-2
- HOSTNAME=localhost
- HOSTNAME_EXTERNAL=localhost
- LOCALSTACK_HOSTNAME=localhost
- EDGE_PORT=4566
- DEBUG=1
volumes:
- './init:/docker-entrypoint-initaws.d'
#!/bin/sh
# s3 버킷 만들기
echo "Init localstack ::: s3"
awslocal s3 mb s3://test-bucket
# dynamodb 테이블 만들기
echo "Init localstack ::: dynamodb"
awslocal dynamodb create-table \
--table-name user \
--attribute-definitions \
AttributeName=mallId,AttributeType=S \
AttributeName=userId,AttributeType=S \
--key-schema \
AttributeName=mallId,KeyType=HASH \
AttributeName=userId,KeyType=RANGE \
--provisioned-throughput \
ReadCapacityUnits=10,WriteCapacityUnits=5 \
--region ap-northeast-2
# sns 토픽 만들기
echo "Init localstack ::: sns ::: create topics"
lunasoft_topic_arn=$(awslocal sns create-topic --name lunasoft-topic --region ap-northeast-2 --output text)
echo "$lunasoft_topic_arn"
gng_topic_arn=$(awslocal sns create-topic --name gng-topic --region ap-northeast-2 --output text)
echo "$gng_topic_arn"
# sqs 큐 만들기
echo "Init localstack ::: sqs ::: create queues"
dean_queue_url=$(awslocal sqs create-queue --queue-name dean-queue --region ap-northeast-2 --output text)
dean_queue_arn=$(awslocal sqs get-queue-attributes --queue-url "$dean_queue_url" --attribute-names QueueArn --output text | awk '{print $2}')
echo "$dean_queue_arn"
brian_queue_url=$(awslocal sqs create-queue --queue-name brian-queue --region ap-northeast-2 --output text)
brian_queue_arn=$(awslocal sqs get-queue-attributes --queue-url "$brian_queue_url" --attribute-names QueueArn --output text | awk '{print $2}')
echo "$brian_queue_arn"
brandon_queue_url=$(awslocal sqs create-queue --queue-name brandon-queue --region ap-northeast-2 --output text)
brandon_queue_arn=$(awslocal sqs get-queue-attributes --queue-url "$brandon_queue_url" --attribute-names QueueArn --output text | awk '{print $2}')
echo "$brandon_queue_arn"
jacob_queue_url=$(awslocal sqs create-queue --queue-name jacob-queue --region ap-northeast-2 --output text)
jacob_queue_arn=$(awslocal sqs get-queue-attributes --queue-url "$jacob_queue_url" --attribute-names QueueArn --output text | awk '{print $2}')
echo "$jacob_queue_arn"
neo_queue_url=$(awslocal sqs create-queue --queue-name neo-queue --region ap-northeast-2 --output text)
neo_queue_arn=$(awslocal sqs get-queue-attributes --queue-url "$neo_queue_url" --attribute-names QueueArn --output text | awk '{print $2}')
echo "$neo_queue_arn"
harvey_queue_url=$(awslocal sqs create-queue --queue-name harvey-queue --region ap-northeast-2 --output text)
harvey_queue_arn=$(awslocal sqs get-queue-attributes --queue-url "$harvey_queue_url" --attribute-names QueueArn --output text | awk '{print $2}')
echo "$harvey_queue_arn"
# sns 구독 설정하기
echo "Init localstack ::: create subscriptions"
subscription1_arn=$(awslocal sns subscribe --topic-arn "$lunasoft_topic_arn" --protocol sqs --notification-endpoint "$dean_queue_arn" --output text)
echo "$subscription1_arn"
subscription2_arn=$(awslocal sns subscribe --topic-arn "$lunasoft_topic_arn" --protocol sqs --notification-endpoint "$brian_queue_arn" --output text)
echo "$subscription2_arn"
subscription3_arn=$(awslocal sns subscribe --topic-arn "$lunasoft_topic_arn" --protocol sqs --notification-endpoint "$brandon_queue_arn" --output text)
echo "$subscription3_arn"
subscription4_arn=$(awslocal sns subscribe --topic-arn "$gng_topic_arn" --protocol sqs --notification-endpoint "$jacob_queue_arn" --output text)
echo "$subscription4_arn"
subscription5_arn=$(awslocal sns subscribe --topic-arn "$gng_topic_arn" --protocol sqs --notification-endpoint "$neo_queue_arn" --output text)
echo "$subscription5_arn"
subscription6_arn=$(awslocal sns subscribe --topic-arn "$gng_topic_arn" --protocol sqs --notification-endpoint "$harvey_queue_arn" --output text)
echo "$subscription6_arn"
# sns 구독 속성 설정하기
echo "Init localstack ::: set subscription attributes"
awslocal sns set-subscription-attributes --subscription-arn $subscription1_arn --attribute-name RawMessageDelivery --attribute-value true
awslocal sns set-subscription-attributes --subscription-arn $subscription2_arn --attribute-name RawMessageDelivery --attribute-value true
awslocal sns set-subscription-attributes --subscription-arn $subscription3_arn --attribute-name RawMessageDelivery --attribute-value true
awslocal sns set-subscription-attributes --subscription-arn $subscription4_arn --attribute-name RawMessageDelivery --attribute-value true
awslocal sns set-subscription-attributes --subscription-arn $subscription5_arn --attribute-name RawMessageDelivery --attribute-value true
awslocal sns set-subscription-attributes --subscription-arn $subscription6_arn --attribute-name RawMessageDelivery --attribute-value true
정상 구동 확인
로컬에서 awscli로 정상 구동 확인하기
s3 버킷 리스트 확인
aws s3 ls --endpoint-url=http://localhost:4566
aws dynamodb list-tables --endpoint-url=http://localhost:4566 --region ap-northeast-2
aws sns list-topics --endpoint-url=http://localhost:4566 --region=ap-northeast-2
aws sqs list-queues --endpoint-url=http://localhost:4566 --region=ap-northeast-2
aws sns list-subscriptions --endpoint-url=http://localhost:4566 --region=ap-northeast-2
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LocalstackS3Test {
private static final String _ACCESS_KEY = "test-access-key";
private static final String _SECRET_KEY = "test-secret-key";
private static final String _ENDPOINT = "http://localhost:4566";
private static final String _REGION = "ap-northeast-2";
private static final String _S3_BUCKET_NAME = "test-bucket";
private static final String _LOCAL_FILE_PATH = "file";
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
String now = sdf.format(new Date());
File file = new File(_LOCAL_FILE_PATH + "/sample.txt");
String fileKey = now + "_" + file.getName();
// credentials
AWSCredentials credentials = new BasicAWSCredentials(_ACCESS_KEY, _SECRET_KEY);
AwsClientBuilder.EndpointConfiguration config = new AwsClientBuilder.EndpointConfiguration(_ENDPOINT, _REGION);
AmazonS3 amazonS3 = AmazonS3ClientBuilder.standard()
.withEndpointConfiguration(config)
.withPathStyleAccessEnabled(true)
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
// s3 업로드
uploadToAWS(amazonS3, file, fileKey);
// s3 다운로드
downloadToAWS(amazonS3, file.getAbsolutePath(), fileKey);
// s3 이름변경
renameToAWS(amazonS3, fileKey, "test-file-key.txt");
// s3 삭제
removeToAWS(amazonS3, fileKey);
}
public static void uploadToAWS(AmazonS3 amazonS3, File file, String fileKey) {
try {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("plain/text");
PutObjectRequest request = new PutObjectRequest(_S3_BUCKET_NAME, fileKey, file);
request.setMetadata(metadata);
request.withCannedAcl(CannedAccessControlList.AuthenticatedRead);
amazonS3.putObject(request);
System.out.println("upload success : " + fileKey);
} catch (SdkClientException e) {
System.out.println("upload fail : " + e.getMessage());
}
}
public static void downloadToAWS(AmazonS3 amazonS3, String filePath, String fileKey) {
try {
S3Object fullObject = amazonS3.getObject(_S3_BUCKET_NAME, fileKey);
InputStream in = fullObject.getObjectContent();
Files.copy(in, Paths.get(filePath + fileKey));
System.out.println("download success : " + fileKey);
} catch (AmazonS3Exception e) {
System.out.println("download fail : " + e.getMessage());
} catch (IOException e) {
System.out.println("file copy fail : " + e.getMessage());
}
}
public static void renameToAWS(AmazonS3 amazonS3, String sourceKey, String destinationKey) {
try {
amazonS3.copyObject(_S3_BUCKET_NAME, sourceKey, _S3_BUCKET_NAME, destinationKey);
amazonS3.deleteObject(_S3_BUCKET_NAME, sourceKey);
System.out.println("rename success : " + sourceKey + " to " + destinationKey);
} catch (SdkClientException e) {
System.out.println("rename fail : " + e.getMessage());
}
}
public static void removeToAWS(AmazonS3 amazonS3, String fileKey) {
try {
amazonS3.deleteObject(_S3_BUCKET_NAME, fileKey);
System.out.println("remove success : " + fileKey);
} catch (SdkClientException e) {
System.out.println("remove fail : " + e.getMessage());
}
}
}
aws s3 ls --endpoint-url=http://localhost:4566
aws s3 ls s3://test-bucket --endpoint-url=http://localhost:4566
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.QueryOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.DeleteItemRequest;
import com.amazonaws.services.dynamodbv2.model.DeleteItemResult;
import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
import com.amazonaws.services.dynamodbv2.model.GetItemResult;
import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
import com.amazonaws.services.dynamodbv2.model.PutItemResult;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class LocalstackDynamoDBTest {
private static final String _ACCESS_KEY = "test-access-key";
private static final String _SECRET_KEY = "test-secret-key";
private static final String _ENDPOINT = "http://localhost:4566";
private static final String _REGION = "ap-northeast-2";
private static final String _TABLE_NAME = "user";
private static final String _MALL_ID = "10";
private static final String _USER_ID = "test-user-id";
private static final String _CONTENT = "test contents";
public static void main(String[] args) {
// credentials
AWSCredentials credentials = new BasicAWSCredentials(_ACCESS_KEY, _SECRET_KEY);
AwsClientBuilder.EndpointConfiguration config = new AwsClientBuilder.EndpointConfiguration(_ENDPOINT, _REGION);
AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard()
.withEndpointConfiguration(config)
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
// table list 출력
getTableList(amazonDynamoDB);
// item 등록
putItem(amazonDynamoDB);
// item 조회 (key)
getItemByKey(amazonDynamoDB);
// item 조회 (query)
getItemByQuery(amazonDynamoDB);
// item 삭제
// removeItem(amazonDynamoDB);
}
public static void getTableList(AmazonDynamoDB amazonDynamoDB) {
List<String> tableNames = amazonDynamoDB.listTables().getTableNames();
System.out.println("========== TABLE LIST ==========");
for (String tableName : tableNames) {
System.out.println(tableName);
}
System.out.println("================================");
}
public static void putItem(AmazonDynamoDB amazonDynamoDB) {
Map<String, AttributeValue> item = new HashMap<>();
item.put("mallId", (new AttributeValue()).withS(_MALL_ID));
item.put("userId", (new AttributeValue()).withS(_USER_ID));
item.put("content", (new AttributeValue()).withS(_CONTENT));
item.put("deleted", (new AttributeValue()).withBOOL(false));
item.put("createdAt", (new AttributeValue()).withS("2023-02-06T02:21:30.536Z"));
PutItemRequest putItemRequest = (new PutItemRequest())
.withTableName(_TABLE_NAME)
.withItem(item);
PutItemResult putItemResult = amazonDynamoDB.putItem(putItemRequest);
if (200 == putItemResult.getSdkHttpMetadata().getHttpStatusCode()) {
System.out.println("[success] put item");
} else {
System.out.println("[fail] put item");
}
}
public static void getItemByKey(AmazonDynamoDB amazonDynamoDB) {
Map<String, AttributeValue> key = new HashMap<>();
key.put("mallId", (new AttributeValue()).withS(_MALL_ID));
key.put("userId", (new AttributeValue()).withS(_USER_ID));
GetItemRequest getItemRequest = (new GetItemRequest())
.withTableName(_TABLE_NAME)
.withKey(key);
GetItemResult getItemResult = amazonDynamoDB.getItem(getItemRequest);
Map<String, AttributeValue> result = getItemResult.getItem();
String mallId = result.get("mallId").getS();
String userId = result.get("userId").getS();
String content = result.get("content").getS();
boolean deleted = result.get("deleted").getBOOL();
String createdAt = result.get("createdAt").getS();
System.out.println("======== GET ITEM BY KEY ========");
System.out.println("mallId : " + mallId);
System.out.println("userId : " + userId);
System.out.println("content : " + content);
System.out.println("deleted : " + deleted);
System.out.println("createdAt : " + createdAt);
System.out.println("================================");
}
public static void getItemByQuery(AmazonDynamoDB amazonDynamoDB) {
DynamoDB dynamoDB = new DynamoDB(amazonDynamoDB);
Table user = dynamoDB.getTable(_TABLE_NAME);
QuerySpec spec = new QuerySpec()
.withKeyConditionExpression("mallId = :mallId and userId = :userId")
.withFilterExpression("content = :content")
.withValueMap(new ValueMap()
.withString(":mallId", _MALL_ID)
.withString(":userId", _USER_ID)
.withString(":content", _CONTENT))
.withConsistentRead(true);
ItemCollection<QueryOutcome> items = user.query(spec);
Iterator<Item> iterator = items.iterator();
Item item = null;
while (iterator.hasNext()) {
item = iterator.next();
long mallId = item.getLong("mallId");
String userId = item.getString("userId");
String content = item.getString("content");
boolean deleted = item.getBOOL("deleted");
String createdAt = item.getString("createdAt");
System.out.println("======= GET ITEM BY QUERY =======");
System.out.println("mallId : " + mallId);
System.out.println("userId : " + userId);
System.out.println("content : " + content);
System.out.println("deleted : " + deleted);
System.out.println("createdAt : " + createdAt);
System.out.println("================================");
}
}
public static void removeItem(AmazonDynamoDB amazonDynamoDB) {
Map<String, AttributeValue> key = new HashMap<>();
key.put("mallId", (new AttributeValue()).withS(_MALL_ID));
key.put("userId", (new AttributeValue()).withS(_USER_ID));
DeleteItemRequest deleteItemRequest = (new DeleteItemRequest())
.withTableName(_TABLE_NAME)
.withKey(key);
DeleteItemResult deleteItemResult = amazonDynamoDB.deleteItem(deleteItemRequest);
if (200 == deleteItemResult.getSdkHttpMetadata().getHttpStatusCode()) {
System.out.println("[success] delete item");
} else {
System.out.println("[fail] delete item");
}
}
}
aws dynamodb query \
--table-name user \
--key-condition-expression "mallId = :mallId and userId = :userId" \
--expression-attribute-values '{":mallId":{"S":"10"},":userId":{"S":"test-user-id"}}' \
--endpoint-url=http://localhost:4566 \
--region ap-northeast-2
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.sns.AmazonSNS;
import com.amazonaws.services.sns.AmazonSNSClientBuilder;
import com.amazonaws.services.sns.model.PublishRequest;
import com.amazonaws.services.sns.model.PublishResult;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LocalstackSnsTest {
private static final String _ACCESS_KEY = "test-access-key";
private static final String _SECRET_KEY = "test-secret-key";
private static final String _ENDPOINT = "http://localhost:4566";
private static final String _REGION = "ap-northeast-2";
private static final String _LUNA_TOPIC = "arn:aws:sns:ap-northeast-2:000000000000:lunasoft-topic";
private static final String _GNG_TOPIC = "arn:aws:sns:ap-northeast-2:000000000000:gng-topic";
public static void main(String[] args) {
// credentials
AWSCredentials credentials = new BasicAWSCredentials(_ACCESS_KEY, _SECRET_KEY);
AwsClientBuilder.EndpointConfiguration config = new AwsClientBuilder.EndpointConfiguration(_ENDPOINT, _REGION);
AmazonSNS amazonSNS = AmazonSNSClientBuilder.standard()
.withEndpointConfiguration(config)
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
// send message
sendMessage(amazonSNS, _LUNA_TOPIC);
sendMessage(amazonSNS, _GNG_TOPIC);
}
private static void sendMessage(AmazonSNS amazonSNS, String topicArn) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
String now = sdf.format(new Date());
String message = "SAMPLE:::" + now;
PublishResult publishResult = amazonSNS.publish(new PublishRequest()
.withTopicArn(topicArn)
.withMessage(message));
if (200 == publishResult.getSdkHttpMetadata().getHttpStatusCode()) {
System.out.println("[success] send message ::: " + topicArn);
} else {
System.out.println("[fail] send message ::: " + topicArn);
}
}
}
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.Message;
import java.util.List;
public class LocalstackSqsTest {
private static final String _ACCESS_KEY = "test-access-key";
private static final String _SECRET_KEY = "test-secret-key";
private static final String _ENDPOINT = "http://localhost:4566";
private static final String _REGION = "ap-northeast-2";
private static final String _DEAN_QUEUE = "http://localhost:4566/000000000000/dean-queue";
private static final String _BRIAN_QUEUE = "http://localhost:4566/000000000000/brian-queue";
private static final String _BRANDON_QUEUE = "http://localhost:4566/000000000000/brandon-queue";
private static final String _JACOB_QUEUE = "http://localhost:4566/000000000000/jacob-queue";
private static final String _NEO_QUEUE = "http://localhost:4566/000000000000/neo-queue";
private static final String _HARVEY_QUEUE = "http://localhost:4566/000000000000/harvey-queue";
public static void main(String[] args) {
// credentials
AWSCredentials credentials = new BasicAWSCredentials(_ACCESS_KEY, _SECRET_KEY);
AwsClientBuilder.EndpointConfiguration config = new AwsClientBuilder.EndpointConfiguration(_ENDPOINT, _REGION);
AmazonSQS amazonSQS = AmazonSQSClientBuilder.standard()
.withEndpointConfiguration(config)
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
// receive message
while (true) {
receiveMessage(amazonSQS, _DEAN_QUEUE);
receiveMessage(amazonSQS, _BRIAN_QUEUE);
receiveMessage(amazonSQS, _BRANDON_QUEUE);
receiveMessage(amazonSQS, _JACOB_QUEUE);
receiveMessage(amazonSQS, _NEO_QUEUE);
receiveMessage(amazonSQS, _HARVEY_QUEUE);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static void receiveMessage(AmazonSQS amazonSQS, String queueUrl) {
List<Message> messages = amazonSQS.receiveMessage(queueUrl).getMessages();
for (Message message : messages) {
System.out.println("url : " + queueUrl + ", id : " + message.getMessageId() + ", body : " + message.getBody());
amazonSQS.deleteMessage(queueUrl, message.getReceiptHandle());
}
}
}