aws-blueprint example for an API backed by a single lambda
Each branch of this repo is a different language for the same example app.
This example sets up a CI/CD for a single lambda, fronted by CloudFront and API Gateway.
- Resources CloudFormation: aws/cloudformation/cf-apig-single-lambda-resources.yaml
- CI/CD CloudFormation: single-lambda-test-staging-prod.yaml
-
Run the setup script from your local git repo dir:
wget -q https://raw.githubusercontent.com/rynop/abp-single-lambda-api/master/bin/setup.sh; bash setup.sh; rm setup.sh
This:
- Downloads the branch of of your favorite programming language, and common aws dir out of
master
branch. - Sets
NestedStacksS3Bucket
and s3 versions of yournested-stacks
in your resources CloudFormation file.
- Downloads the branch of of your favorite programming language, and common aws dir out of
-
Create a s3 bucket that will hold your lambda zips. Only need one bucket per AWS. Ex:
deploy.yourdomain.com
-
Create your "resources" (CloudFront, API Gateway etc) stacks using
aws/cloudformation/cf-apig-single-lambda-resources.yaml
in your repo. Stack naming convention is[stage]--[repo]--[branch]--[eyecatcher]--r
. Ex:prod--abp-single-lambda-api--master--ImageManip--r
:- Create a stack for your
test
andprod
stages. You will have 2 root stacks. Theprod
stack takes care of bothprod
andstaging
resources. - The
Outputs
tab in the CloudFormation UI for each root stack has commands you will run in the next steps. Outputs that start withRun*
you should run from your CLI.
- Create a stack for your
-
Some of the Lambda configuration is stored in Systems manager parameter store with the convention based prefix
/<stage>/<repoName>/<branch>/<lambdaName>/
. Ex:aws ssm put-parameter --name "/prod/abp-single-lambda-api/master/ResizeImage/lambdaExecutionRoleArn" --type "String" --value 'arn:aws:iam::accountId:role/roleName'
. These keys are required per stage:/<stage>/<repoName>/<branch>/<lambdaName>/lambdaExecutionRoleArn
(don't create forstaging
stage.staging
uses theprod
lambdaExecutionRoleArn
). The output of the Resources CloudFormation stack contains aSsmSetLambdaExecutionRoleCmd
value that is an aws CLI command that sets this for you./<stage>/<repoName>/<branch>/<lambdaName>/lambdaTimeout
/<stage>/<repoName>/<branch>/<lambdaName>/lambdaMemory
/<stage>/<repoName>/<branch>/<lambdaName>/vpcConfig
. Optional. If your lambda needs to be in vpc, value should be likeSubnetIds=string,string,SecurityGroupIds=string,string
. See AWS CLI docs for more info.
-
Setup env vars per stage. All keys in the
lambdaEnvs
namespace are automatically added your your lambda's env. They can optionally be encrypted in systems manager param store, we handle all the decoding complexity (if you use the default KMS key). You can use this script help set them./<stage>/<repoName>/<branch>/<lambdaName>/lambdaEnvs/<env var name>
. Ex:/prod/abp-single-lambda-api/master/ResizeImage/lambdaEnvs/MY_VAR
- Run the
SsmSetXFromCdnEnvVarCmd
output value from the Resources CloudFormation stack. It setsX_FROM_CDN
(used by the example code in this repo). - These env vars get set for your in the lambda configuration:
APP_STAGE
-
Create a Github user (acct will just be used to read repos for CI/CD), give it read auth to your github repo. Create a personal access token for this user at https://github.com/settings/tokens. This token will be used by the CI/CD to pull code.
-
Go through the
README.md
of the language branch you copied, language specific setup and for stack parameter values that will be used in CI/CD stack creation (next step). -
Create a CloudFormation stack for your CI/CD using single-lambda-test-staging-prod.yaml with the stack naming convention of
[repo]--[branch]--[eyecatcher]--cicd
. Ex:abp-single-lambda-api--master--ResizeImage--cicd
. -
Commit your code and the CI/CD CodePipline will automatically run. The buildspec files assume you check in your dependencies (aka
node_modules
). Prevents version issues when working in teams, also prevents deploy issues during github outage. -
The domain your app can be reached, is located in the
Outputs
tab of the resources CloudFormation stack at keyCNAME
. -
Create a DNS entry in route53 for production that consumers will use. The cloud formation creates one for
prod--
but you do not want to use this as the CloudFormation can be deleted.
Want a lambda that does not need a web API (that is invoked by something like sns)? Follow the steps above, but instead of using aws/cloudformation/cf-apig-single-lambda-resources.yaml
for your resources CloudFormation, use aws/cloudformation/no-web-api-single-lambda-resources.yaml
. You will use the same codebuild files and same CI/CD.
Astute developers may notice an APIG line in aws/codebuild/lambda-publish, however this has no impact and will not fail the build.
The publishing process is multi-stage, with manual approvals, all handled in an automated fashion. Here are the details:
PublishTest
step:- Create Lambda if DNE. Set env vars from ssm namespace
/test/[repo]/[branch]/[LAMBDA_NAME]/lambdaEnvs
, role from/test/[repo]/[branch]/[LAMBDA_NAME]/lambdaExecutionRoleArn
, timeout from/test/[repo]/[branch]/[LAMBDA_NAME]/lambdaTimeout
, memory from/test/[repo]/[branch]/[LAMBDA_NAME]/lambdaMemory
, - Create Lambda version & alias
test
- Create Lambda if DNE. Set env vars from ssm namespace
- When CodePipeline
ApproveTest
approved,PublishStaging
step: :- Update lambda. Set env vars from ssm namespace
/staging/[repo]/[branch]/[LAMBDA_NAME]/lambdaEnvs
, role from/prod/[repo]/[branch]/[LAMBDA_NAME]/lambdaExecutionRoleArn
, timeout from/staging/[repo]/[branch]/[LAMBDA_NAME]/lambdaTimeout
, memory from/test/[repo]/[branch]/[LAMBDA_NAME]/lambdaMemory
. - Copy zip package to
s3://${S3_BUCKET_CONTAINING_PACKAGES}/${S3_PATH_TO_PACKAGES}/${codeSha256}.zip
wherecodeSha256
is the just deployedstaging
lambdaCodeSha256
configuration value. This ensures the code deployed to staging is the code that will be deployed toprod
. - Create Lambda version & alias
staging
- Update lambda. Set env vars from ssm namespace
- When CodePipeline
ApproveStaging
approved,PublishProd
step: :- Update lambda using
${codeSha256}.zip
. Set env vars from ssm namespace/prod/[repo]/[branch]/[LAMBDA_NAME]/lambdaEnvs
, role from/prod/[repo]/[branch]/[LAMBDA_NAME]/lambdaExecutionRoleArn
, timeout from/staging/[repo]/[branch]/[LAMBDA_NAME]/lambdaTimeout
, memory from/prod/[repo]/[branch]/[LAMBDA_NAME]/lambdaMemory
. - Create Lambda version & alias
prod
- Update lambda using