This post is part of our AWS/Terraform Workshops series, which explores our vision for Service Oriented Architecture (SOA) and closely examines AWS Simple Storage Service, Terraform Remote State, and Identity Access Management. To learn more, check out our introductory workshop and new posts at Smartling Engineering Blog.
AWS Lambda is a compute service where you can upload your code and the application will run it on your behalf using AWS' infrastructure. Once code is uploaded as a Lambda function, AWS will take care of provisioning and managing the servers that will be used to run it. There are three languages currently supported: Node.js, Python 2.7, and Java.
A common Lambda use is for event-driven compute services, where code is executed in response to events, such as changes to data in an S3 bucket, a message in an SNS topic, CloudWatch events, etc.
Lambda functions consist of code, associated dependencies, and configuration. In the configuration, you specify how much memory should be allocated, the execution timeout, and the IAM role that Lambda will assume to execute code on your behalf. For Lambda functions, it is also required to specify a handler (that is, a filename and the name of the method/function in your code) where AWS Lambda can begin executing your code.
Note: CPU power cannot be specified in the Lambda configuration. AWS Lambda allocates it proportionally to allocated memory.
Note: 1536 MB is the maximum memory that can be allocated to a Lambda function, with a max execution duration of 300 seconds. More limits can be found here.
Event sources publish events that cause the Lambda function to be invoked. You associate an event source with your Lambda function using an event source mapping. The list of event sources supported by AWS Lambda (push invocation model) includes: SNS (when you push a new message to an Amazon SNS topic, it can trigger a Lambda function), scheduled events (you can set up AWS Lambda to invoke your code on a regular, scheduled basis using the schedule event capability in CloudWatch), and S3 (you can configure notifications on an Amazon S3 bucket to publish bucket events, such as when objects are created or deleted, to AWS Lambda and invoke a Lambda function to respond to these events).
Note: Scheduled event sources are defined as CloudWatch (event rules specify expressions for schedules).
Note: Scheduled CloudWatch event sources support a minimum interval of 5 minutes. If you wish to trigger Lambda function faster, you’ll need to write your own scheduler so that it will invoke Lambda with the desired frequency.
In addition to invoking Lambda functions using event sources, you can also invoke your Lambda function over HTTPS. You can do this by defining a custom REST API and endpoint using Amazon API Gateway. This is beyond the scope of this workshop, but you can find more info here.
Execution role: The IAM role must grant the permissions that your Lambda function needs (e.g. read objects in S3, read messages in SNS, permissions to modify AWS resources according to code).
Note: The execution role specifies permissions for a Lambda function itself but not permissions for those entities which trigger said Lambda function. So in order to make it possible for S3, SNS, or CloudWatch to trigger a Lambda function, you should use the AddPermission API call to add those permissions (or use the Terraform aws_lambda_permission resource instead).
Note: The IAM role specified as the execution role for the Lambda function must include the AWS Lambda service in its trust policy to allow the function to assume this role.
AWS Lambda automatically monitors Lambda functions on your behalf, reporting metrics through Amazon CloudWatch. To help you troubleshoot failures in a function, Lambda logs all requests handled by your function and also automatically stores logs generated by your code through Amazon CloudWatch Logs.
Note: In order to allow a Lambda function to create logs, the IAM role specified in the function’s configuration must have the corresponding permissions to CloudWatch.
Go to the w5 directory in the cloned Smartling/aws-terraform-workshops Git repository.
Create an Auto Scaling Group (ASG), then attach ELB to it.
Finish the incomplete Terraform configuration and be prepared to fix mistakes.
Attach ELB to the ASG (do not enable ELB checks for ASG, keep the default EC2).
terraform plan, terraform apply:
$ aws-profile yourteam-dev terraform plan
$ aws-profile yourteam-dev terraform apply
Check the AWS resources created in this step.
Make sure the ELB DNS name can be opened with your browser — it should show the Nginx welcome page.
Create an SNS topic, then subscribe your email to it.
Create a Lambda function for monitoring Nginx behind ELB. It will send the results to SNS (and to your mailbox).
Finish the incomplete terraform configuration to create a Lambda function triggered by CloudWatch events every 5 minutes.
terraform plan, terraform apply.
Go to the AWS Lambda console and check the URL and SNS in the Lambda function’s code.
Note: Make sure you specified the actual DNS name of your ELB (it can be found in the AWS web console or in the tfstate file)
Try to trigger the Lambda function in the console manually. Consider what should be changed in case the Lambda execution fails.
Check the Lambda function execution logs in CloudWatch.
Simulate a service outage by stopping Nginx at the instance in ASG.
Go to the instance via SSH and run the ‘sudo service docker stop’ command to shut down the container with Nginx.
Adjust the rules in the EC2 security group in your terraform configuration to prevent ELB from communicating with the instance.
Check that ELB doesn’t show the Nginx welcome page in your browser anymore.
Wait until the Lambda function is executed by the CloudWatch schedule. Make sure you received an email about the failed web check in your mailbox.
Destroy the AWS resources by using the corresponding terraform command. (Optional.)
Change the code of the Lambda function to send custom metrics to CloudWatch, e.g. 1 when the web check succeeded and 0 when it failed.
Find the previous workshop here!