Lambda Deployment using CodePipeline and CDK - amazon-web-services

I'm using CDK and am trying to define a CodePipeline that triggers a Lambda Deployment. It doesn't seem as if there are any CDK constructs to achieve this.
I could only find CodeDeployEcsDeployAction and CodeDeployServerDeployAction.
The problems are:
CodeDeployEcsDeployAction: asks for an ECS task definition
CodeDeployServerDeployAction: only accepts an artifact input for properties. However, it won't pick up the appspec file I have defined in the artifact and there are no properties to define the path
(There is no way to do artifact.atPath('appspec.json'))
(Submitted issue 20782 just in case this is an actual request)
Here's my Lambda CodeDeploy setup
const application = new codedeploy.LambdaApplication(
this,
'CodeDeployLambdaApplication',
{
applicationName: 'LambdaApplication',
},
);
const lambdaDeploymentGroup = new codedeploy.LambdaDeploymentGroup(
this,
'AllAtOnceDeployment',
{
application,
alias,
deploymentConfig: codedeploy.LambdaDeploymentConfig.ALL_AT_ONCE,
},
);

You need to use CodeDeploy and Lambda Action:
https://docs.aws.amazon.com/cdk/api/v1/docs/aws-codedeploy-readme.html for the general docs, specifically:
https://docs.aws.amazon.com/cdk/api/v1/docs/aws-codedeploy-readme.html#lambda-applications
Alternatively, if your program is not that complex and does not need all the additional overhead that CodeDeploy brings (having to synth the template and pass it to CodeDeploy and all) then just use a codebuild, that takes a source from your git repo and runs the command cdk deploy your stack

Related

AWS CDK accessing parameters when deploying stacks on the pipeline via yaml, typescript and nodejs

I'm fairly new to AWS and using the CDK but have been working on a project which deploys to AWS via a pipeline using yaml for the cf-template and later a node script to run cdk deploy on a set of stack files that have been written in Typescript.
In the cf-template yaml where the cdk-toolkit is being defined there's a bucket resource with name X. After the toolkit has been created/updated in the pipeline, the cdk deploy command is executed to deploy some stacks and workers, which should live in bucket X. They aren't automatically being uploaded there however, so I've tried using the --parameters flag to specify X as below.
cdk deploy --toolkit-stack-name my-toolkit --parameters uploadBucketName=X --ci --require-approval never
When I do this I get the following error in the pipeline for the first stack that gets deployed:
Parameters: [uploadBucketName] do not exist in the template
I assumed this meant that in the MyFirstStack.ts file it was missing a parameter definition as suggested by the AWS documentation, but it's not clear to me why this is necessary or how it's supposed to be used when it's the cdk deploy command which provides a value for this parameter. I tried adding it per the docs
const uploadBucketName = new CfnParameter(this, "uploadBucketName", {
type: "String",
description: "The name of the Amazon S3 bucket where uploaded files will be stored."});
but not sure if this is really the right thing to do, and it doesn't work besides - I still get the same error.
Does anyone have any ideas where I'm going wrong?

aws codepipline update lambda function source using s3 object

I am using terraform to create all the infra(CodePipeline, lambda, buckets) on AWS
currently, I've created a pipeline that builds the source zip file and puts it on s3 bucket but the lambda still keeps using the older source. So, I update the URL manually in the AWS console and it works.
Now I want to automate the flow but available solutions are:
AWS SAM + CFT
Codebuild Stage to update the source using AWS CLI
Create a lambda that updates the source
Code Deploy + AWS SAM + CFT
I am not willing to use CFT at all since all of our code is in terraform and CFT requires me to create new lambdas instead of using old ones.
is there any other simpler way to update the lambda source through Codepipeline
The preferred way to deploy a Lambda via CodePipeline is using a CloudFormation Deploy action [1]. Since you are not looking to use CloudFormation, next option could be to run your terraform plan/apply commands from within a CodeBuild job that is part of the pipeline. You will need to provide the CodeBuild role required permission for resource creation (or export the credentials in Environment variabels for TF to use via this [2] method) and install the TF binary within install phase of buildspec.
Ref:
[1] Building a Continuous Delivery Pipeline for a Lambda Application with AWS CodePipeline - https://docs.aws.amazon.com/lambda/latest/dg/build-pipeline.html
[2] How to retrieve Secret Manager data in buildspec.yaml

Deploy Lambda Function using CodePipeline and CDK generated CloudFormation Template

I have a Lambda function that I'm trying to deploy using CodePipeline.
The Lambda function source code is in the same project as the Lambda CDK app. Since they are both in the same repository, the CDK app can reference the Lambda source code directly.
The docs suggest to use lambda.Code.fromAsset(path) when the CDK app can reference the Lambda code directly so I started with the follow definition for my Lambda function.
const fn = new lambda.Function(this, "Fn", {
code: lambda.Code.fromAsset(path/to/lambda/source),
handler: "index.handler",
runtime: lambda.Runtime.NODEJS_10_X
});
In the CodePipeline, I use CodeBuild to run cdk synth and synthesize the CloudFormation template.
The problem with defining my Lambda in this way is the CloudFormation template has parameters for the Lambda source code bucket and key which are seemingly named randomly e.g. AssetParameters3ffd...affdS3Bucket1CFF873D
When you run cdk deploy the CLI knows what the parameters are and populates them with values.
In my case however, I'm not using cdk deploy. I want to use CloudFormation in a CodePipeline.
That means I need to fill the parameters with the values for the Lambda source artifact which is output from my CodeBuild step. Getting the values is easy but I have no way of knowing what the parameters are named.
Next I tried using the following to define the parameter names myself.
const fn = new lambda.Function(this, "Fn", {
code: lambda.Code.fromCfnParameters({
bucketNameParam: new core_1.CfnParameter(this, "LambdaSourceBucket"),
objectKeyParam: new core_1.CfnParameter(this, "LambdaSourceKey"),
}),
handler: "index.handler",
runtime: lambda.Runtime.NODEJS_10_X
});
No luck. cdk synth still modifies the parameter names in the template e.g. AppLambdaSourceBucket8B89D730. That's better than before but I still can't be sure what the parameters will be named so I can assign them in my CodePipeline.
I can't use lambda.Code.fromBucket(bucket, key) because the bucket and key are determined by the CodePipeline/CodeBuild.
I found this example which is doing almost the same thing as me except their CodePipeline is defined in the same CDK app as their Lambda function. That avoids the problem that I'm having because the Lambda definition and CodePipeline definition can both reference the same CfnParametersCode instance.
Unfortunately I can't co-locate my CodePipeline definition with my Lambda like they've done in that example. I feel like this should still be possible without that.
What am I missing?
I'm able to do this with new CfnParametersCode (which should be equivalent to the factory method you're calling). Are you possibly creating this inside another construct and not at the stack level?

How to deploy environment variable using serverless deploy for AWS lambda

I am new to AWS lambda i have i am using serveless deploy to deploy my lambda function declared in serverless.yml file.
In that file i wrote a lambda function i deployed and it is working fine but problem is that whatever environment variable i gave is not available in console of that lambda function. I might be doing some minor mistake or for deploying environment variable there should be some other syntax.
I can go to lambda function in console and add environment variable manually.
But my doubt is can we do it while deploying it through serverless deploy
You can use versions and aliases provided by AWS Lambda
You can create different versions of the same lambda function and give them an alias. Like when you push your lambda code - create a version (say it's 5) - create an alias this (say TEST).
When you're sure that its ready for production, create a version(or choose an existing version and name that (say PROD).
Now whenever your lambda function executes, it gives lambda ARN
which contains alias, by that you can know which alias(in context.invokedFunctionArn) is
executed i.e. that can be used as the environment variable. While
invoking the function, you can mention which function to execute from
your invocation code.
let thisARN = context.invokedFunctionArn;
// Get the last string in ARN - It's either function name or the alias name
let thisAlias = thisARN.split(":").pop();
Now whenever you deploy a new code, just point the alias to that version.
You can use AWS console or CLI for that.
Take a look at this lambda versioning and aliases
For directly deploying to your alias(PROD), you can do this -
aws lambda update-alias \
--region region \
--function-name helloworld \
--function-version 2 \
--name PROD
serverless deploy
Serverless deploy works fine for deployment on any stage it also deploys environment variable in given stage, my case environment variable was not deployed of indentation problem in yaml file, and even serverless deploy command was not throwing error it was deploying function but environment variables were not deployed
In yaml file we can state the the stage where we want to deploy like this
provider:
name: aws
runtime: nodejs6.10
stage: dev
region: eu-west-2
Hope this will help if someone gets similar issue

CodeDeploy can't find my AWS Lambda Function

I have an Issue with CodeDeploy and AWS Lambda when they work inside AWS CodePipeline. This is my setup:
Source GitHub
AWS CodeBuild
AWS CodeDeploy
The Issue
Step 1. and 2. work without a problem, but when it comes to CodeDeploy I get the following error:
Action execution failed BundleType must be either YAML or JSON
If I unzip the Artifact generated by CodeBuild all the files are in place.
If I try to manually deploy to AWS Lambda from CodeDeploy I then get a different message...
Deployment Failed The deployment failed because either the target
Lambda function FUNCTION_NAME does not exist or the specified function
version or alias cannot be found
This is very confusion as to which Error message is valid, or if they are the same but have a different Error message.
The Setup
The ARN of the function is:
arn:aws:lambda:us-east-1:239748505547:function:email_submition
The ARN for the Alias is:
arn:aws:lambda:us-east-1:239748505547:function:email_submition:default
And my appspec.yml file has the following content
version: 0.0
Resources:
- email_submition:
Type: AWS::Lambda::Function
Properties:
Name: "email_submition"
Alias: "default"
CurrentVersion: "1"
TargetVersion: "2"
And the folder structure of the project is:
.gitignore
appspec.yml
buildspec.yml
index.js
README.md
Question
What am I missing in this configuration?
So really this should be a comment not an answer. I do not have 50 rep yet so it's here.
I am having the same issues as you. I'm not sure if you found a solution or not. I was able to successfully execute a deployment with the following appspec.yml:
version: 0.0
Resources:
- mylambdafunction:
Type: AWS::Lambda::Function
Properties:
Name: "mylambdafunction"
Alias: "staging"
CurrentVersion: "2"
TargetVersion: "3"
Both the current version and target version had to exist before CodeDeploy would work. Of course I've tested this by doing a manual deployment.
I think what is needed here is something that actually updates the code and creates a new version. Which is what I would have thought CodeDeploy would do.
Edit: Further research has yielded information about CodePipeline I hadn't realized.
Per here it looks like to run through the Pipeline you need your buildspec, appspec, and a cft. The reason the pipeline fails is because you need to include a CloudFormation Template for the lambda function, this is what deploys the actual code. The appspec.yml is there to migrate traffic from the old version to the new version but the cft is what does the deployment of new code.
Edit2: This example app got me squared away.
Use CodeBuild to build your app but also to generate your CFT for doing actual deployment. This means you build your CFT with the lambda resource.
This removes appspec completely from the resources and instead you use a CFT to define the Lambda function. Here is a link to the SAM docs.
I can not help you with the CodeBuild part as I use a 3rd party CI solution but maybe I can help with the rest.
I think there is a mistake in the AWS documentation as I've never been able to get this to work either. They say to call "aws deploy push" on the command line and give it your appspec.yml file instead of a zip for Lambda, but no matter what you do, you will always get the error:
Action execution failed BundleType must be either YAML or JSON
I think this is because push automatically calls "register-application-revision" after it uploads. If you split this into separate parts, this will work.
Your appspec.yml should look like the
version: 0.0
Resources:
- YourFunctionName:
Type: "AWS::Lambda::Function"
Properties:
Name: "YourFunctionName"
Alias: "YourFunctionNameAlias"
CurrentVersion: "CurrentAliasVersionGoesHere"
TargetVersion: "NewlyPublishedVersionGoesHere"
The version you use should be the version the current alias is attached to. The target version should be the new version you just published (see below) This part still confusing me a bit. I don't understand why it can't figure out what the current version the alias is pointing to by itself.
Also, note that you can always just upload new code for your Lambda code with update-function-code and it will overwrite the latest version. Or you can publish which will create a new version and always just call the latest version. CodeDeploy is only necessary if you want to do some fancy gradually deployment or have different versions for test and live code.
I'd try the following:
Publish your lambda function:
aws lambda update-function-code --function-name YourFunction --zip-file fileb://~/your-code.zip --publish
Take note of the version number it created
Upload your appspec.yml file to S3
aws s3 cp appspec.yml s3://your-deploy-bucket/your-deploy-dir/appspec.yml
Register your application revision:
aws deploy register-application-revision --application-name YourApplcationName --s3-location bucket=your-deploy-bucket,key=your-deploy-dir/appspec.yml,bundleType=YAML
From the CLI this won't appear to do anything, but it did.
Get the application revision to make sure it worked
aws deploy get-application-revision --application-name YourApplcationName --s3-location bucket=your-deploy-bucket,key=your-deploy-dir/appspec.yml,bundleType=YAML
Create a deployment to deploy your code
aws deploy create-deployment --s3-location bucket=your-deploy-bucket,key=your-deploy-dir/appspec.yml,bundleType=YAML