8 ms·
Terraform Gotchas and How We Work Around Them
- kalmar 9y agoHey author here! Happy to answer any questions etc :-)
- kingbirdy 9y agoYour site appears to be down, the connection is timing out for me
- toomuchtodo 9y agoNo questions, just a suggestion: implement the part where the terraform plan is added as a comment in the PR. We set this up at my current employer and it makes the review process much quicker (also, commenting on lines in the ~plan~ terraform code changes is the bee's knees). Don't have the apply be automatic after a review is approved; terraform apply's occasionally go sideways and need human intervention (remember: rollbacks are not automatic). A human should always kick off the apply and monitor state change activity.
- jfroma 9y agoI couldn't agree more with this, we do exactly the same and it works great for us. Plan on a comment and manual apply.
- kalmar 9y agoWoah can you comment on lines in a comment? /me dashes to investigate github And thanks for the suggestion. So far it's been on a someday maybe list, but if it really does help that much, maybe we'll bump it to someday maybe soon.
- captn3m0 9y agoQuestions from our team: - Are you commenting with the output of show on the planfile to get human-readable version? - Line by line commenting on comments? - Do you have state-splits? Do you run plan on each individually for every PR?
- toomuchtodo 9y agoMay I email you answers to these?
- captn3m0 9y agoYes, that works. (email in profile)
- cakeface 9y agoGreat post! I too had the issue with AWS volume attachments and the need to separate them out. Luckily it happened early during some of my first provisioning and we realized it before standing up more databases. I now have a policy where each server has a separate EBS volume, using a volume attachment Terraform resource, for any data. Inline EBS volumes are just used for the OS. I've run into another similar type issue now and I think that I'm going to have to do state surgery like you. I want to refactor some of my terraform resources into modules, but this changes the resource names. I can't see any way to do it without either standing up new infrastructure or modifying the state directly.
- sevagh 9y agoWe ran into similar issues. From there I went one step further and wrote a tool to do the attachments for me (instead of using Terraform's aws_volume_attachment): https://github.com/sevagh/goat https://github.com/sevagh/goat This way in Terraform I provision a group of volumes, a group of instances, and rely on `goat` to do the rest.
- kalmar 9y agoThat's pretty cool. So is the model that you don't manage the volumes in TF at all? (Btw I think I know people you know... also in Montreal and I know a couple folks at AdGear!)
- sevagh 9y agoThat's cool, I'll ask my coworkers. And yes this way I keep EBS and the rest of my recipes as far away as possible. Something like: ``` kafka-volumes/ <ebs volumes> terraform.tfstate kafka/ (use local backend ../kafka-volumes/terraform.tfstate) <ec2 instances> ```
- nodesocket 9y agoGreat post. I think the area where things start to go off the rails with Terraform is variables/modules though. There are edge cases and gotchas with modules and not a lot of best practice guides. Shameless plug, if anybody is looking for a guide on getting started with Terraform and Google Cloud Platform, I wrote a short blog post: https://blog.elasticbyte.net/getting-started-with-terraform-and-google-compute-engine/ https://blog.elasticbyte.net/getting-started-with-terraform-...
- OhSoHumble 9y agoShameless plug, if anybody wants to generate a Terraform module with a testing harness preconfigured then I hacked up a module scaffolder last night/this morning: https://github.com/howdoicomputer/terrashovel https://github.com/howdoicomputer/terrashovel
- stuff4ben 9y agoWe're using Terraform for our AWS env and while it worked great for getting stuff out there, we're now scrambling to figure out how to get Terraform to do non-destructive updates to the environment. For instance, I need to update our base OS for the application servers we're running. How do I do this without incurring a downtime? Or I need to now interject a new reverse proxy between our ELB's and app servers, but want to do it without causing an interruption. We're doing our research and this blog post is very helpful, but if you have any pointers...
- hnov 9y agoYou pretty much have to take the same approach as you would outside of terraform: create the new thing (launch configuration, standalone instance) and attach it to the ELB before spinning down the old one. Terraform does have some rudimentary aid to that end in the form of the create_before_destroy[0] flag, though it doesn't work out with uniquely named things. [0] https://www.terraform.io/docs/configuration/resources.html#create_before_destroy https://www.terraform.io/docs/configuration/resources.html#c...
- Thaxll 9y agoYou should use 2 ASG ( blue / green ) and 1 ELB for that, then when you need to update the OS of one of the ASG you just update the launch configuration. It's easy to do in Terraform. 1) Update the launch configuration of your un-used ASG ( with the new AMI ID ) 2) Apply terraform to deploy the new ASG 3) Make sure it's working ( your local app on your new instances ) 4) Connect the ELB to your new ASG 5) Set the old ASG to 0 instances to drain the connections
- mayank 9y agoThis is a pretty common question. Check out this blog post for how to get Terraform to bring up a new ASG with a new AMI before removing the old one from an ELB: https://robmorgan.id.au/posts/rolling-deploys-on-aws-using-terraform/ https://robmorgan.id.au/posts/rolling-deploys-on-aws-using-t...
- brazzledazzle 9y agoHave you tried Terragrunt[1]? [1] https://github.com/gruntwork-io/terragrunt https://github.com/gruntwork-io/terragrunt
- jen20 9y agoAll the useful things terragrunt does have been built in since Terraform 0.9. Disclaimer: ex-HashiCorp employee.
- wildfire 9y agoNot true. Terraform v0.9 only handles remote state and locking properly. Handling multiple applies of state is something scheduled for 0.10 Basically terragrunt handles some stuff today in a less robust, less portable, way that your team is likely to need today -- whilst waiting for core terraform support. (disclaimer: I follow terragrunt and terraform very closely but do not actually use terragrunt in producution anymore).
- anh79 9y agohi Kalmar, Is it possible to query information directly from a state file? Some interpolation would help. I ask this because I often refer to resource information from another project, and I don't see that modules are helpful. I posted my work-around here [1] some days ago . The real code was not there because I haven't had permission for my company, but it's very short and easy to write by anyone. Thanks for your reading. [1] https://github.com/icy/oops/blob/master/terraform/problem_1_output_without_output.md https://github.com/icy/oops/blob/master/terraform/problem_1_...
- nategri 9y agoSo... ahem what other idiots came here expecting a post about troubleshooting Martian habitability? ::Sulks off dejectedly::
- irfanka 9y agoAt least one :)
- jjtheblunt 9y agoat least two :)
- pugworthy 9y agoat least many!
- mtgx 9y agoNow that project would be cool to see.
- kej 9y agoWikipedia has a decent article if you've never read it: https://en.wikipedia.org/wiki/Terraforming_of_Mars#Challenges_and_limitations https://en.wikipedia.org/wiki/Terraforming_of_Mars#Challenge...
- sevagh 9y ago>Terraform state surgery Did you try to use `terraform state mv`? I've found that command useful (albeit for much less than thousands of resources).
- kalmar 9y agoI don't think it would work in this case, as the `ebs_block_device` block isn't a resource. In fact, the TF state doesn't even have the volume IDs for them! An alternative to doing this was `terraform import` on all the volumes, then defining attachments, and hoping it all worked when you run `terraform plan`. I don't 100% remember now why we didn't do that.
- luhn 9y ago> Always write your plan -out, and apply that plan I have in my dotfiles: alias tfplan='terraform plan -out=.tfplan -refresh=false' alias tffreshplan='terraform plan -out=.tfplan' alias tfapply='terraform apply .tfplan; rm .tfplan' That way I never accidentally `terraform apply` without creating a plan first. I also have it not refresh the state by default, which is mostly unnecessary and speeds up the planning significantly.
- kalmar 9y agoOh interesting. Note to self: see if there's an option to disable `terraform apply` without a plan. I always refresh when running the pre-apply plan, but while iterating I use that. Do you always run your `tffreshplan` command before applying?
- nodesocket 9y agoAgree would be nice to add a new option which prevents invoking `apply` without a supplied plan argument. Create an issue in the GitHub, I'll upvote.
- kalmar 9y agoHere's an issue: https://github.com/hashicorp/terraform/issues/15263 https://github.com/hashicorp/terraform/issues/15263
- RyanGWU82 9y agoMy muscle memory for "terraform apply" was too strong, so I just moved "terraform" out of my path altogether. Now I have a wrapper that invokes it safely (or a Makefile, depending on which project I'm working on).
- sethvargo 9y agoHey all - Seth here from HashiCorp (the company that makes Terraform). The next version of Terraform (0.10) natively adopts very similar behavior, presenting a plan before applying as an added safety step. You can read more in the 0.10 upgrade guide. At the time of this writing, 0.10 is not yet released, but compiling Terraform from source at master will inherit this behavior. https://github.com/hashicorp/terraform/blob/master/website/source/upgrade-guides/0-10.html.markdown https://github.com/hashicorp/terraform/blob/master/website/s...
- pavement 9y agoOh, geeze. This is about: terraform.io
- PhasmaFelis 9y agoYeah, a title change would be nice. I was anticipating something much more interesting.
- paulddraper 9y agoAnd I wanna hoverboard.
- vultour 9y agoIt would probably say Terraforming gotchas if it was about the other thing.
- irrational 9y agoHa! That was my first thought too. Where is the information about terraforming Mars?
- johnmarcus 9y agoI absolutely can't stand how destructive terraform is by nature. We have switched to Ansible, which has an excellent AWS module, and never looked back.
- smt88 9y agoWhy Ansible rather than Elastic Beanstalk or Cloud Formation?
- an27 9y agoIt's vendor-agnostic? And CF is super slow and limited to a small number of resources (not sure if it's a 100 or a 1000).
- paulddraper 9y agoDefinitely 100. And every little thing is a resource.
- 80x25 9y agohttp://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuid... Am I a missing something? Nothing in these docs about a 100 resource limit
- paulddraper 9y agoIt used to be 100. Looks like it's 200 now.
- 80x25 9y agoThat's 200 resources per CF template. That's a massive CF template :)
- tjbiddle 9y ago
- mental_ 9y agoI thought terragrunt was a must have for that kind of deployment.
- brazzledazzle 9y agoI'm curious about that as well. I was told by coworkers that Hashicorp added support for DynamoDB which rendered terragrunt redundant but I haven't had time to look into it.
- Florin_Andrei 9y agoterraform { backend "s3" { region = "us-west-1" bucket = "foo-tf-us-west-1" key = "foobar.tfstate" dynamodb_table = "tf-lock" } } https://www.terraform.io/docs/backends/types/s3.html#dynamodb_table https://www.terraform.io/docs/backends/types/s3.html#dynamod...
- tjbiddle 9y agoAwesome! Any idea when this was added? I feel like this wasn't in the documentation a week or two ago; everything had still said "Use Hashicorp Atlas for remote state locking".
- Florin_Andrei 9y agoI've been using it for weeks if not months. Their documentation might be lagging occasionally. It's a small team tackling a big challenge.
- 7ewis 9y agoTerraform has interested me for a while, and I've been meaning to give it a try, but haven't had a chance just yet. From what I have seen so far though, there isn't really that much difference/benefit over CloudFormation. We currently have 95% of our resources in AWS with about 4% in Azure, and 1% in Google Cloud. It's great that Terraform is 'mulit-cloud' but it still seems like you have to write .tf's catered to each cloud, you can't just lift and shift to another cloud by copying and pasting a file? People say the 'plan' feature is one of the advantages over CFN, but as far as I can tell, CFN now offers the same feature... it tells you what's going to change when you upload a new stack. I sound like a CFN advocate now, but I genuinely don't have that much experience with it, and really do want to give Terraform a chance. Convince me? Oh, and since CFN started supporing YAML it looks easier to write too
- philsnow 9y agoCloudFormation has a lot of things going for it, but it was unsuitable for us ~18 months ago when I was looking around for a way to "infrastructure as code"-ify our setup, because it can't "adopt" existing resources into your setup, and we have tons of stuff we don't want to bring down/up just to bring under cloudformation. I used the terraforming gem (either because "terraform import" didnt' exist at the time, or because I just didn't like the way it worked) to bring a lot of things under management by terraform.
- mayank 9y ago> It's great that Terraform is 'mulit-cloud' but it still seems like you have to write .tf's catered to each cloud, you can't just lift and shift to another cloud by copying and pasting a file? We're not quite at the point where even the "comparable" cloud services across clouds are drop-in compatible with each other, so this is not going to be possible for a while for reasons not related to Terraform. > I sound like a CFN advocate now, but I genuinely don't have that much experience with it, and really do want to give Terraform a chance. Convince me? You could spend your time learning either a vendor-specific tool (CFN), or a vendor agnostic one (Terraform). Since Terraform can do a lot of what CFN does, it may make sense to spend your time learning Terraform instead. Edit: not sure about CFN, but Terraform is open source: https://github.com/hashicorp/terraform https://github.com/hashicorp/terraform
- philsnow 9y agoThere's another similar issue with how EC2 security group rules are encoded: you can encode them either as ingress/egress stanzas on an "aws_security_group" resource, or you can attach rules to a security group resource with separate "aws_security_group_rule". You can't mix the two approaches on a single security group resource. We adopted the ingress/egress stanza on security group resource approach. If we ever wanted to change to the other approach (as described in the article), I don't think I would do state surgery by hand or even use "terraform state mv". I would: 1. change terraforming to generate .tf files and tfstates the way I want 2. remove the security groups from my config and my state 3. use terraforming to regenerate the .tf files and tfstate
- Florin_Andrei 9y agoYeah, this is a universal theme with Terraform resources. If you can choose between a "con todo" description that lumps together resources and subresources, versus describing every single little thing separately and then attaching them together, always use attachments.
- mitchellh 9y agoHey there. Disclaimer: one of the creators of Terraform I wanted to apologize that this is super confusing. All the scenarios where this exists (there are many) are historical. We originally went with the "nested" approach and now prefer the "split" approach for good reasons shown to us by users. But we kept both for backwards compatibility reasons. We have no good mechanism to enforce a migration at the moment. There are a couple ways we can resolve this technically in the future. For now, we should probably make sure the docs are annotated in all situations of the limitations of nested vs. standalone. I'll mention this to the team!
- nunez 9y agohere's something i got bit by more recently re: terraform plan -out and tooling using Terraform's Golang API. Handling package dependencies with Go is not straighforward. There are several ways of doing it, and none are native to Golang. Additionally, Go doesn't support getting versions of packages by tag or branch. This bit me hard when I tried to update Palantir's TFJSON utility (turns tfplan binaries into json) so I could do unit testing of my Terraform plans with rspec. The utility depended on v0.7.4 of terraform, but Terraform maintains a plan format constant that defines which plans can be used by what versions. They changed the plan format between 0.7.4 and 0.9.8 without bumping that constant, so when I tried running tfjson against plans created by the latter version, I got a weird non-matching datatype error that took a while to figure out. (I eventually had to vimdiff the hex outputs of plans created by both versions to figure that out.) Additionally, HashiCorp made a significant change to the way they handled providers between 0.9.8 and 0.10.0 that justified them to bump the plab format version AGAIN. The catch: 0.10.0 isn't released yet, despite that being the code in their master branch. I figured that updating tfjson's vendored terraform library to 0.9.8 would solve it. I first did a go get to fetch the latest TF codebase and used gvt to vendor it. That's when I discovered that plans generated by 0.9.8 are no longer compatible. After discovering that go get can't fetch packages by tag (Hashicorp tags their release commita) because Google believes in stable HEADs, I had to find a tool that could support fetching packages by tags. Govendor did that, so I used that. It takes FOREVER to fetch all of the subpackages used by terraform. I couldn't do it during a three hour flight. Rubygems has its problems, but fetching deps isn't one of them. And even when I thought I fetched the entire source tree at v0.9.8, I would still get errors about missing types or missing packages. I'm hopeful that I'll eventually find a solution, but it's a dog compared to using Gemfile.lock.
- ian_d 9y agoI've been using terraform for a couple of months now (love it), but honestly our biggest pain was just project organization. It looks like a lot of people make a file per-resource type (elb.tf, ec2.tf, rds.tf) but we thought that would be a lot of bloat. We opted to have a file per system (dev_db.tf, dev_ecs_asg.tf, dev_haproxy.tf, etc) and everything related to that particular system is contained in a single file (security groups, dns entries, roles/profiles, etc). But it's still in one flat directory per environment. (I know tf has introduced environments, but we haven't switched over yet.) I know you can hack this together with modules, but it seems like environment/project organization would be easier if terraform just recursed subdirectories. Right? I've seen a couple of issues for it, but I don't believe I've seen a concrete reason why it's a no-go.
- lobster_johnson 9y agoI've wanted, and tried and failed, to adopt Terraform several times now. What always gets in my way is that we already have all our infrastructure in place, and Terraform's import capabilities are too limited. For example, the last time I used it, a few months ago, it was not able to import almost any of our Google Cloud stuff, and I discovered that import support is only provided for some resources. There's a third-party tool called Terraforming, but it apparently only works with AWS. I'm quite disheartened that the world is lagging this far behind. The only competitor I've found is Salt, and I found its orchestration support to be a bit of a mess. And just as with Terraform, the code is constantly lagging behind the providers. The one provider I'd have expected to be on the forefront of orchestration is Google, and in a different multiverse their engineers are swarming around Terraform to make sure it has top-notch, official, first-class support, but alas, not in this one. Are there any competitors that provide a smoother experience?
- danawillow 9y agoHey there- Dana from Google here, I lead the efforts around Terraform from our side. You'll be happy to know that in the last 2 months alone we've added import for: - google_bigquery_dataset - google_bigquery_table - google_compute_address - google_compute_disk - google_compute_global_address - google_compute_route - google_compute_network - google_dns_managed_zone - google_sql_user - google_storage_bucket , with more to come shortly! We only have one open issue around import, so if there are other resources you'd like to see imported feel free to file an issue: https://github.com/terraform-providers/terraform-provider-google/issues https://github.com/terraform-providers/terraform-provider-go... (just moved to a new repo a few days ago, and we're still in the process of getting existing issues moved over). A big factor in our prioritization of what to work on is based around issues filed (and thumbs ups on those issues), so that's a great way to get in touch with the team. If you have any other questions around the Terraform+GCP experience, feel free to ask us in the #terraform channel in the GCP slack (https://gcp-slack.appspot.com/ https://gcp-slack.appspot.com/ if you aren't already there). Best of luck, and do reach out if you need anything!
- lobster_johnson 9y ago
- Artemis2 9y agoThis sums up our experience with Terraform perfectly: > Most outages are caused by human error and configuration changes, and applying Terraform changes is a terrifying mix of the two. Terraform is a great tool nonetheless. Just like Heap, we have code reviews for the configuration itself, and a CI pipeline for validating it. This pipeline is quite superficial (`terraform validate` mostly does syntax checking), so we are too working on using centralized state to `terraform plan` for reviews.
- iofiiiiiiiii 9y agoI am just now implementing Packer and Vagrant in our devops workflows. Terraform is next on the list. So far, it leaves me rather anxious - Packer and Vagrant appear to offer the bare minimum of usable functionality, with any advanced scenario bumping into (sometimes intentional) walls. For example, it takes me 15-20 minutes to transfer a 50 MB file to a Windows VM being created by Packer. The GitHub issue, filed nearly 2 years ago, is closed with a comment that this is by design: https://github.com/hashicorp/packer/issues/2648#issuecomment-307354697 https://github.com/hashicorp/packer/issues/2648#issuecomment... Yet there is a PowerShell command that uses the same communication mechanism that can somehow do it in a matter of seconds. Of course, I cannot use this PowerShell command because Packer does not give me a variable with a machine's IP address because... it is improper somehow? https://github.com/hashicorp/packer/issues/4993 https://github.com/hashicorp/packer/issues/4993 What the hell, Hashicorp... I have a list of 10+ issues I have found so far and I am only starting to use these tools. From the activity in GitHub, they seem to be abandonware. Maybe if I submitted PRs they might be accepted (then again, maybe not: https://github.com/hashicorp/packer/pulls https://github.com/hashicorp/packer/pulls) but I expect more from software than just accepting PRs - I expect its authors to actually develop it and to show an interest in improving it. There is unfortunately nothing better out there. I admit, I am forced to use these products even though I do not find them satisfactory and the authors do not seem helpful. If I had to start all over again with my current knowledge, I might perhaps just write my own scripting and skip Packer/Vagrant altogether. The value they offer with VM management comes with the downside of being left in the mud and having the system work against you when you try something nontrivial. I am scared of what I will find when I touch Terraform. As I write this, I think I will first see whether I can just script it manually.