Search code examples
terraformterraform-template-file

Terraform: How to decouple a file resource from an instance and RDS


I have a standard 2 tier app that I am deploying to AWS. As a part of this deployment, I need to write a config file into the EC2 instance. This config file contains the database (RDS) settings. Right now I have this file defined as a provider in the EC2 instance. So what terraform does is that it won't even start building the EC2 instance until the RDS is 100% up and running (which takes about 5 minutes). This makes things very slow.

Is there a way that I can do a file resource outside the context of the EC2 instance so that the RDS instance and EC2 instance will be created in parallel? Or is there another pattern here I should be using?

Here's some code bits:

resource "aws_instance" "foo" {
  ami           = "${lookup(var.AMIS, var.AWS_REGION)}"
  instance_type = "t2.micro"
    //setup the config file
    provisioner "file" {
      destination = "foo/config.json"
      content     = "${data.template_file.config_file.rendered}"
 ...
 }

data "template_file" "config_file" {
  template = "${file("config.json.tmpl")}"
  vars {
    mysql_pass = "${var.MYSQL_PASSWORD}"
    mysql_addr = "${aws_db_instance.mysql.endpoint}"
  }
}


resource "aws_db_instance" "mysql" {
 allocated_storage    = 20
 ...
}

Solution

  • You could use a null_resource to run the provisioner step that copies the config over to the instance.

    In your case you might use something like the following:

    resource "null_resource" "db_config" {
      # Recreating the instance requires the config to be redeployed
      triggers {
        instance_ids = "${aws_instance.foo.id}"
      }
    
      connection {
        host = "${aws_instance.cluster.public_ip}"
      }
    
      provisioner "file" {
          destination = "foo/config.json"
          content     = "${data.template_file.config_file.rendered}"
      }
    }
    

    This will then allow your EC2 and RDS instance to be created at the same time and then the template file can be generated and then finally the provisioner step to copy the templated config across will run.

    Remember that your application will now start a reasonably long time before the database is up and before it has any config available to it so make sure that it will be okay with retrying the connection to the database (and the reading of the config).

    As an alternative you might want to consider some configuration templating structure such as confd or Consul Template.