Edit: Since this post was written a while ago I’ve written a new example with Terraform 0.12, much cleaner code with modules and code used available in Github.

Since I’ve become a big fan of modules a case where you might need them is by creating multiple instances at the same time for your Terraform project.

One option is that you have the main Terraform project and call the modules from projects main.tf file multiple times like this:

module “CreatePublicInstance1” {
source=”../instance”
}
module “CreatePublicInstance2” {
source=”../instance”
}
module “CreatePublicInstance3” {
source=”../instance”
}
But there is other option where you use the count variable in a resource. You can easily scale the amount of resources by providing the count parameter to the module and it will loop the resource as many times you have defined.
Note that at this time there are some limitations with count – it can not be a value from other module but rather you need to define it as a static variable.

Terraform project for creating instances

Again I have three files in my Terraform project named “Create_three_instances”. The files are:

  • variables.tf
  • main.tf
  • outputs.tf

Let’s take a look of them.

In the variables.tf I have defined the necessary variables for this project. In this case when I’m creating instances I have some variables pointing to existing resources related to compartment, network and instance image/shape. These are required as in the main.tf I will need to get existing OCID’s for subnets, ADs etc. I have also defined a variable server_count which is the amount of servers I want to create in this example.

In the main.tf I get existing data by using the variables.

terraform_oci_data.PNG

As you can see I first get the compartment information by passing tenancy_ocid and filter the result by compartment name. After that I use the compartment OCID to get Availability Domains and VCNs.

With compartment and VCN OCID I get the subnet information and limit the result with the subnet name. Lookups are very easy to use to get already existing data created by my network project earlier!

Next I call the actual module which creates the instances.

terraform_oci_create_instance

Calling this module I pass the server_count variable, some data through lookups which are required and also some static variables which were defined in the variables.tf.

One additional thing to note is the instance_create_vnic_details_private_ip. As you can see I actually pass the cidr_block of the subnet. Why? You will see when the actual module is being used.

Finally in the outputs.tf I will just print out the instance name, public and private IPs.

terraform_outputs_main

Using count when creating the resource

Now by looking the actual resource “oci_core_instance” “CreateInstance” you can see the usage of the count.

terraform_oci_count

I pass the server_count variable to count in the start of the resource and this determines how many times the create resource will be looped through.

As you might want to or you have to separate the naming for some resources I’ve used  ${count.index} in some places to have separation without creating a list of variables in the project’s variables.tf. In my opinion list might hard to keep updated and by using the numbering you can still have different naming.

If you take a look on the private_ip variable you see now the usage of the subnet cidr block I mentioned earlier. I use built-in function cidrhost to give specific private IP addresses for each host. You could let OCI to allocate those automatically but in some cases you want to define them.

Definition of cidrhost is as follows:

cidrhost(iprange, hostnum) – Takes an IP address range in CIDR notation and creates an IP address with the given host number. If given host number is negative, the count starts from the end of the range. For example, cidrhost(“10.0.0.0/8”, 2) returns 10.0.0.2 and cidrhost(“10.0.0.0/8”, -2) returns 10.255.255.254.

Reason why I have +3 in the end is that Oracle reserves two first IP addresses in the start of every subnet so the first instance will receive .3 IP address and continue to grow from there.

I also have outputs.tf in the module. There I need to use splat syntax (*) to send the list out.

output “instancePublicIP” {value = [“${oci_core_instance.CreateInstance.*.public_ip}”]}

Creating the resources

Now when I’m ready to create the resource I will run the usual terraform init, plan and apply. If you want to know more about those check my earlier blog post and video from here.

When I run terraform plan it will show that it will create three new resources:

Plan: 3 to add, 0 to change, 0 to destroy.

That matches the server_count variable. Once I’ve executed apply the outputs for the instances are:

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

instanceName = [
publicinstance-0,
publicinstance-1,
publicinstance-2
]
instancePrivateIP = [
10.0.2.3,
10.0.2.4,
10.0.2.5
]
instancePublicIP = [
130.61.XX.81,
130.61.XX.238,
130.61.XX.133
]

Video

Here is video also showing the exact same thing as above. You can see the code as well as running the Terraform project.

Summary

When you use Terraform modules the main goal would be to make easily repeatable code for your infrastructure. As Terraform isn’t always so flexible to different cases using count is one way to scale your resources up based on the need.

Lot of valuable information about Terraform I’ve got and used also here is from Yevgeniy Brikman’s book Terraform: Up and Running: Writing Infrastructure as CodeDefinitely buy it if you are interested to learn more!

9 thoughts on “Create multiple instances with one Terraform module in Oracle Cloud Infrastructure”

  1. Hi Simo,
    Thanks for sharing the concept. Do we have this code available on github.
    request you please share the url.

    Keep writing such useful notes:)

    Thanks.

  2. How would you extend your concept when each instance e.g. needs two additional data volumes attached?
    Or you need to have the same firewall rules for each instance?
    count only works in one resource definition, as far as I understand it.

    1. Yeah there are definitely some hacks required if you go with count-approach. You would need to play with different set of variables (and the map with lists doesn’t work well yet). We discussed this also earlier with the team and since our projects usually involve instances without many similarities we mainly do all without count but utilize modules then from the project per instance/resource.

Leave a Reply

Your email address will not be published. Required fields are marked *