An independent guide to building modern software for serverless and native cloud

Deploying CloudFormation Stacks

This tutorial references the code in the aws-connectedcar-dotnet-serverless repository. If you're new to this course, see the introduction for information about setting up your workstation and getting the sample code.

There are several different ways you might deploy a CloudFormation stack to AWS. These include using IDE plug-ins, running as part of a build pipeline, or even working manually in the console. In this course, until we get to the last section that covers deployment automation with CodePipeline, we’re using deployment scripts that you execute from the command line. We’re using these scripts to do the following:

  • Build versioned Lambda deployment packages and upload these to a stack-specific S3 folder
  • Upload CloudFormation templates and OpenAPI documents (if used) to the same S3 folder
  • Call the CloudFormation create-stack or update-stack commands to deploy the solution

Using scripts to call the CloudFormation stack commands is, I think, the best development option. This provides a repeatable deployment process and offers the flexibility to separately perform resource and code updates. As an added benefit, these scripts are easily adapted for the native build pipeline that we cover later in the CodePipeline section. This scripted approach is what we’ll step through in this tutorial.

Deployment Scripts Overview

For each variant and API version of the sample code, you’ll see that there are four scripts: a shared config.zsh script that sets configuration values; a clean.zsh script that deletes previously uploaded files; a build.zsh script that compiles the Lambdas and uploads its deployment package to S3; and a deploy.zsh script that calls the create or update stack commands for CloudFormation.

Separating the build and deployment steps like this allows you to skip the build step if you want to update resources but don’t have any associated code changes. Note as well that throughout the sample code, wherever there are scripts, both Z shell and PowerShell versions are provided. We’re going to step through the Z shell scripts here, but the PowerShell scripts all have the same file names and are functionally identical. We’re also working with the .Net solution in this section, but again, the scripts are almost identical in the Java sample code.

Now let’s step through these scripts, one-by-one.

Setting Variables with the Config Script

Anywhere in the sample code where there are related scripts in a folder, there’s also usually a shared config script that’s referenced from the other scripts. Here’s the config.zsh script for the SAM deployment, where you can see that the variables on lines 6-13 correspond to the input parameters in the CloudFormation master.yaml template:

Deleting Uploaded S3 Files with the Clean Script

The first of our executable scripts is the clean.zsh script, which deletes any uploaded files from the target folder in the S3 bucket. You’ll note the reference to the config.zsh script on line 3:

Packaging & Uploading Lambdas with the Build Script

With the build.zsh script for the .Net version of the solution we’re running two commands, as shown below:

First, on lines 11-14, we’re running the Lambda tools dotnet command to compile and package the Lambdas in the ConnectedCar.Lambda project. Second, we’re using the S3 copy command on lines 22-24 to upload the zip file for the Lambda deployment package to the target S3 folder.

Triggering Lambda Updates

You’ll note that on line 24 we’re appending a version string to the zip file for the Lambda deployment package, whose S3 target URL is referenced in the CloudFormation templates. This string is entirely arbitrary and is not referenced by the Lambda service in any way. Basically, this is a trick that enables us to control whether the Lambdas in the deployed solution get updated or not when a stack is updated. When this version number (and therefore the referenced Lambda package file) is unchanged, CloudFormation will not trigger an update to the Lambdas when updating a stack. This lets you update other resources in the stack without having to build and upload the Lambdas. Conversely, by changing this version string, a CloudFormation stack update will trigger an update to the Lambdas, whether other resources have changed or not. We’ll step through different scenarios using this trick in the labs that follow.

Creating & Updating Stacks with the Deploy Script

The deploy.zsh script starts with a series of S3 copy commands to upload the five child templates to the same target folder as we use for the Lambda package zip files. On line 31, the script then checks to see if the configured stack name exists, and if not, executes the CloudFormation create-stack command, as shown below:

The four arguments for the create-stack command are itemized below:

  • Line 40: The “stack-name”, which is just the combined service and environment variable names
  • Line 41: The “template-body”, which points to the local master.yaml template file
  • Lines 42-47: A space-delimited list of parameter key/value pairs
  • Line 48: A list of the capabilities that the template requires to execute

The create-stack command does not block for the full CloudFormation stack creation process. Instead, it initiates the process and returns with either a template validation error or an ID for the newly created stack resource. This is why the script includes the “wait stack-create-complete” command, shown on lines 50-51. This second command blocks script execution until the deployment process has successfully run all the way to completion, or has failed and rolled back.

If the check on line 31 to see if the stack already exists returns true, then the else block shown below executes. First, there’s a stack query on lines 61-64, which allows us to pass the existing domain parameter to the update-stack command (we’ll cover queries like this in the labs). The update-stack command on lines 66-75 has the same arguments as the create-stack command outlined above.

Lastly, there’s another stack query performed on lines 88-91, which writes the stack outputs to the console in table format. This provides information, such as the generated API IDs or the Cognito User Pool ID, that’s needed to set up a client application like Postman to test the stack.