Rolling update EC2 with Terraform
Tags: terraform, packer, devops, aws
Published: 2020-09-27 22:18:58

This post is just an implementation of [@endofcake's](https://medium.com/@endofcake) [article](https://medium.com/@endofcake/using-terraform-for-zero-downtime-updates-of-an-auto-scaling-group-in-aws-60faca582664). I'm going to show a real example on how to use the rolling update technique with EC2. If you want to get more background about the difference between Rolling Update and Blue/Green please check his post.

{% medium https://medium.com/@endofcake/using-terraform-for-zero-downtime-updates-of-an-auto-scaling-group-in-aws-60faca582664 %}

#<center>🚨Warning🚨</center>

###Extreme rolling techniques ahead. Proceed with caution.
![rolling](https://media.giphy.com/media/BL6Jq3lI1jHeU/giphy.gif)

Terraform can do Blue/Breen natively, just add `create_before_destroy = true` in the [lifecycle block](https://www.terraform.io/docs/configuration/resources.html#lifecycle-lifecycle-customizations) and the terraform will create the resource in a blue/green manner.

```terraform
resource "azurerm_resource_group" "example" {
  # ...

  lifecycle {
    create_before_destroy = true
  }
}
```
<figcaption>Fig.1 - Lifecycle block example.</figcaption>

In other to show this update I decided to create a really simple web page using Packer to create the images.

### Speed things up with Packer

Before we dive into how to create rolling updates with terraform let's talk a little about Packer.

HashiCorp [Packer](https://www.packer.io/intro#what-is-packer) aims to build automated machine images, which means, we can create scripts to configure images with our application inside, installing all the dependencies that our application needs.

In our example, we use Packer to build a very simple HTTP server. I created a simple script that will install Apache web server and create a web page with a specif background color ( you can choose the color, exciting isn't it? ).

{% gist https://gist.github.com/souzaxx/b0af82412d8489e4838273c9fa881254 file=basic-website.sh %}

To update the "version" of our application just change the color variable to any color of your preference. The default color of our web page is red.

```hcl
variable "color" {
  default = "red"
}
```
<figcaption>variable.pkr.hcl</figcaption>

I won't get into details of Packer in this post, but basically, Packer will create an EC2 instance, execute the `scripts/basic-website.sh` inside it, and take a snapshot of that instance, saving it as `rolling_update_{{timestamp}}`. The execution of this script is described in the `provisioner` block.

{% gist https://gist.github.com/souzaxx/b0af82412d8489e4838273c9fa881254 file=build.hcl %}

I know that isn't a good tutorial, but enough of Packer for now.

![enough](https://media.giphy.com/media/lUB49ZnxhLsZi/giphy.gif)

## Rolling Update with Terraform

Well, here's the fun part. Terraform has no way to do this. 

![rolling](https://media.giphy.com/media/pPhyAv5t9V8djyRFJH/giphy.gif)

Terraform has no way to know if your application is alive nor to check what is the current version; because it was not built for this purpose.

Although we can configure health-checks on Targets Groups and Auto Scaling Groups, Terraform will not care if the application is healthy after finishing the apply phase.

In other to create the rolling update with Terraform we are going to use a little hack... We are going to use CloudFormation!

![isThatSo](https://i.imgflip.com/zxlb8.jpg) 

CloudFormation gives to Auto Scaling Group a really cool feature, the **UpdatePolicy**. This is a policy that is triggered every time that ASG is updated, which means if we launch a new version of a launch template we can trigger our ASG to update its instances.

We can take advantage of this CloudFormation automation and blend it into Terraform!

![fusion](https://media.giphy.com/media/TbYgHMnICI1A4/giphy.gif)

Ok, Lucas, [@endofcake](https://medium.com/@endofcake) already explains all this to us.

Less talk and more code.

![start](https://media.giphy.com/media/l2JecCAExsqUC4HDy/giphy.gif)

First, clone this git repository:

{% github souzaxx/Rolling-Update-Terraform no-readme %}

Create our first AMI going inside the `packer` folder.

```bash
cd packer
packer build .
```

### Wait until the AMI is created

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5e1d7y5s3918ol22wp26.png)

After that, go back to the root of the repository and apply the terraform.

```bash
cd ..
terraform init
terraform apply
```

To check that our web page is up and running gets the LoadBalancer DNS from Terraform output `terraform output lb_dns` and open it in your favorite browser or just curl it `curl $(terraform output lb_dns)`.

### Update the Image

In other to check the update progress, execute this loop in another terminal:

```bash
while true; do
curl $(terraform output lb_dns)
sleep 1
done
```

Now, create a new "version" of our application by choosing a color. You can overwrite the default variable passing `-var 'color=green'` into the packer CLI.

```
cd packer
packer build -var 'color=green' .
```

Wait for its completion and apply the terraform again:

```bash
cd ..
terraform apply
```

We can check that `lauchconfiguration` and `cloudformation` resources have changed.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/v9mgy54emkuq7fth7w3z.png)

Confirm the apply and check the curl loop to see the changes in realtime.

![final](https://dev-to-uploads.s3.amazonaws.com/i/u3x03istrtxyza0rcw2x.png)

# Conclusion

I hope this post was useful for your studies in Terraform and in my next post I want to show this process with a real application such as Consul.

## Clean up

```
terraform destroy --auto-approve
```

and delete all the AMI created by Packer:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8l8hytsh28jbjfonqdf8.png)

Thank you for your time and

![Alt Text](https://media.giphy.com/media/js0dt5JLCU01bvlt7d/giphy.gif)