Extend your service mesh to support AWS Lambda
While managing a service mesh with Consul, you may need to exchange the source of a service for another source. For example, a service mesh hosted on a Kubernetes cluster could include a service that experiences heavy amounts of traffic which exceeds the provisioned capacity of the cluster. Autoscaling a cluster is a common method to manage peak capacity, but autoscaling takes time to provision new instances within a cluster to meet the needs of the service. Serverless computing solutions like AWS Lambda can quickly scale to the capacity a service requires, without the time investment of waiting for instances to provision. During instances of peak demand, this can help you or your organization manage workloads in a sustainable predictable manner.
With Consul on AWS Lambda, you can take advantage of the benefits of serverless workloads. These benefits include reducing cost, decreasing administrative overhead, and scaling services inside a Consul service mesh with minimal context switching.
In this tutorial, you will deploy HashiCups, a demo application, onto an Amazon Elastic Kubernetes Services (EKS). Then, you will learn how to route traffic away from a Kubernetes service and towards a Lambda function, using Consul's service splitter and terminating gateway.
Prerequisites
The tutorial assumes an intermediate understanding of Consul, AWS, and Kubernetes. If you're new to Consul, refer to the Getting Started tutorials collection.
For this tutorial, you will need:
An HCP account configured for use with Terraform
An AWS account configured for use with Terraform
A cleanup script is provided to help minimize the time resources are actively accruing charges to your AWS account.
Note
Some infrastructure in this tutorial does not qualify for AWS free tier.
Clone example repository
Clone the GitHub repository containing the configuration files and resources.
Navigate into the repository folder.
Fetch the latest tags and check out the v0.9
tag of the repository.
Navigate into the project's terraform folder for this tutorial.
Deploy tutorial infrastructure
This tutorial deploys an HCP Consul Dedicated cluster, an Amazon EKS cluster with Consul installed via Helm and supporting infrastructure. The Consul cluster on EKS is pre-configured with support for AWS Lambda, and includes a terminating gateway you will configure later in this tutorial.
Initialize the Terraform project.
Then, deploy the resources. Confirm by entering yes
.
Once complete, Terraform will display a list of outputs that you will use to connect to your HCP Consul Dedicated and Kubernetes clusters.
Configure your terminal to connect to HCP Consul Dedicated and Kubernetes
Update your local kubeconfig
file by using the Terraform output eks_update_kubeconfig_command
. Then, verify that you
can connect to your EKS cluster with kubectl cluster-info
.
Set the environment variables required by kubectl
and the AWS CLI.
Set your HCP Consul Dedicated environment variables. You will use these to configure your Consul CLI to interact with your HCP Consul cluster.
Verify tutorial infrastructure
Copy and paste the Consul public URL (consul_public_endpoint
) into your browser to visit the Consul UI. Since HCP
Consul is secure by default, copy and paste the ACL token (hcp_login_token
) into the Consul authentication prompt to
use the Consul UI.
Once you have authenticated, click the Services tab on the left navigation pane to review your deployed services.
Verify HashiCups deployment
Retrieve the URL of the Consul API Gateway. Input this URL into your browser to confirm HashiCups is working.
Verify payment service routing to Kubernetes
Verify HashiCups is routing payments traffic to the Kubernetes pod. Later, you will compare this output to the payments service routing to the Lambda function.
Create a port-forward, sending local requests to port 8080
to the public-api
.
In another terminal, simulate a payment by sending the following request with curl
to the HashiCups public-api
endpoint.
The following message indicates a successful response to your request. The Kubernetes-based payments
service is
returning unencrypted data as noted by the card_ciphertext
return value.
Create AWS Lambda function registrator
Since Lambda functions do not include a Consul agent, you must register Lambda functions to the Consul service mesh
using the Consul API. You can do this using the consul-lambda-registrator
Terraform module, or manually through the Consul API. In this tutorial, you will use consul-lambda-registrator
to automatically register Lambda functions in Consul service mesh.
The Terraform module deploys a registrator Lambda function. The registrator function checks for Lambda functions with
specific Consul annotations in your account, in the deployed region, on an interval, defined by the Lambda function's
tags block in the aws_lambda
resource. When discovered, the registrator functions registers the Lambda function as a
service in Consul service mesh.
The registrator module also deploys a private Elastic Container Registry repository to store the registrator's container image in your AWS account.
Begin by adding the Lambda function registrator code to the lambda-tutorial.tf
Terraform file. Note the highlighted
lines below for the sync frequency and the ECR repository.
Use terraform get
in the project folder to download the consul-lambda-registrator
module.
Create the registrator. Confirm by entering yes
.
Deploy AWS Lambda function for HashiCups payments
Next, you will deploy the Lambda function payments workload and supporting infrastructure. This includes an IAM Role
and Policy to write logs to CloudWatch, allowing you to confirm success in using this tutorial. The diagram below
reflects the flow of how the payments
service routes to AWS Lambda via the terminating gateway.
The Lambda function resource includes a block of tags
. You must include these annotations for the registrator to
register your Lambda function to the Consul service mesh.
Add the following block of Terraform code to lambda-tutorial.tf
to deploy the Lambda function. The Lambda function will replace the payments service and pods in Kubernetes.
Create the Lambda function. Confirm by entering yes
.
When Terraform finishes creating the function, wait one minute for the registrator to sync and register the new Lambda
function. Use the following aws logs
command to verify the registrator found and registered the payments Lambda
function.
Tip
Customize the sync period by configuring the sync_frequency_in_minutes
value of the registrator module.
Next, navigate into the Consul UI's Services section, to verify the Lambda function is registered in Consul service
mesh. You should find a service starting with payments-lambda-
in the dashboard.
Migrate Consul payments service to Lambda function
The Lambda function is present in the service mesh, but is not receiving traffic. As the Lambda function is considered an external workload by Consul, the Consul terminating gateway will serve as the proxy for this Lambda function.
Configure ACL for terminating gateway
The terminating gateway needs permission the via an ACL policy to interact with the Lambda function in Consul.
Retrieve the terminating gateway's ACL token, saving the AccessorID
as an environment variable named TGW_TOKEN
.
Next, open practitioner/terminating-gateway-policy.hcl
. This is a pre-rendered policy file for the ACL token, that
grants read (intentions) and write (policy) access to the payment service and payments Lambda service. Your policy file
should look similar to the following code block.
Create an ACL policy with the pre-rendered policy file.
Associate this policy with the saved ACL token for the terminating gateway, merging this policy to existing roles and policies associated to this token.
Link Lambda payments service to terminating gateway
Associate the Lambda function service to the Consul terminating gateway. The terminating gateway routes requests for the
payments service, to the AWS Lambda function. Open ./practitioner/terminating-gateway.yaml
to find the pre-rendered
service terminating gateway definition.
Review the following YAML example to observe the association of the payments Lambda function to the terminating gateway.
Apply the pre-rendered terminating gateway configuration file to the Kubernetes cluster.
In the Consul UI, the Terminating Gateway now includes the payments-lambda
service as a linked service to the gateway:
Route traffic to payments Lambda function with service splitter
Since this tutorial uses Consul with ACLs enabled, the public-api
service requires a service intention to route requests to the underlying Lambda function. Open ./practitioner/service-intentions.yaml
to find the pre-rendered service intentions definition.
Apply the pre-rendered service intention definition file.
Route traffic to the payments-lambda
function with the ServiceSplitter
resource. In this tutorial, you will route 100% of the traffic for the payment
service to the payments-lambda
function. Open ./practitioner/service-intentions.yaml
to find the pre-rendered ServiceSplitter
definition.
Apply the pre-rendered ServiceSplitter
policy.
Verify payment service routing to Lambda
Verify HashiCups is routing payments
traffic to the Lambda function by simulating a payment.
Create a port-forward that sends local requests to port 8080
to the public-api
.
In a different terminal, simulate a payment by sending the following request with curl
to the HashiCups public-api
endpoint.
The following payload indicates a successful response to your request. Note the value of card_ciphertext
returning
Encryption Enabled
. In context of this tutorial, this value confirms the payments
service routed to AWS Lambda, as the
terminating gateway returns send and returns encrypted traffic.
Note
If you receive a No Such Host
error in a new terminal window, reload your kubeconfig
file in this
terminal with the AWS CLI. You can retrieve this command for your specific cluster by using terraform output
.
To verify the AWS Lambda function responded to this request, search for the value of the name
key from the request
payload in the Cloudwatch logs. You should find HELLO_LAMBDA_FUNCTION
in the returned data.
Clean up
To remove all resources, use terraform destroy
twice. Use the following command to have terraform destroy
immediately begin after the first command finishes running.
Note
Due to race conditions with the various cloud resources created in this tutorial, it is necessary to use the destroy command twice to ensure all resources have been properly removed.
Next Steps
In this tutorial, you migrated a Consul service from Kubernetes to an AWS Lambda function. First, you deployed the Terraform Lambda function registrator for Consul, which listens for Lambda functions being created in your AWS account. Then, you used a Terminating Gateway, Service Splitter, and Service Intention to route traffic flow in the service mesh with no downtime. Refer to the Consul AWS Lambda documentation for further details about Lambda function support in Consul.
To register a Lambda function manually in Consul, the Lambda registration documentation provides the necessary instructions and API calls to register services manually.