More reflections from a terraform n00b

There are many posts out there talking about how to use Hashicorp's Terraform, and a number of them describing some of the things people learned as they were just beginning to use the product.  It's still early enough in its life cycle that these are useful. One came a few weeks ago from Charity, and I am adding the few things I've learned as an addendum to that.

Once you have a functional Terraform environment, there are a few things that can help you level up your game. You start thinking about how to get something that can be safely modified by a larger team and how to use your revision control to safely make changes to your environment in a way that you can test.

Multiple State Files
It is not at all uncommon to have multiple state files (aka multiple terraform ... I don't have a good word for it). This is even recommended by Hashicorp in some of their Atlas documentation. Common uses are
  • multiple copies of your environment (eg production, staging, etc.)
  • federation of responsibility (each team manages their own service)
  • protection (you're not making changes to the terraform config for all resources when changing only some. This is especially true for qa/dev/prod or global config vs. specific service config). 
  • refreshing large state files can have a significant performance impact, so splitting your installation into multiple states can be beneficial as your infrastructure grows.

Reusing Modules
Modules can be reused within a single .tf file. The module "name" is the definition of the local instance of that module; the module source is what determines what module to use. This was surprising to me because I thought module paralleled resource, where the first argument is the type of resource (the first argument would be the module name). This is not so - the only argument of module is more akin to the second argument to resource, giving it a local name. It's totally fine (and common) to say module "foo1" {source="./foo"}, module "foo2" {source="./foo"}, changing some other variable to make the two uses of the module different.

Promoting Changes using Modules
The module source can be a github repo for external modules (terraform get will download them) and they can also be github URLs at a specific revision (of your own or remote modules) to assert a specific version of a module. You can use multiple versions of the same module within one terraform instance, allowing you to promote changes from dev to qa to prod within a single terraform state. Note, of course, that doing this means that you have to run terraform get every time you update a module, whereas when using file paths to your modules, they're just symlinks so all changes are immediate.

For example, your dev environment can have source="github.com/...?ref=master" while your staging and prod .tf files can use source="github.com/...?ref=abcd1234" (or a git tag or branch) to avoid getting all the new changes until you're ready.

Overall Impression
It's been lovely getting to play with all these AWS resources that I'm used to mucking with by hand in a structured, automatable way. Though there are some strange bits to the configuration files (you can nest quotes! it's weird.), you get used to them quickly enough. I will bet that this product goes through radical change over the next year or two (in a manner similar to how the Chef community grew a few years ago) and I look forward to seeing it (and helping it) mature.

No comments: