The purpose of the following code examples and demos is to introduce the reader to the basic usage of Packer and Terraform by deploying an example, real (sort of, at least...) service in AWS.
The full, final Packer and Terraform configuration can be found here. In particular, note that some demos (the *.cast files available here) might be hard to watch in a browser due to the JS player limitations. In which case, they can be downloaded and played with asciinema offline player.
The objective of the below demonstration is to deploy a service which will serve nginx default page.
Demo:
Before writing Terraform config for the actual service, let's get acquainted with basic usage of the tool.
A common flow for a user to introduce any changes into the infrastructure managed by Terraform is to clone the config repository, make the changes in the config, initialize Terraform, and run plan and apply.
Demo:
A slightly less common use case is to destroy either the whole infrastructure or some of its elements.
Note that selective destruction is out of scope of these examples.
Demo:
Now, after getting acquainted with the basic usage, let's proceed with preparing the nginx default page service.
The new code contains the EC2 (the AWS virtual instance) definition as well as entries for private network entities which will be used as the network context for the new instance.
Note the multiple files in this example. Terraform collects and uses all files in a current directory which end with .tf, which gives a freedom in splitting up the service configuration.
Demo:
Unfortunately, the infrastucture created in the previous step lacks any public endpoint. Let's fix this by adding an EIP (AWS Elastic IP) definition and reapplying.
Comparison with previous version.
Demo:
The EIP has been created in the previous example, but we don't have any immediate way of knowing it. As an alternative of logging in to AWS Console to check what it is, we can add an output definition.
This time, the infrastructure doesn't change, so we just need to refresh the Terraform state to obtain the IP.
Comparison with previous version.
Demo:
Before the next step, which would be the introduction of multiple instances of our nginx default page endpoints, we need to do some softcoding of the values used in the config. Terraform provides variable config items for this purpose.
Comparison with previous version.
No demo, since functionally nothing changes.
Now it's time for multiple nginx-default-page instances! Terraform allows creating multiple instances of an object by providing count metaparameter.
Note that lots of things are changing when running apply. Terraform is able to detect that for instance the existing subnet doesn't have to be recreated, however that's not the case with the existing instance, which is created anew. This could be mitigated by manually adjusting the terraform state, however that's out of scope of this demonstration.
Comparison with previous version.
Demo:
The last step is to modularize the network configuration, which can be then reused for other, more serious services.
Superficially, a lot has changed since the last example, however note that this is mostly due to moving vpc.tf to modules/basic-vpc/main.tf. The biggest conceptual change is to encapsulate the VPC objects and provide the input and output definitions for the module (with modules/basic-vpc/variables.tf and modules/basic-vpc/outputs.tf, respectively).
Unfortunately, Terraform will destroy and recreate almost everything in this case. Again, in real life this could be prevented by tinkering with the Terraform state.
Comparison with previous version.
Demo: