Advanced CloudFormation Skills
The course is part of these learning paths
As AWS-based cloud environments grow in complexity, DevOps Professionals need to adopt more powerful tools and techniques to manage complex deployments. In the AWS ecosystem, CloudFormation is the most powerful and sophisticated automation tool available to developers. In this course, we explore some of the most advanced CloudFormation skills AWS engineers can learn.
In addition to normal templated resource generation for single stacks using CloudFormation, engineers will learn how to:
- Develop continuous integration and continuous deployment on CloudFormation
- Tie into CloudFormation system events via SNS for operational tasks
- Nest multiple levels of CloudFormation stacks to build out massive cloud systems
- Author CloudFormation Custom Resources to add additional functionality and resource types to stacks
This course is best taken after reviewing the basics of CloudFormation with CloudAcademy's starter course How To Use AWS CloudFormation.
The AWS CloudFormation templates and related scripts as demonstrated within this course can be found here:
Today we'll be talking about the true nature of CloudFormation, and a way to reason about the system so that we can learn further advanced topics. First, let's talk about how CloudFormation actually achieves the create, update, and delete actions when we work with stacks.
It's important to know that a stack is effectively a state machine inside of CloudFormation. How does this work? Well, CloudFormation acts as the transition function that changes templates and parameters into a stack during a create operation, templates, parameters, and the present stack into the next stack iteration, and transforms the present state of the current stack into nothing. That is, deleting it. Why is this important? Well, it helps us to model our stack creation, not as some magical process, but to think of it as taking two inputs, running through the CloudFormation service itself as a function, or rather the CloudFormation create operation that produces a stack.
When we do an operate operation, it's important to understand that we not only get the original parameters and template that are coming in, but we also get this present state of the stack. That is, CloudFormation needs all three of these things to go through and do an update. We need the two new inputs and the present state to produce the new state. We also need the present state to delete, which should be pretty clear.
Now, this is pretty a complicated operation, but the entire benefit of CloudFormation is that it reads our JSON templates, understands the dependencies between each of the resources in the system, then invokes the transition functions for each resource in the stack, and propagates it until the very last resource that depends on the most recent other updated resource is finished.
So when I trigger a create over here in CloudFormation, it first figures out from the template the appropriate resource to create first. That would be a resource that does not depend on any other resources in the stack. It will create that resource by doing a signal of a create to the resource, then create the next resource that depends on that resource, etc.etc.
There are also some optimizations where CloudFormation will create two resources in parallel if that is appropriate, and they don't have any dependencies on each other. Same for update and delete. However, in the update function, we also receive this third parameter, which is the present state of the stack. It is important for the update cycle to have the present stack value because CloudFormation needs to know how to modify some existing resources to create the new stack state. Or in cases where we do a full replacement operation, CloudFormation needs to know how to create the new value of the stack based on the template and parameters, but also delete the present stack based on the old values. Then during the delete cycle, CloudFormation needs the present state of the stack in order to delete everything and reduce the stack to nothingness.
Now, why is this important that we understand how the CloudFormation service itself acts as a state transition function? Well, because this is very similar to how resources behave. This slide should look pretty familiar after looking at the stack state machine slide before. This is because resources follow a very similar life cycle model to stacks, having create, update, and delete actions themselves.
As we can see, similar to the stack create function, we go from a user-defined list of properties through some logic and produce a new resource in the create cycle. In the update cycle, we see that we take some user-defined properties as well as the previous state, feed it into some custom logic, and we see another fresh resource. And again, delete is almost identical to the stack life cycle in that there is a resource, some logic that it runs through, and then nothing.
As I was saying on the previous slide, these resource provider logic functions are CloudFormation or user-defined functions that take a properties object defined in the resources block of the template, operate over it with some logic, and then produce actual resources, which can then be referred to elsewhere in the template using the ref function or fn.getAttributes.
The create action within a resource is invoked whenever we are creating a new stack or an existing stack that is being updated sees a new logical resource ID within the resources block. The update function for resources is invoked during stack updates whenever we change a property on a resource, or we change a dependent resource of a property. For example, the update function will run for any subnet if the underlying VPC has been updated. This does not necessarily mean that the underlying resource represented by the subnet inside of the template will be changed. It simply means that the update function operates over the subnet and checks if there needs to be any updates done. If no updates are found, CloudFormation will just return a success code and do no operations during an update. That is, there are many cases in which previous resource is exactly equal to the fresh resource.
The delete action is invoked on resources whenever we are deleting a stack or we are doing a full replacement operation on a resource in a stack during an update. This second kind of delete happens during the update complete cleanup in progress stack status. This second form of delete that happens during the update cleanup phase is important to clean resources that are no longer needed after a stack update, which produces new resources.
For example, if we have a stack in which we model a VPC and a subnet and we change the underlying VPC to map to a different CIDR block, then the VPC will be fully replaced. Because subnets belong to VPCs, the subnet will also be updated in order to fully replace it and move it over to the other VPC.
During the first phase of an update that requires a full replacement of a resource, the update function will actually create a new fresh resource based off of the resource properties. During the second phase, it will then delete the unused resource later. This pattern of new resource creation then delete on full replacement updates is important because it enables us to make major changes to stacks with minimal downtime.
In summary, CloudFormation resources are implemented via a resource provider logic function, which understands create, update, and delete. Depending on which action is being invoked, the different properties will be provided to this resource provider logic.
In most cases, the resource provider logic is defined by the CloudFormation team itself. In some cases, we can author our own resource provider logic in order to extend the functionality of CloudFormation.
Later in the course, we will go over how to create your own custom resource provider logic functions in order to define custom resources that can be used in templates. When we do this, we will also use something called a service token. When using built-in CloudFormation resources, the service token is already known to the CloudFormation template since it's a built-in resource.
When creating or utilizing a custom resource, the service token defines either the SNS topic that the custom resource should post its properties to, or the lambda function that the custom resource should submit its property to for event processing when it's time to run the resource provider logic itself.
That about wraps it up for our advanced discussion of how CloudFormation actually works internally. Next up, we'll be discussing how to tie into the fronts and backs of these different resource life cycles by using SNS topics to create automation.
About the Author
Nothing gets me more excited than the AWS Cloud platform! Teaching cloud skills has become a passion of mine. I have been a software and AWS cloud consultant for several years. I hold all 5 possible AWS Certifications: Developer Associate, SysOps Administrator Associate, Solutions Architect Associate, Solutions Architect Professional, and DevOps Engineer Professional. I live in Austin, Texas, USA, and work as development lead at my consulting firm, Tuple Labs.