chrismitchellonline

Prepare a NodeJS Lambda Function for CodePipeline

2020-11-12

With AWS CodePipeline we can create an continuos integration and deployment using AWS managed services to build, test, and deploy code to our Lambda functions. This article will outline the steps we need to take to prepare our NodeJS Lambda functions to be able to be built using CodeBuild and deployed using CodePipeline.

CloudFormation

The first step we need to do is ensure that our Lambda function is managed by a CloudFormation stack. For more information on this topic see this article: Create a Lambda Function with CloudFormation.

Read on to see examples of creating a new Lambda function or using an existing. In each case we will need to include the CloudFormation template file with our code for use in the pipeline.

New Lambda Function

If you are creating a new Lambda function to be used with CodePipelines you can use the following CloudFormation template to create a new NodeJS Lambda function and role. I’ve assumed a few basic details like function name and runtime. Additionally, the source code for your function should be in an S3 bucket and BUCKET and SOURCE parameters should be filled in.

Click to copy snippet to your clipboard Copied!
{
   "AWSTemplateFormatVersion": "2010-09-09",
   "Resources": {
       "NewLambdaFunction": {
       "Type": "AWS::Lambda::Function",
       "Properties": {
           "FunctionName": "",
           "Handler": "lambda/index.handler",
           "Role": {
           "Fn::GetAtt": [
               "NewLambdaFunctionRole",
               "Arn"
           ]
           },       
           "Code": {
           "S3Bucket": "<BUCKET>",
           "S3Key": "<SOURCE>"
           },
           "Runtime": "nodejs12.x"  
       }
       },
       "NewLambdaFunctionRole": {
       "Type": "AWS::IAM::Role",
       "Properties": {
           "RoleName": "NewLambdaFunctionRole",
           "AssumeRolePolicyDocument": {
           "Version": "2012-10-17",
           "Statement": [{
               "Effect": "Allow",
               "Principal": {
               "Service": [ "lambda.amazonaws.com" ]
               },
               "Action": [ "sts:AssumeRole" ]
           }]
           },
           "Path": "/",
           "Policies": [{
           "PolicyName": "AWSLambdaBasicExecutionRole",
           "PolicyDocument": {
               "Version": "2012-10-17",
               "Statement": [{
               "Effect": "Allow",
               "Action": [
                   "logs:CreateLogGroup",
                   "logs:CreateLogStream",
                   "logs:PutLogEvents"
               ],
               "Resource": "*"
               }]
           }
           }]
       }
       }
   }
}

Save this template to a file CFTemplate.json and run this command to create your new CloudFormation stack with a new Lambda function:

aws cloudformation create-stack --stack-name NewLambdaFunctionStack --template-body file://CFTemplate.json --capabilities CAPABILITY_NAMED_IAM
Existing Lambda Function

If you plan on using CodePipeline to deploy code to an existing Lambda function you will need to add your Lambda function to a CloudFormation stack. You can do this by defining your Lambda function details in a CloudFormation template, similar to creating a new CloudFormation stack, with a few extra requirements:

  • DeletionPolicy Must be defined in your resource. I’m using “Retain”
  • Role Must already exist
  • Source Must be a copy of your existing Lambda function, in a .zip file and available in S3
Click to copy snippet to your clipboard Copied!
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Describe your function.",
    "Resources":{
        "ExistingFunction":{
            "DeletionPolicy": "Retain",
            "Type": "AWS::Lambda::Function",
            "Properties":{
                "Code":{
                    "S3Bucket": BUCKET,
                    "S3Key": SOURCE
                },
                "Handler": "index.handler",
                "Runtime": "nodejs12.x",
                "Role": EXISTING ROLE
            }
        }
    }
}

Save this file as CFTemplate.json to use for the import process.

Then to create a CloudFormation stack I found it easiest to use the web console. From the CloudFormation home page, select Create Stack -> With existing resources (Import resources). Use CFTemplate.json as the template, and follow the directions for importing the individual resources.

Note: This process is also possible via AWS CLI, but there are multiple steps that the web console does for you, such as defining resources and creating change sets to create your new CloudFormation stack. Unless CLI is necessary, I found the web console the easiest way to do this task.

CodeBuild

AWS CodePipeline will use CodeBuild for the build process of our code. In our NodeJS application a build process usually consists of running npm install to pull our NPM packages, but can also include running tests, etc. To define our build process we will need to include a buildspec.yml file in our source.

Also notice we are including the CFTemplate.json file from our CloudFormation template using the aws cloudformation package command. CodeBuild will update the template with our latest source information and make it available to CodePipelines via S3.

Here is a sample buildspec file:

version: 0.2
phases:
  install:
    runtime-versions:
        nodejs: 12
  build:
    commands:
      - npm ci
      - export BUCKET=<OUTPUT BUCKET>     
      - aws cloudformation package --template-file CFtemplate.json --s3-bucket $BUCKET --s3-prefix codepipeline --output-template-file outputtemplate.yml
artifacts:
  type: zip
  files:
    - template.yml
    - outputtemplate.yml

In this template we define run time version, output artifacts for use with additional CodePipeline tasks, and our build commands. Along with running npm install (npm ci) we also define where our output sources will live. These built sources will be used by CodePipeline to deploy our code.

Ensure this buildspec.yml file is included with your source code to allow CodeBuild to build your application.

Conclusion

With your Lambda function now living in a CloudFormation stack with a template.json file, and having a buildspec.yml file, this is all we need from the source code side to be able to use CodePipeline to deploy our Lambda application.

comments powered by Disqus
Social Media