Redirect AWS sdks' default endpoint to mocked

2019-06-24 14:19发布

问题:

I have multiple Java spring boot services (around 20 of them) using Amazon SDKs for S3, SQS, DynamoDB, etc..

Currently, to use Amazon Web Service I only need to specify my AWS key & secret.

ACCESS_AWS_KEY=<MY_KEY>
ACCESS_AWS_SECRET=<MY_SECRET>

However, I wanted to setup offline dev enviroment so I started to dockerize my services and set up a single multi-docker container with all my services dockerized and localstack should be used instead of remote AWS service to allow complete offline development.

docker-compose.yml looks something like this

version: '3'
services:
  service_1:
    build: ./repos/service_1
    links:
    - service_2:
    - localstack
  service_2:
    build: ./repos/service_2
    links:
    - localstack
  service_3:
    build: ./repos/service_3
    links:
    - localstack
  localstack:
    image: localstack/localstack

Amazon SDK provides AWS_REGION env variable, but not an endpoint environment variable which I can easily use in all services.

I also don't want to make code changes in my services to accommodate the new non-default endpoint.

I want a generic solution to forward requests like this:

dynamodb.eu-west-1.amazonaws.com => localstack_1:4569
s3-eu-west-1.amazonaws.com => localstack_1:4572

where localstack_1 is a linked docker container of localstack and reachable by other containers.

I came across extra_hosts: in docker-compose, but it only redirects to IPs and has no hostname resolving.

Also, notice that I have dozens of ports exposed in localstack from 4569 to 4582.

I thought about running a script on each machine setting up a vhost in some way, or forwarding all outgoing connections from all containers to a centralized request forwarder service, but have no clue where to start.

This will only used as a offline dev environment and will not receive any real traffic.

回答1:

Ok, I was able to finally find a solution for this. I had to actually go through localstack code base to be able to find the solution. Couple of quick things :

  • Localstack is not integrated with IAM. So it just simply ignores the secret key or password.
  • If you're using IAM, you now need to have a flag to override the endpoint. You can probably have a flag to indicate localstack mode.

Couple of classes which I found helpful if you're debugging issues :
https://github.com/atlassian/localstack/blob/master/localstack/ext/java/src/test/java/com/atlassian/localstack/SQSMessagingTest.java https://github.com/atlassian/localstack/blob/master/localstack/ext/java/src/test/java/com/atlassian/localstack/TestUtils.java

Now for the solution :

AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration("http://localhost:4576/", awsRegion.getName());
    AmazonSQSClient client =  (AmazonSQSClient) AmazonSQSClientBuilder.standard()
        .withCredentials(configuration.getSqsConfiguration().getCredentialsProvider())
        .withEndpointConfiguration(endpoint)
        .build();

Here http://localhost:4576/ is where localstacks runs SQS. Don't miss the trailing slash. For using this in camel route is same as using AWS resources. Hopefully this helps!