DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • AWS Step Functions Local: Mocking Services, HTTP Endpoints Limitations
  • A Comprehensive Guide To Testing and Debugging AWS Lambda Functions
  • Deploying Java Serverless Functions as AWS Lambda
  • Building Scalable Data Lake Using AWS

Trending

  • Breaking Bottlenecks: Applying the Theory of Constraints to Software Development
  • How to Configure and Customize the Go SDK for Azure Cosmos DB
  • A Modern Stack for Building Scalable Systems
  • Performance Optimization Techniques for Snowflake on AWS
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. AWS Lambda Aliases: A Practical Approach

AWS Lambda Aliases: A Practical Approach

Simple and flexible Lambda function configuration across multiple environments.

By 
Robert Pupazzoni user avatar
Robert Pupazzoni
·
Mar. 14, 22 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
5.6K Views

Join the DZone community and get the full member experience.

Join For Free

Lambda functions are a fundamental component of the AWS serverless model. They provide a simple, cost-effective, and easily scalable programming model based on FaaS (functions as a service).

Lambda ARNs

Lambda functions can be referenced by their ARN (Amazon Resource Name). For example, the ARN to reference a 'helloworld' function in the 'us-east-2' region in account '3445435' would be:

arn:aws:lambda:us-east-2:3445435:function:helloworld

By default, referencing a Lambda function without any additional qualifiers will reference the code in the unpublished version of the Lambda, which is termed $LATEST. Therefore, these two ARNs are exactly equivalent:

arn:aws:lambda:us-east-2:3445435:function:helloworld

arn:aws:lambda:us-east-2:3445435:function:helloworld:$LATEST

Publishing and Referencing Lambda Versions

The act of "publishing" a Lambda function simply copies the code and the current values of its environment variables from $LATEST to a sequentially numbered version.  Each time a Lambda is published the version number is incremented by 1.

A published version is basically an immutable snapshot of $LATEST which includes all of the following:

  • The function code and all associated dependencies.
  • The Lambda runtime that invokes the function.
  • All the function settings, including the environment variables.
  • A unique Amazon Resource Name (ARN) to identify the specific version of the function.

Any subsequent changes to the code and/or its environment variables can only be made to the unpublished (i.e., $LATEST) version. (As we shall see, this limitation has a significant downside with respect to the configuration in multiple environments.)

To reference a specific published version of a Lambda, we simply append the version number to the ARN. For example, to reference version 3 of our 'helloworld' function, we can use:

arn:aws:lambda:us-east-2:3445435:function:helloworld:3

Hello World Function Breakdown

Lambda Aliases

A Lambda Alias is simply a named pointer to a specific Lambda version. We can have multiple aliases for our Lambda function, each pointing to a different (or even the same) version.

Similar to versions, we can reference the aliased version of a Lambda function simply by appending the alias name to the ARN. Suppose we create an alias called test, and point it to version 3. Then the following ARNs are equivalent:

arn:aws:lambda:us-east-2:3445435:function:helloworld:test

arn:aws:lambda:us-east-2:3445435:function:helloworld:3

One of the advantages of using the alias (rather than the explicit version number), is the alias mapping can easily be changed to point to a different version, with no changes or impact to any consumers of the Lambda. Aliases can also facilitate blue/green traffic routing, canary deployments, etc. but for this article, we will focus on the configuration aspects.

Hello World Example With Lambda AliasesAssume for example we have a test environment and a prod environment, and we wish to run different versions of the same Lambda in each. We can use aliases to point to different versions in each environment — the test alias might point to our newer bleeding-edge function version 3, while the prod alias might point to a more stable function version 2. At any time, we can simply re-point our aliases to different versions as needed to promote or roll back the versions for a specific environment.

Trouble in Paradise

Now let's assume our Lambda function needs to access a DynamoDB table. Rather than hard-coding the DynamoDB table name into the code, best practice would dictate that we externalize the configuration with a Lambda environment variable (e.g., TABLE_NAME), and reference that variable from within our code. Now, should we need to change the table name, we can simply change the value of the environment variable — no code changes are needed. If we're using Lambda aliases, we can simply publish a new version of the code, point the alias to the new version, and the config change will immediately take effect. Simple!

Well, not always. One of the advantages of aliases is the ability to more easily support different versions for multiple operating environments (like our previous test and prod example). In such a situation, it's actually quite likely we'd prefer using different DynamoDB tables for test vs. prod. (That is... unless we want to live dangerously and risk blowing away our production data!)

But as we know, a Lambda Alias is just a named pointer to some underlying immutable version. And that immutable version includes both the code and the values of its environment variables at the time it was published.  So before we publish a new version of the code, we'll need to change the environment values each time to correspond to all of the multiple environments with different configurations.

For example, we might consider publishing 2 versions every time:  one with the TABLE_NAME environment value set for the test, and another one for the TABLE_NAME environment value set for prod. Now imagine we have even more environments and dozens or hundreds of functions. Perhaps we could automate this somehow, but at best, it's error-prone and hard to manage.  At worst, a mistake could prove disastrous.

A Practical Solution

So how can we leverage the advantages of Lambda Aliases while having a flexible configuration for multiple environments? We want our code to be immutable, but we need to inject different external configurations into that code, based on the environment our code is running in.

Rather than trying to bake in a fixed configuration at deployment time, we can instead use the value of the Lambda Alias at runtime to dynamically determine an appropriate location to load configuration data from. Depending on the use case, this could include AWS S3, AWS Systems Manager Parameter Store, a dedicated config server (e.g., Spring Cloud Config), etc.  The general approach is applicable to any supported programming language supported by Lambda.  

For simplicity, let's explore a straightforward Python code example using an S3 bucket to store Lambda configurations.

Python Example

Assume we want to support 3 Lambda function environments:

  • A dev environment that simply points to our $LATEST Lambda version.
  • A test environment pointed to a version referenced by a Lambda Alias called test.
  •  A prod environment pointed to a version referenced by a Lambda Alias called prod.

Let's create an S3 bucket called mycompany-lambda-config and store the following JSON files into it:

my-hello-world-LATEST.json: 

{"customer-table-name":"my-customer-table-dev", "product-catalog-id":"DEV0001"} 

my-hello-world-test.json: 

{"customer-table-name":"customer-sample-testing", "product-catalog-id":"TEST1234"}

my-hello-world-prod.json: 

{"customer-table-name":"customer-prod", "product-catalog-id":"CATALOG-2022"}

In our Lambda environment, we specify the S3 location using an environment variable with special placeholders for the function name and alias:

S3_CONFIG_SOURCE

s3://my-company-lambda-config/${functionName}-${aliasName}.json        

Now our objective is to determine, at runtime, the appropriate configuration to load from S3, based on the alias used to invoke the Lambda. The following Python code will accomplish this:

Python
 
import boto3
import json
import os

# Replace ${functionName} and ${aliasName} placeholders in 'str' with values from current Lambda 'context'
# ARN format - arn:aws:lambda:aws-region:acct-id:function:function-name:alias-name
def replace_arn_placeholders(str, context):
    arn = context.invoked_function_arn
    parts = arn.split(':')
    function_name = parts[6]
    if len(parts) > 7:
        alias_name = parts[7].replace('$LATEST', 'LATEST')
    else:
        alias_name = 'LATEST'
    return str.replace('${functionName}', function_name).replace('${aliasName}', alias_name)

# Parse 's3_path' (e.g. 's3://bucket-name/path-part-1/path-part-2/...') and into bucket-name and full path components
def extract_bucket_and_key(s3_path):
    path_parts = s3_path.replace("s3://","").split("/")
    bucket = path_parts.pop(0)
    key = "/".join(path_parts)
    return bucket, key

# Read JSON config file located at 's3_config_source_with_placeholders' and return name/value pairs
def read_json_config_values(s3_config_source_with_placeholders, context):
    s3_config_source = replace_arn_placeholders(s3_config_source_with_placeholders, context)
    print('s3_config_source: ' + s3_config_source)
    (s3_bucket, s3_key) = extract_bucket_and_key(s3_config_source)

    s3 = boto3.client('s3')
    obj = s3.get_object(Bucket=s3_bucket, Key=s3_key)
    return json.loads(obj["Body"].read())
    
def lambda_handler(event, context):
    print('invoked_function_arn: ' + context.invoked_function_arn)
    print('function_version: ' + context.function_version)

    s3_config_source_with_placeholders = os.environ.get('S3_CONFIG_SOURCE')
    print('s3_config_source_with_placeholders: ' + s3_config_source_with_placeholders)

    config_values = read_json_config_values(s3_config_source_with_placeholders, context)
    message = '*** Currently configured values: customer-table-name = ' + config_values['customer-table-name'] + ', product-catalog-id = ' + config_values['product-catalog-id']
    print(message)
    return message


Results

(1) Called via arn:aws:lambda:aws-region:acct-id:function:my-hello-world

invoked_function_arn: arn:aws:lambda:us-east-1:512804910637:function:my-hello-world 

function_version: $LATEST 

s3_config_source_with_placeholders: s3://veriforge-lambda-config/${functionName}-${aliasName}.json 

s3_config_source: s3://veriforge-lambda-config/my-hello-world-LATEST.json 

*** Currently configured values: 

customer-table-name = my-customer-table-dev, product-catalog-id = DEV0001


(2) Called via arn:aws:lambda:aws-region:acct-id:function:my-hello-world:test

invoked_function_arn: arn:aws:lambda:us-east-1:512804910637:function:my-hello-world:test 

function_version: 12 

s3_config_source_with_placeholders: s3://veriforge-lambda-config/${functionName}-${aliasName}.json 

s3_config_source: s3://veriforge-lambda-config/my-hello-world-test.json 

*** Currently configured values: 

customer-table-name = customer-sample-testing, product-catalog-id = TEST1234


(3) Called via arn:aws:lambda:aws-region:acct-id:function:my-hello-world:prod

invoked_function_arn: arn:aws:lambda:us-east-1:512804910637:function:my-hello-world:prod 

function_version: 11 

s3_config_source_with_placeholders: s3://veriforge-lambda-config/${functionName}-${aliasName}.json 

s3_config_source: s3://veriforge-lambda-config/my-hello-world-prod.json 

*** Currently configured values: 

customer-table-name = customer-prod, product-catalog-id = CATALOG-2022 

Conclusion

We've demonstrated a simple technique for externalizing Lambda function configurations and dynamically loading the appropriate configuration at runtime based on the Lambda Alias the function was invoked with. The code required to implement this technique can easily be coded in any language runtime supported by Lambda. We simply need to:

  1. Define an environment variable pointing to a desired config source location (e.g. an S3 bucket).
  2. Parameterize the environment variable using dynamic placeholders for the function name and alias.
  3. Resolve the placeholders at runtime and load the appropriate configuration on-demand.
AWS AWS Lambda Testing

Opinions expressed by DZone contributors are their own.

Related

  • AWS Step Functions Local: Mocking Services, HTTP Endpoints Limitations
  • A Comprehensive Guide To Testing and Debugging AWS Lambda Functions
  • Deploying Java Serverless Functions as AWS Lambda
  • Building Scalable Data Lake Using AWS

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!