AWS DevOps & Developer Productivity Blog
Automated CI/CD pipeline for .NET Core Lambda functions using AWS extensions for dotnet CLI
The trend of building AWS Serverless applications using AWS Lambda is increasing at an ever-rapid pace. Common use cases for AWS Lambda include data processing, real-time file processing, and extract, transform, and load (ETL) for data processing, web backends, internet of things (IoT) backends, and mobile backends. Lambda natively supports languages such as Java, Go, PowerShell, Node.js, C#, Python, and Ruby. It also provides a Runtime API that allows you to use any additional programming languages to author your functions.
.NET framework occupies a significant footprint in the technology landscape of enterprises. Nowadays, enterprise customers are modernizing .NET framework applications to .NET Core using AWS Serverless (Lambda). In this journey, you break down a large monolith service into multiple smaller independent and autonomous microservices using.NET Core Lambda functions
When you have several microservices running in production, a change management strategy is key for business agility and time-to-market changes. The change management of .NET Core Lambda functions translates to how well you implement an automated CI/CD pipeline using AWS CodePipeline. In this post, you see two approaches for implementing CI/CD for .NET Core Lambda functions: creating a pipeline with either two or three stages.
Creating a pipeline with two stages
In this approach, you define the pipeline in CodePipeline with two stages: AWS CodeCommit and AWS CodeBuild. CodeCommit is the fully-managed source control repository that stores the source code for .NET Core Lambda functions. It triggers CodeBuild when a new code change is published. CodeBuild defines a compute environment for the build process. It builds the .NET Core Lambda function and creates a deployment package (.zip). Finally, CodeBuild uses AWS extensions for Dotnet CLI to deploy the Lambda packages (.zip) to the Lambda environment. The following diagram illustrates this architecture.
Creating a pipeline with three stages
In this approach, you define the pipeline with three stages: CodeCommit, CodeBuild, and AWS CodeDeploy.
CodeCommit stores the source code for .NET Core Lambda functions and triggers CodeBuild when a new code change is published. CodeBuild defines a compute environment for the build process and builds the .NET Core Lambda function. Then CodeBuild invokes the CodeDeploy stage. CodeDeploy uses AWS CloudFormation templates to deploy the Lambda function to the Lambda environment. The following diagram illustrates this architecture.
Solution Overview
In this post, you learn how to implement an automated CI/CD pipeline using the first approach: CodePipeline with CodeCommit and CodeBuild stages. The CodeBuild stage in this approach implements the build and deploy functionalities. The high-level steps are as follows:
- Create the CodeCommit repository.
- Create a Lambda execution role.
- Create a Lambda project with .NET Core CLI.
- Change the Lambda project configuration.
- Create a buildspec file.
- Commit changes to the CodeCommit repository.
- Create your CI/CD pipeline.
- Complete and verify pipeline creation.
For the source code and buildspec file, see the GitHub repo.
Prerequisites
Before you get started, you need the following prerequisites:
- MacOS, Linux, or up-to-date Windows 10
- Visual Studio 2019 with latest updates (if on Windows)
- .NET Core 3.1
- AWS extensions for Dotnet CLI
- Amazon.Lambda.Templates package
Creating a CodeCommit repository
You first need a CodeCommit repository to store the Lambda project source code.
1. In the Repository settings section, for Repository name, enter a name for your repository.
2. Choose Create.
3. Initialize this repository with a markdown file (readme.md). You need this markdown file to create documentation about the repository.
4. Set up an AWS Identity and Access Management (IAM) credential to CodeCommit. Alternatively, you can set up SSH-based access. For instructions, see Setup for HTTPS users using Git credentials and Setup steps for SSH connections to AWS CodeCommit repositories on Linux, MacOS, or Unix. You need this to work with the CodeCommit repository from the development environment.
5. Clone the CodeCommit repository to a local folder.
Proceed to the next step to create an IAM role for Lambda execution.
Creating a Lambda execution role
Every Lambda function needs an IAM role for execution. Create an IAM role for Lambda execution with the appropriate IAM policy, if it doesn’t exist already. You’re now ready to create a Lambda function project using .NET Core Command Line Interface (CLI).
Creating a Lambda function project
You have multiple options for creating .NET Core Lambda function projects, such as using Visual Studio 2019, Visual Studio Code, and .NET Core CLI. In this post, you use .NET Core CLI.
By default, .NET Core CLI doesn’t support Lambda projects. You need the Amazon.Lambda.Templates nuget package to create your project.
- Install the nuget package Amazon.Lambda.Templates to have all the Amazon Lambda project templates in the development environment. See the following CLI Command.
dotnet new -i Amazon.Lambda.Templates::*
- Verify the installation with the following CLI Command.
dotnet new
You should see the following output reflecting the presence of various Lambda templates in the development environment. You also need to install AWS extensions for Dotnet Lambda CLI to deploy and invoke Lambda functions from the terminal or command prompt.
- To install the extensions, enter the following CLI Commands.
dotnet tool install -g Amazon.Lambda.Tools dotnet tool update -g Amazon.Lambda.Tools
You’re now ready to create a Lambda function project in the development environment.
- Navigate to the root of the cloned CodeCommit repository (which you created in the previous step).
- Create the Lambda function by entering the following CLI Command.
dotnet new lambda.EmptyFunction --name Dotnetlambda4 --profile default --region us-east-1
After you create your Lambda function project, you need to make some configuration changes.
Changing the Lambda function project configuration
When you create a .NET Core Lambda function project, it adds the configuration file aws-lambda-tools-defaults.json at the root of the project directory. This file holds the various configuration parameters for Lambda execution. You want to make sure that the function role is set to the IAM role you created earlier, and that the profile is set to default.
The updated aws-lambda-tools-defaults.json file should look like the following code:
{
"Information": [
"This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
"To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
"dotnet lambda help",
"All the command line options for the Lambda command can be specified in this file."
],
"profile": "default",
"region": "us-east-1",
"configuration": "Release",
"framework": "netcoreapp3.1",
"function-runtime": "dotnetcore3.1",
"function-memory-size": 256,
"function-timeout": 30,
"function-handler": "Dotnetlambda4::Dotnetlambda4.Function::FunctionHandler",
"function-role": "arn:aws:iam::awsaccountnumber:role/testlambdarole"
}
After you update your project configuration, you’re ready to create the buildspec.yml file.
Creating a buildspec file
As a prerequisite to configuring the CodeCommit stage, you created a Lambda function project. For the CodeBuild stage, you need to create a buildspec file.
Create a buildspec.yml file with the following definition and save it at the root of the CodeCommit directory:
version: 0.2
env:
variables:
DOTNET_ROOT: /root/.dotnet
secrets-manager:
AWS_ACCESS_KEY_ID_PARAM: CodeBuild:AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY_PARAM: CodeBuild:AWS_SECRET_ACCESS_KEY
phases:
install:
runtime-versions:
dotnet: 3.1
pre_build:
commands:
- echo Restore started on `date`
- export PATH="$PATH:/root/.dotnet/tools"
- pip install --upgrade awscli
- aws configure set profile $Profile
- aws configure set region $Region
- aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID_PARAM
- aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY_PARAM
- cd Dotnetlambda4
- cd src
- cd Dotnetlambda4
- dotnet clean
- dotnet restore
build:
commands:
- echo Build started on `date`
- dotnet new -i Amazon.Lambda.Templates::*
- dotnet tool install -g Amazon.Lambda.Tools
- dotnet tool update -g Amazon.Lambda.Tools
- dotnet lambda deploy-function "Dotnetlambda4" --function-role "arn:aws:iam::yourawsaccount:role/youriamroleforlambda" --region "us-east-1"
You’re now ready to commit your changes to the CodeCommit repository.
Committing changes to the CodeCommit repository
To push changes to your CodeCommit repository, enter the following git commands.
git add --all
git commit –a –m “Initial Comment”
git push
After you commit the changes, you can create your CI/CD pipeline using CodePipeline.
Creating a CI/CD pipeline
To create your pipeline with a CodeCommit and CodeBuild stage, complete the following steps:
- In the Pipeline settings section, for Pipeline name, enter a name.
- For Service role, select New service role.
- For Role name, use the auto-generated name.
- Select Allow AWS CodePipeline to create a service role so it can be used with this new pipeline.
- Choose Next.
- In the Source section, for Source provider, choose AWS CodeCommit.
- For Repository name, choose your repository.
- For Branch name, choose your branch.
- For Change detection options, select Amazon CloudWatch Events.
- Choose Next.
- In the Build section, for Build provider, choose AWS CodeBuild.
- For Environment image, choose Managed image.
- For Operating system, choose Ubuntu.
- For Image, choose aws/codebuild/standard:4.0.
- For Image version, choose Always use the latest image for this runtime version.
- CodeBuild needs to assume an IAM service role to get the required privileges for successful build operation.Create a new service role for the CodeBuild project.
- Attach the following IAM policy to the role:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "SecretManagerRead", "Effect": "Allow", "Action": [ "secretsmanager:GetRandomPassword", "secretsmanager:GetResourcePolicy", "secretsmanager:UntagResource", "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret", "secretsmanager:ListSecretVersionIds", "secretsmanager:ListSecrets", "secretsmanager:TagResource" ], "Resource": "*" } ] }
- You now need to define the compute and environment variables for CodeBuild. For Compute, select your preferred compute.
- For Environment variables, enter two variables. For Region, enter your preferred Region. For Profile, Enter Value as default. This allows the environment to use the default AWS profile in the build process.
- To set up an AWS profile, the CodeBuild environment needs AccessKeyId and SecretAccessKey. As a best practice, configure AccessKeyId and SecretAccessKey as secrets in AWS Secrets Manager and reference it in buildspec.yml. On the Secrets Manager console, choose Store a new secret.
- For Select secret type, select Other type of secrets.
- Configure secrets AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
- For the encryption key, choose DefaultEncryptionKey.
- Choose Next.
- For Secret name, enter CodeBuild.
- Leave the rest of selections as default and choose Store.
- In the Add deploy stage section, choose Skip deploy stage.
Completing and verifying your pipeline
After you save your pipeline, push the code changes of the Lambda function from the local repository to the remote CodeCommit repository.
After a few seconds, you should see the activation of the CodeCommit stage and transition to CodeBuild stage. Pipeline creation can take up to a few minutes.
You can verity your pipeline on the CodePipeline console. This should deploy the Lambda function changes to the Lambda environment.
Cleaning up
If you no longer need the following resources, delete them to avoid incurring further charges:
- CodeCommit repository
- CodePipeline project
- CodeBuild project
- IAM role for Lambda execution
- Lambda function
Conclusion
In this post, you implemented an automated CI/CD for .NET Core Lambda functions using two stages of CodePipeline: CodeCommit and CodeBuild. You can apply this solution to your own use cases.
About the author
Sundararajan Narasiman works as Senior Partner Solutions Architect with Amazon Web Services.