Microservices-based architecture helps reduce the complexity of application components, while posing a new class of problems related to the connectivity between microservices. Keeping track of all your application components, whether custom-built or managed AWS services, across multiple stages and deployments is a challenging task. AWS Cloud Map is a fully-managed service discovery tool for all the cloud resources and application components that help your applications connect to the correct endpoints, making your deployments safer and reducing the complexity of the infrastructure code. In this guest post from Ewan Valentine, Technical Architect at Peak.ai, we look at an open source library that allows you to seamlessly integrate AWS Cloud Map service discovery into your serverless application, making the transition to microservice-based architecture at scale smoother.

Alexandr Moroz

 

At Peak.ai, we embarked on our journey to a microservices-based, serverless architecture almost a year ago. One of the key problems we faced was choosing the correct tool for service discovery. We had begun our journey before AWS Cloud Map was announced, but there were lots of tools we could have used: Consul, etcd, ZooKeeper, etc. – all of which have considerable overhead in setup and ongoing maintenance.

As a small team (of five) responsible for this task, we opted to go for a managed solution. Luckily for us, AWS announced AWS Cloud Map, which was exactly what we needed. The setup was simple and straightforward, and we were able to very quickly create a rich set of tools on top of AWS Cloud Map tooling so that we can register and interact with services throughout our ecosystem, tightly coupling services to each other without having to hard-code or pass around ARNs. We have now open sourced these tools so that other AWS Cloud Map customers can benefit.

AWS Cloud Map features

This is not an exhaustive list, but these are the AWS Cloud Map features most critical to us:

Service support

AWS Cloud Map supports many of the main AWS services out of the box: you can create DNS-discoverable references to SQS, DynamoDB tables, S3 buckets, and much more.

DNS, API, or both

AWS Cloud Map supports creating DNS-friendly urls for your services, tables, or buckets, but you can also use the API discovery type, allowing you to use the AWS SDK to discover instances by metadata. This is really useful for services which don’t necessarily need to be reached via a URL. For example, if you have lots of Lambda microservices communicating via direct calls or maybe an SQS queue, you can simply discover the ARN for each, and use the AWS SDK to call your discovered service. We also have written a wrapper to abstract this calling behavior around the AWS SDK, based on the type of call being made – we’ll dig into that later in this post. You can also create namespaces, which allow you to discover using both http and the API.

Serverless by nature

Often with service discovery, you’ll find yourself having to maintain and run instances of a service discovery software, such as etcd or consul on EC2 instances. You have to worry about scale, security, physical resources, etc. With AWS Cloud Map, all of that is managed for you, so you can focus on writing your business logic.

Ease of use

AWS Cloud Map is incredibly easy to get started with and use. For example, you can call discoverInstances({ NamespaceName, ServiceName: QueryParameters }) which returns a list of registered instances for your services, such as lambda functions.

Health checks

AWS Cloud Map supports checking for a service’s health, which means you can write more resilient systems which check that the service you are trying to call is healthy and accessible. Which means you can write contingencies such as exponential back-off, and catch failures safely.

Safer upgrades

Because AWS Cloud Map acts as a directory or facade to other services, you can safely switch out services by updating the Cloud Map service/instance for that service. This means, for example, that you can deploy, upgrade and maintain your services without having to update references to them elsewhere.

Pricing

In the serverless approach, you pay for what you use: $1 for each million requests. The API registry is free, then it’s $0.10 per resource registered with DNS. This means AWS Cloud Map has been far more economical for us than running our own.

Our applications use case

To integrate AWS Cloud Map into our projects, we wrote a thin wrapper on top of the AWS Cloud Map SDK, which made service discovery a joy to work with:

const job = await Discovery.request(‘ais.scheduler->get-job’, {
  id,
  type,
});

// Trigger a lambda via SNS
await Discovery.publish(‘ais.my-event’, event);

// Queue a message in SQS
await Discover.queue(‘ais.my-queue’, message);

// Listen on an SQS queue
const eventEmitter = await Discover.listen(‘ais.my-queue’);

AWS Cloud Map supports service discovery at both the application and DNS level, so you can create friendly URLs for your services, which is incredibly useful for containerised applications, or applications which would typically require a load balancer to be resolved by other services.

Registering your services

When creating our AWS CloudFormation templates, we simply register our service’s ARNs against a user-friendly name, for example:

CloudMapService:
    Type: 'AWS::ServiceDiscovery::Service'
    Properties:
      Description: discover handlers for scheduler
      Name: scheduler-service
      NamespaceId: !FindInMap [ CloudMapMappings, !Ref Stage, CloudMapNamespaceID ]

  SchedulerQueueInstance:
    Type: 'AWS::ServiceDiscovery::Instance'
    Properties:
      InstanceAttributes:
        arn: !Join [ '-', [ 'ais', !Ref Stage, scheduler.fifo' ] ]
        type: queue
        url: !Ref SchedulerQueue
      InstanceId: scheduler-queue
      ServiceId: !Ref CloudMapService

Then in our code, anywhere within our platform, we can reference that queue, using our library:

await ServiceDiscovery.queue(‘namespace-prod.scheduler-service->scheduler-queue’, message);

We have created a standard format consisting of three parts:

<namespace>.<service>-><instance>

Serverless integration

At Peak, we use the serverless framework very heavily, so we wanted to look into ways of integrating AWS Cloud Map into the serverless framework workflow. We also created a serverless plugin for AWS Cloud Map and a serverless component which have now been added to the official Serverless plugins repository, so you can register and integrate your serverless microservices into AWS Cloud Map directly using the serverless framework.

Conclusion

AWS Cloud Map has enabled our journey to a microservices platform by acting as the glue that binds all of our business logic at scale. AWS Cloud Map has enabled us to move more quickly when rolling out new functionality, and even when replacing old functionality. The simplicity of AWS Cloud Map meant that it was quick to implement and easy to pick up and adopt.

We’d love you to get involved and try out our AWS Cloud Map-based libraries:

We’re open to ideas and suggestions and we’d love to see folks try it out!

Ewan Valentine.

Ewan Valentine

Ewan Valentine is a technical architect at Peak.ai and resident Gopher, focussing on microservices and AI solutions. Previously of BBC, LAD Bible, and Boots Walgreens.

The content and opinions in this post are those of the third-party author and AWS is not responsible for the content or accuracy of this post.

from AWS Open Source Blog