<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrey Berezhinsky</title>
    <description>The latest articles on DEV Community by Andrey Berezhinsky (@moleculeman).</description>
    <link>https://dev.to/moleculeman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F146713%2F99fc573a-b167-4bed-8d40-a0d56100c222.jpeg</url>
      <title>DEV Community: Andrey Berezhinsky</title>
      <link>https://dev.to/moleculeman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moleculeman"/>
    <language>en</language>
    <item>
      <title>Lessons learned from 4 years of working with cloudformation</title>
      <dc:creator>Andrey Berezhinsky</dc:creator>
      <pubDate>Tue, 26 Mar 2019 13:53:42 +0000</pubDate>
      <link>https://dev.to/moleculeman/lessons-learned-from-4-years-of-working-with-cloudformation-n72</link>
      <guid>https://dev.to/moleculeman/lessons-learned-from-4-years-of-working-with-cloudformation-n72</guid>
      <description>&lt;p&gt;I started working with cloudformation 4 years ago. Since then I screwed up many pieces of infrastructure. Some of them were in production. But every time I screwed up something I learned something new as well. Thanks to my ignorance 4 years later I can share some of the most important lessons I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 1: verify changes before deploying changeset
&lt;/h2&gt;

&lt;p&gt;I learned this lesson pretty early in my journey with cloudformation. I don't remember exactly what have I broken but I remember that I was using &lt;code&gt;aws cloudformation update&lt;/code&gt; command to deploy my stacks back then. This command just rolls out your template without any kind of verification of the changes to be deployed. I don't think it requires explanation that you need to verify that you understand what you are about to deploy.&lt;/p&gt;

&lt;p&gt;After that screw up I immediately changed my deployment pipeline by replacing &lt;code&gt;update&lt;/code&gt; command with &lt;code&gt;create-change-set&lt;/code&gt; command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# OPERATION is either "UPDATE" or "CREATE"&lt;/span&gt;
&lt;span class="nv"&gt;changeset_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws cloudformation create-change-set &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHANGE_SET_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stack-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STACK_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--template-body&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TPL_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-type&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OPERATION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--parameters&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PARAMETERS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--output&lt;/span&gt; text &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--query&lt;/span&gt; Id&lt;span class="si"&gt;)&lt;/span&gt;

aws cloudformation &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    change-set-create-complete &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$changeset_id&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When changeset is created it doesn't affect the existing stack in any way.  Unlike the &lt;code&gt;update&lt;/code&gt; command the changeset approach doesn't cause the actual deployment. Instead it creates list of changes that you can review before the actual deployment. You can view the changes in the aws console gui. But if you have automate-everything mentality then probably you would prefer checking them in you cli:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# this command is presented only for demonstrational purposes.&lt;/span&gt;
&lt;span class="c"&gt;# the real command should take pagination into account&lt;/span&gt;
aws cloudformation describe-change-set &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$changeset_id&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'Changes[*].ResourceChange.{Action:Action,Resource:ResourceType,ResourceId:LogicalResourceId,ReplacementNeeded:Replacement}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--output&lt;/span&gt; table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command should produce an output similar to the following one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--------------------------------------------------------------------
|                         DescribeChangeSet                        |
+---------+--------------------+----------------------+------------+
| Action  | ReplacementNeeded  |      Resource        | ResourceId |
+---------+--------------------+----------------------+------------+
|  Modify | True               |  AWS::ECS::Cluster   |  MyCluster |
|  Replace| True               |  AWS::RDS::DBInstance|  MyDB      |
|  Add    | None               |  AWS::SNS::Topic     |  MyTopic   |
+---------+--------------------+----------------------+------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay a special attention to the changes where &lt;code&gt;Action&lt;/code&gt; is &lt;code&gt;Replace&lt;/code&gt;, &lt;code&gt;Delete&lt;/code&gt; or where &lt;code&gt;ReplacementNeeded&lt;/code&gt; is &lt;code&gt;True&lt;/code&gt;. Those are the most dangerous changes and usually cause some data loss.&lt;/p&gt;

&lt;p&gt;When the changes are reviewed they can be deployed with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cloudformation execute-change-set &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$changeset_id&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;operation_lowercase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OPERATION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'[:upper:]'&lt;/span&gt; &lt;span class="s1"&gt;'[:lower:]'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
aws cloudformation &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="s2"&gt;"stack-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;operation_lowercase&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-complete"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stack-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STACK_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lesson 2: use stack policy to prevent replacement or deletion of statefull resources
&lt;/h2&gt;

&lt;p&gt;Well, sometimes simply reviewing changes is not enough. We are all humans and we all make mistakes. Soon after we started using changesets teammate of mine unknowingly performed deployment which caused database to be recreated. No harm was done as it was testing environment. Even though our scripts were showing list of changes and were asking for confirmation the &lt;code&gt;Replace&lt;/code&gt; change was overlooked because the change list was so big it was not fitting to the screen.  And as it was a routine update in testing environment not so much attention was paid to the changes.&lt;/p&gt;

&lt;p&gt;There are resources that you never want to be replaced or deleted. Those are statefull services like RDS database instance or elastichsearch cluster etc.  It would be nice if aws would automatically deny deployment if the performed operation would require deletion of such a resource. Fortunately cloudformation has a built-in way of doing this. It's called stack policy and you can read more about it in &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html" rel="noopener noreferrer"&gt;the docs&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;STACK_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;RESOURCE_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;

&lt;span class="nv"&gt;POLICY_JSON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
{
    "Statement" : [{
        "Effect" : "Deny",
        "Action" : [
            "Update:Replace",
            "Update:Delete"
        ],
        "Principal": "*",
        "Resource" : "LogicalResourceId/&lt;/span&gt;&lt;span class="nv"&gt;$RESOURCE_ID&lt;/span&gt;&lt;span class="sh"&gt;"
    }]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

aws cloudformation set-stack-policy &lt;span class="nt"&gt;--stack-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STACK_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stack-policy-body&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$POLICY_JSON&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lesson 3: use UsePreviousValue when updating stack with secret parameters
&lt;/h2&gt;

&lt;p&gt;When you create RDS mysql instance aws requires you to provide &lt;code&gt;MasterUsername&lt;/code&gt; and &lt;code&gt;MasterUserPassword&lt;/code&gt;. As it's not an option to store secrets in the source code and as I wanted to automate absolutely everything I implemented a "clever mechanism" where prior to deployment credentials would be retrieved from s3 and if credentials wouldn't be found the new credentials would be generated and stored in s3. These credentials then would be passed as parameters to cloudformation create-change-set command. While experimenting with the script it happened once that connection to s3 was lost and my "clever mechanism" treated it as a signal to generate new credentials. If I would start using this script in production and this connection problem occurred again it would update the stack with new credentials. In this particular case probably nothing bad would happen.  However I anyways abandoned my "clever mechanism" and started using less clever approach of providing credentials only once - when the stack is created. And later on when the stack would require an update I would rather than specifying secret parameter value just use &lt;code&gt;UsePreviousValue=true&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cloudformation create-change-set &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHANGE_SET_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stack-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STACK_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--template-body&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TPL_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-type&lt;/span&gt; &lt;span class="s2"&gt;"UPDATE"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--parameters&lt;/span&gt; &lt;span class="s2"&gt;"ParameterKey=MasterUserPassword,UsePreviousValue=true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lesson 4: use rollback configuration
&lt;/h2&gt;

&lt;p&gt;The other team at my working place started to use cloudformation feature called rollback configuration. I never saw it before and quickly realized that it would make the deployment of my cloudformation stacks even more bulletproof. Now I use it whenever I deploy my code to lambda or ECS via cloudformation. Here how it works: you specify cloudwatch alarm arn in the &lt;code&gt;--rollback-configuration&lt;/code&gt; parameter when you create changeset. Later on when you execute the changeset aws monitors this alarm for at least one minute. It rolls the deployment back if during this time alarm changes state to &lt;code&gt;ALARM&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example excerpt of cloudformation template where I create a cloudwatch alarm which monitors custom cloudwatch metric of number of errors in the cloudwatch logs (metric is created via MetricFilter):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# this metric tracks number of errors in the cloudwatch logs. In this&lt;/span&gt;
  &lt;span class="c1"&gt;# particular case it's assumed logs are in json format and the error logs are&lt;/span&gt;
  &lt;span class="c1"&gt;# identified by level "error". See FilterPattern&lt;/span&gt;
  &lt;span class="na"&gt;ErrorMetricFilter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Logs::MetricFilter&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;LogGroupName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;LogGroup&lt;/span&gt;
      &lt;span class="na"&gt;FilterPattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{$.level&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"error"}'&lt;/span&gt;
      &lt;span class="na"&gt;MetricTransformations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;MetricNamespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${AWS::StackName}-log-errors"&lt;/span&gt;
        &lt;span class="na"&gt;MetricName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Errors&lt;/span&gt;
        &lt;span class="na"&gt;MetricValue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
        &lt;span class="na"&gt;DefaultValue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

  &lt;span class="na"&gt;ErrorAlarm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::CloudWatch::Alarm&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AlarmName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${AWS::StackName}-errors"&lt;/span&gt;
      &lt;span class="na"&gt;Namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${AWS::StackName}-log-errors"&lt;/span&gt;
      &lt;span class="na"&gt;MetricName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Errors&lt;/span&gt;
      &lt;span class="na"&gt;Statistic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Maximum&lt;/span&gt;
      &lt;span class="na"&gt;ComparisonOperator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GreaterThanThreshold&lt;/span&gt;
      &lt;span class="na"&gt;Period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# 1 minute&lt;/span&gt;
      &lt;span class="na"&gt;EvaluationPeriods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;Threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
      &lt;span class="na"&gt;TreatMissingData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;notBreaching&lt;/span&gt;
      &lt;span class="na"&gt;ActionsEnabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now this alarm can be used as rollback trigger when the changeset is executed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ALARM_ARN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;

&lt;span class="nv"&gt;ROLLBACK_TRIGGER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
{
  "RollbackTriggers": [
    {
      "Arn": "&lt;/span&gt;&lt;span class="nv"&gt;$ALARM_ARN&lt;/span&gt;&lt;span class="sh"&gt;",
      "Type": "AWS::CloudWatch::Alarm"
    }
  ],
  "MonitoringTimeInMinutes": 1
}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

aws cloudformation create-change-set &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHANGE_SET_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stack-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STACK_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--template-body&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TPL_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-type&lt;/span&gt; &lt;span class="s2"&gt;"UPDATE"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--rollback-configuration&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROLLBACK_TRIGGER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lesson 5: make sure you are deploying the latest version of the template
&lt;/h2&gt;

&lt;p&gt;It's very easy to deploy not the most up-to-date version of the cloudformation template and cause a lot of damage. In fact this happened in our team: developer hasn't pulled the latest changes from git and unknowingly deployed the previous version of the stack. This caused some downtime in the application that was using this stack.&lt;/p&gt;

&lt;p&gt;Something as simple as adding check if you branch is up-to-date with remote before executing deployment will do just fine (assuming git is your version control tool):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch
&lt;span class="nv"&gt;HEADHASH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;UPSTREAMHASH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse master@&lt;span class="o"&gt;{&lt;/span&gt;upstream&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HEADHASH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$UPSTREAMHASH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
   &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Branch is not up to date with origin. Aborting"&lt;/span&gt;
   &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lesson 6: don't reinvent the wheel
&lt;/h2&gt;

&lt;p&gt;It might look like deploying the cloudformation is straightforward. You just need bunch of bash scripts executing aws cli commands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkyyfqsq80sy159b2vgin.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkyyfqsq80sy159b2vgin.jpg" alt="Well yes, but actually no"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Four years ago I started with a simple script that just called &lt;code&gt;aws cloudformation create-stack&lt;/code&gt; command. It was not long afterwards when the script was not simple anymore. Each lesson learned caused the script to go more and more complex. It was not only complex it was also buggy. I noticed only long afterwards that the command presenting changeset changes wouldn't return complete set of changes when the output was too large.&lt;/p&gt;

&lt;p&gt;I'm working in a relatively small IT department. As it turned out - not surprisingly - every team has invented its own way of deploying the cloudformation stacks. It's definitely a bad thing. We could do better and not reinvent the same thing independently. But this already happened and probably happens in other teams as well. Right now we are migrating to the unified way of deployment and it does take bigger effort than I originally thought. I wish that our teems agreed on the one deployment tool from the beginning.&lt;/p&gt;

&lt;p&gt;Fortunately there are lots of tools that help with deploying and configuring cloudformation stacks. In fact I've written one of such tools myself. It's called &lt;a href="https://github.com/molecule-man/stack-assembly" rel="noopener noreferrer"&gt;stack-assembly&lt;/a&gt; and it was written with all those mentioned lessons in mind.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudformation</category>
      <category>cli</category>
    </item>
  </channel>
</rss>
