{"id":8279,"date":"2019-09-13T11:46:37","date_gmt":"2019-09-13T11:46:37","guid":{"rendered":"https:\/\/www.milesweb.in\/hosting-faqs\/?p=8279"},"modified":"2022-02-19T12:34:29","modified_gmt":"2022-02-19T07:04:29","slug":"how-to-write-reusable-terraform-modules-aws","status":"publish","type":"post","link":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/","title":{"rendered":"How to Write Reusable Terraform Modules &#8211; AWS"},"content":{"rendered":"<p>In this post, we are discussing how to use and write reusable Terraform modules.<\/p>\n<p>We recommend using the file layout for Terraform projects:<\/p>\n<p><a href=\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/Terraform-modules-layout.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8280\" src=\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/Terraform-modules-layout.png\" alt=\"Terraform modules layout\" width=\"673\" height=\"483\" srcset=\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/Terraform-modules-layout.png 673w, https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/Terraform-modules-layout-300x215.png 300w\" sizes=\"auto, (max-width: 673px) 100vw, 673px\" \/><\/a><\/p>\n<p>How do you avoid code redundancy during the use of such a file layout? For example, how do you avoid copying and pasting code for the same app installed in various environments, like <em><strong>stage\/services\/frontend-app<\/strong><\/em> and <em><strong>prod\/services\/frontend-app<\/strong><\/em>?<\/p>\n<p>Generally, in the programming language, like Ruby, if you have copied and pasted the same code in multiple places, you have to put that code inside of a function and recall that function everywhere you want:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>def example_function()<br \/>\nputs &#8220;Hello, World&#8221;<br \/>\nend<\/p>\n<p># Other places in your code<br \/>\nexample_function()<\/p>\n<\/div>\n<\/div>\n<p>With Terraform, you can write your code inside of a <em>Terraform module<\/em> and recall that module in many places everywhere your code. Instead of having the same code copied\/pasted in the staging and production environments, you\u2019ll be able to have both environments recall code from the same module.<\/p>\n<p>This can be a big deal. Modules are usually an important element to be able to write reusable, maintainable, and testable Terraform code. When you start utilising them, there is no moving back.<\/p>\n<ul>\n<li>You can start developing everything as a module.<\/li>\n<li>Developing a library of modules to share within your organisation.<\/li>\n<li>Start using modules you find online.<\/li>\n<li>Start thinking of your whole infrastructure as a set of reusable modules.<\/li>\n<\/ul>\n<p>In this post, we\u2019ll explain to you how to use Terraform modules by including the topics as follows:<\/p>\n<ol>\n<li>Module basics<\/li>\n<li>Module inputs<\/li>\n<li>Module outputs<\/li>\n<li>Versioned modules<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h2>1. Module basics<\/h2>\n<p style=\"text-align: justify;\">The Terraform module is very easy: any set of Terraform configuration files in a folder is a module (the module in the present working directory is named the <em>root module<\/em>). To understand what modules can manage, you have to utilise one module from another module.<\/p>\n<p style=\"text-align: justify;\">Instead of copying and pasting the code all across the place, you can convert it into a reusable module by placing it in a folder.<\/p>\n<p style=\"text-align: justify;\">Create a new folder named <em><strong>modules<\/strong><\/em> and transfer all the files (i.e., <em><strong>main.tf<\/strong><\/em>, <em><strong>variables.tf<\/strong><\/em>, and <em><strong>outputs.tf<\/strong><\/em>) from the webserver cluster into <em><strong>modules\/services\/webserver-cluster<\/strong><\/em>. Open the <em><strong>main.tf<\/strong><\/em> file in <em><strong>modules\/services\/webserver-cluster<\/strong><\/em> and remove the particular <em><strong>provider<\/strong><\/em> definition. Providers have to be configured by the user of the module and not with the module itself.<\/p>\n<p>Now you can make use of this module in, for example, your staging environment. The syntax for using a module is:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">module &#8220;&lt;NAME&gt;&#8221; {<br \/>\nsource = &#8220;&lt;SOURCE&gt;&#8221; [CONFIG &#8230;]<br \/>\n}<\/div>\n<\/div>\n<p><em><strong>NAME<\/strong><\/em> is an identifier that you may use throughout the Terraform code to specify to this module (e. g., <em><strong>web-service<\/strong><\/em>).<\/p>\n<p><em><strong>SOURCE<\/strong><\/em> is the path where the module code is available (e. g., <em><strong>modules\/services\/webserver-cluster<\/strong><\/em>).<\/p>\n<p><em><strong>CONFIG<\/strong><\/em> contains one or more arguments that are definite to that module (e. g., <em><strong>num_servers = 5<\/strong><\/em>).<\/p>\n<p style=\"text-align: justify;\">For example, you can create a new file in <em><strong>stage\/services\/webserver-cluster\/main.tf<\/strong><\/em> and use the <em><strong>webserver-cluster<\/strong><\/em> module in it as mentioned below:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>provider &#8220;aws&#8221; {<br \/>\nregion = &#8220;us-east-2&#8221;<\/p>\n<p>}<\/p>\n<p>module &#8220;webserver_cluster&#8221; {<br \/>\nsource = &#8220;..\/..\/..\/modules\/services\/webserver-cluster&#8221;<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">You can then recall the specific same module in the production environment by building a new <em><strong>prod\/services\/webserver-cluster\/main.tf<\/strong><\/em> file with the contents as follows:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>provider &#8221; digitalocean&#8221; {<br \/>\ntoken = &#8220;${var.do_token}<\/p>\n<p>}<\/p>\n<p>module &#8220;webserver_cluster&#8221; {<br \/>\nsource = &#8220;..\/..\/..\/modules\/services\/webserver-cluster&#8221;<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">And there you have that: code reuse in various environments with minimal copy\/paste! Note that whenever you add a module to your current Terraform configurations or change the <em><strong>source<\/strong><\/em> parameter of a module, you have to run the <em><strong>init<\/strong><\/em> command before you run <em><strong>plan<\/strong><\/em> or <em><strong>apply<\/strong><\/em>:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>$ terraform init<br \/>\nInitializing modules&#8230;<br \/>\n&#8211; webserver_cluster in ..\/..\/..\/modules\/services\/webserver-cluster<\/p>\n<p>Initializing the backend&#8230;<\/p>\n<p>Initializing provider plugins&#8230;<\/p>\n<p>Terraform has been successfully initialized!<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">You now have seen all the tricks the <em><strong>init<\/strong><\/em> command has up its sleeve. It downloads providers, modules, and configures your backends, all in one useful command.<\/p>\n<p style=\"text-align: justify;\">Before you run the <em><strong>apply<\/strong><\/em> command on this code, you should take note of that there can be an issue with the <em><strong>webserver-cluster<\/strong><\/em> module: all the names are hard-coded. That is, the name of the security groups, CLB, and additional resources are all hard-coded, so if you utilise this module more than once, you&#8217;ll get name conflict errors. To fix these issues, you have to add configurable data to the <em><strong>webserver-cluster<\/strong><\/em> module so it can act differently in various environments.<\/p>\n<h2>2. Module inputs<\/h2>\n<p style=\"text-align: justify;\">You can add input parameters to that function to get configurable in a general-purpose programming language like Ruby:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>def example_function(param1, param2)<br \/>\nputs &#8220;Hello, #{param1} #{param2}&#8221;<br \/>\nend<\/p>\n<p># Other places in your code<br \/>\nexample_function(&#8220;foo&#8221;, &#8220;bar&#8221;)<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">In Terraform, modules also can have input parameters. You use a tool you\u2019re already familiar with \u2018input variables\u2019 to define them. Open <em><strong>modules\/services\/webserver-cluster\/variables.tf<\/strong><\/em> and add a new input variable:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>variable &#8220;cluster_name&#8221; {<br \/>\ndescription = &#8220;The name to use for all the cluster resources&#8221;<br \/>\ntype = string<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">Next, check <em><strong>modules\/services\/webserver-cluster\/main.tf<\/strong><\/em> and use <em><strong>var.cluster_name<\/strong><\/em> alternatively hard-coded names (e. g., alternatively of &#8220;<em><strong>terraform-asg-example<\/strong><\/em>&#8220;). For example, this is how you do it for the CLB security group:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>resource &#8220;aws_security_group&#8221; &#8220;elb&#8221; {<br \/>\nname = &#8220;${var.cluster_name}-elb&#8221;<\/p>\n<p>ingress {<br \/>\nfrom_port = 80<br \/>\nto_port = 80<br \/>\nprotocol = &#8220;tcp&#8221;<br \/>\ncidr_blocks = [&#8220;0.0.0.0\/0&#8221;]<br \/>\n}<\/p>\n<p>egress {<br \/>\nfrom_port = 0<br \/>\nto_port = 0<br \/>\nprotocol = &#8220;-1&#8221;<br \/>\ncidr_blocks = [&#8220;0.0.0.0\/0&#8221;]<br \/>\n}<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">See how the <em><strong>name<\/strong><\/em> parameter is set to <em><strong>&#8220;${var.cluster_name}-elb&#8221;<\/strong><\/em>. You will have to make a related change to the other <em><strong>aws_security_group<\/strong><\/em> resource (e.g., give it the name <em><strong>&#8220;${var.cluster_name}-instance&#8221;<\/strong><\/em>), the <em><strong>aws_elb<\/strong><\/em> resource, and the <em><strong>tag<\/strong><\/em> section of the <em><strong>aws_autoscaling_group<\/strong><\/em> resource.<\/p>\n<p style=\"text-align: justify;\">Presently, in the staging environment, in <em><strong>stage\/services\/webserver-cluster\/main.tf<\/strong><\/em>, you can set the new input variable likewise:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>module &#8220;webserver_cluster&#8221; {<br \/>\nsource = &#8220;..\/..\/..\/modules\/services\/webserver-cluster&#8221;<\/p>\n<p>cluster_name = &#8220;webservers-stage&#8221;<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p>You have to do the same in the production environment in <em><strong>prod\/services\/webserver-cluster\/main.tf<\/strong><\/em>:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>module &#8220;webserver_cluster&#8221; {<br \/>\nsource = &#8220;..\/..\/..\/modules\/services\/webserver-cluster&#8221;<\/p>\n<p>cluster_name = &#8220;webservers-prod&#8221;<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">As you can see, you set input variables to get a module using the same syntax as setting arguments for the resource. The particular input variables are the API of the module, checking how it will act in different environments. This example applies various names in different environments, but you may also need to make other parameters configurable. For example, within staging, you may need to run the small webserver cluster to save money, but within production, you may need to run the larger cluster to manage plenty of traffic. To perform that, you can add three additional input variables to <em><strong>modules\/services\/webserver-cluster\/variables.tf<\/strong><\/em>:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>variable &#8220;instance_type&#8221; {<br \/>\ndescription = &#8220;The type of EC2 Instances to run (e.g. t2.micro)&#8221;<br \/>\ntype = string<br \/>\n}<\/p>\n<p>variable &#8220;min_size&#8221; {<br \/>\ndescription = &#8220;The minimum number of EC2 Instances in the ASG&#8221;<br \/>\ntype = number<br \/>\n}<\/p>\n<p>variable &#8220;max_size&#8221; {<br \/>\ndescription = &#8220;The maximum number of EC2 Instances in the ASG&#8221;<br \/>\ntype = number<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">Next, update the launch configuration in <em><strong>modules\/services\/webserver-cluster\/main.tf<\/strong><\/em> to set its <em><strong>instance_type<\/strong><\/em> parameter to the new <em><strong>var.instance_type<\/strong><\/em> input variable:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>resource &#8220;aws_launch_configuration&#8221; &#8220;example&#8221; {<br \/>\nimage_id = &#8220;ami-0c55b159cbfafe1f0&#8221;<br \/>\ninstance_type = var.instance_type<\/p>\n<p># (&#8230;)<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">Also, you have to update the ASG definition in the same file to set its <em><strong>min_size<\/strong><\/em> and <em><strong>max_size<\/strong><\/em> parameters to the new <em><strong>var.min_size<\/strong><\/em> and <em><strong>var.max_size<\/strong><\/em> input variables:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>resource &#8220;aws_autoscaling_group&#8221; &#8220;example&#8221; {<br \/>\nlaunch_configuration = aws_launch_configuration.example.id<br \/>\navailability_zones = data.aws_availability_zones.all.names<\/p>\n<p>min_size = var.min_size<br \/>\nmax_size = var.max_size<\/p>\n<p># (&#8230;)<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">Now, in the staging environment (<em><strong>stage\/services\/webserver-cluster\/main.tf<\/strong><\/em>), you can keep the cluster small and inexpensive by setting <em><strong>instance_type<\/strong><\/em> to <em><strong>t2.micro<\/strong><\/em> and <em><strong>min_size<\/strong><\/em> and <em><strong>max_size<\/strong><\/em> to <em><strong>2<\/strong><\/em>:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>module &#8220;webserver_cluster&#8221; {<br \/>\nsource = &#8220;..\/..\/..\/modules\/services\/webserver-cluster&#8221;<\/p>\n<p>cluster_name = &#8220;webservers-stage&#8221;<br \/>\ninstance_type = &#8220;t2.micro&#8221;<br \/>\nmin_size = 2<br \/>\nmax_size = 2<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">Alternatively, in the production environment, you can utilise a bigger <em><strong>instance_type<\/strong><\/em> with more CPU and memory like <em><strong>m4.large<\/strong><\/em> (<em><strong>Note:<\/strong><\/em><em> this instance type is <strong>not<\/strong> part of the AWS free tier, so in case you&#8217;re simply using this for learning and do not want to be able to be charged, stick along with <strong>t2. micro<\/strong> for the <\/em><strong><em>instance_type<\/em><\/strong>), and you may set <em><strong>max_size<\/strong><\/em> to <em><strong>10<\/strong><\/em> to let the cluster to reduce or increase according to the load (<em>don&#8217;t bother, in the beginning, the cluster will launch with two instances<\/em>):<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">module &#8220;webserver_cluster&#8221; {<br \/>\nsource = &#8220;..\/..\/..\/modules\/services\/webserver-cluster&#8221;cluster_name = &#8220;webservers-prod&#8221;<br \/>\ninstance_type = &#8220;m4.large&#8221;<br \/>\nmin_size = 2<br \/>\nmax_size = 10<br \/>\n}<\/div>\n<\/div>\n<h2>3. Module Outputs<\/h2>\n<p style=\"text-align: justify;\">A strong feature of Auto Scaling Groups is that you can configure them to increase or decrease the number of servers you have utilised in response to load. One approach to perform this is by using an <em>auto scaling schedule<\/em> that may change the size of the cluster at a scheduled time throughout the day. For example, if traffic to your cluster is increased during the regular business hours, you should use an auto scaling schedule to extend the number of servers at 9 a. m. and reduce it at 5 p. m.<\/p>\n<p style=\"text-align: justify;\">If you specify the auto scaling schedule in the <em><strong>webserver-cluster<\/strong><\/em> module, it would be used to both staging and production. As you do not require doing this sort of scaling within your staging environment, for the time being, you can specify the auto scaling schedule directly in the production configurations.<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>resource &#8220;aws_autoscaling_schedule&#8221; &#8220;scale_out_business_hours&#8221; {<br \/>\nscheduled_action_name = &#8220;scale-out-during-business-hours&#8221;<br \/>\nmin_size = 2<br \/>\nmax_size = 10<br \/>\ndesired_capacity = 10<br \/>\nrecurrence = &#8220;0 9 * * *&#8221;<br \/>\n}<\/p>\n<p>resource &#8220;aws_autoscaling_schedule&#8221; &#8220;scale_in_at_night&#8221; {<br \/>\nscheduled_action_name = &#8220;scale-in-at-night&#8221;<br \/>\nmin_size = 2<br \/>\nmax_size = 10<br \/>\ndesired_capacity = 2<br \/>\nrecurrence = &#8220;0 17 * * *&#8221;<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">This code uses one <em><strong>aws_autoscaling_schedule<\/strong><\/em> resource to extend the number of servers to 10 while the morning hours (the <em><strong>recurrence<\/strong><\/em> parameter utilises cron syntax, so <em><strong>&#8220;0 9 * * *&#8221;<\/strong><\/em> implies &#8220;9 a. m. daily&#8221;) and the other <em><strong>aws_autoscaling_schedule<\/strong><\/em> resource to reduce the number of servers at night (<em><strong>&#8220;0 17 * * *&#8221;<\/strong><\/em> implies &#8220;5 p. m. daily&#8221;). Still, both usages of <em><strong>aws_autoscaling_schedule<\/strong><\/em> are missing a required parameter, <em><strong>autoscaling_group_name<\/strong><\/em>, which defines the name of the ASG. The ASG itself is specified within the <em><strong>webserver-cluster<\/strong><\/em> module, so how do you access its name? In a general-purpose programming language, like Ruby, functions can return values:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>def example_function(param1, param2)<br \/>\nreturn &#8220;Hello, #{param1} #{param2}&#8221;<br \/>\nend<\/p>\n<p># Other places in your code<br \/>\nreturn_value = example_function(&#8220;foo&#8221;, &#8220;bar&#8221;)<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">In Terraform, a module may also return values. Again, this is performed using a system you are already aware: output variables. You can add the ASG name as an output variable in <em><strong>\/modules\/services\/webserver-cluster\/outputs.tf<\/strong><\/em> as mention below:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>output &#8220;asg_name&#8221; {<br \/>\nvalue = aws_autoscaling_group.example.name<br \/>\ndescription = &#8220;The name of the Auto Scaling Group&#8221;<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">You may access module output variables in a similar way as resource output attributes. Following is the syntax:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>module.&lt;MODULE_NAME&gt;.&lt;OUTPUT_NAME&gt;<\/p>\n<\/div>\n<\/div>\n<p>For example:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>module.frontend.asg_name<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">You can use this syntax in <em><strong>prod\/services\/webserver-cluster\/main.tf<\/strong><\/em> to set the <em><strong>autoscaling_group_name<\/strong><\/em> parameter in any of the <em><strong>aws_autoscaling_schedule<\/strong><\/em> resources:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>resource &#8220;aws_autoscaling_schedule&#8221; &#8220;scale_out_business_hours&#8221; {<br \/>\nscheduled_action_name = &#8220;scale-out-during-business-hours&#8221;<br \/>\nmin_size = 2<br \/>\nmax_size = 10<br \/>\ndesired_capacity = 10<br \/>\nrecurrence = &#8220;0 9 * * *&#8221;<\/p>\n<p>autoscaling_group_name = module.webserver_cluster.asg_name<br \/>\n}<\/p>\n<p>resource &#8220;aws_autoscaling_schedule&#8221; &#8220;scale_in_at_night&#8221; {<br \/>\nscheduled_action_name = &#8220;scale-in-at-night&#8221;<br \/>\nmin_size = 2<br \/>\nmax_size = 10<br \/>\ndesired_capacity = 2<br \/>\nrecurrence = &#8220;0 17 * * *&#8221;<\/p>\n<p>autoscaling_group_name = module.webserver_cluster.asg_name<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">You may need to show one other output in the <em><strong>webserver-cluster<\/strong><\/em> module: the DNS name of the CLB, hence, you understand what URL to test when the cluster is deployed. You again add an output variable in <em><strong>\/modules\/services\/webserver-cluster\/outputs.tf<\/strong><\/em> to execute that:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>output &#8220;clb_dns_name&#8221; {<br \/>\nvalue = aws_elb.example.dns_name<br \/>\ndescription = &#8220;The domain name of the load balancer&#8221;<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">You can then \u201cgo through\u201d this output in <em><strong>stage\/services\/webserver-cluster\/outputs.tf<\/strong><\/em> and <em><strong>prod\/services\/webserver-cluster\/outputs.tf<\/strong><\/em> as follows:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>output &#8220;clb_dns_name&#8221; {<br \/>\nvalue = module.webserver_cluster.clb_dns_name<br \/>\ndescription = &#8220;The domain name of the load balancer&#8221;<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<h2>4. Versioned modules<\/h2>\n<p style=\"text-align: justify;\">If both your staging and production environments are directing to the same module directory, then as soon as you create a modification in that folder, it will affect both environments on the same next deployment. This sort of coupling can make it tougher to test a change in staging without any possibility of affecting production. A better approach is always to create <em>versioned modules<\/em> to enable you to use one version in staging (e.g., v0.0.2) and another version in production (e. g., v0. 0. 1).<\/p>\n<p style=\"text-align: justify;\">Out of all module examples you&#8217;ve noticed so far, whenever you used a module, you have set the <em><strong>source<\/strong><\/em> parameter of the module to a local file path. Also, to file paths, Terraform supports other sorts of <a href=\"https:\/\/www.terraform.io\/docs\/modules\/sources.html?source=post_page---------------------------\" target=\"_blank\" rel=\"nofollow noopener\">module sources<\/a>, like Git URLs, Mercurial URLs and optional HTTP URLs. The best way to create a versioned module would be to place the code for the module in a separate Git repository and to set the <em><strong>source<\/strong><\/em> parameter to that repository&#8217;s URL. Which means your Terraform code is going to be spread out over (at least) two repositories:<\/p>\n<ul>\n<li style=\"text-align: justify;\"><strong>modules<\/strong>: This repo specifies reusable modules. Think of each module as a \u201cblueprint\u201d that describes an exact part of your infrastructure.<\/li>\n<li style=\"text-align: justify;\"><strong>live<\/strong>: This repo specifies the existing infrastructure you\u2019re running in each environment such as stage, prod, mgmt, etc. Assume of this as the \u201chouses\u201d you created from the \u201cblueprints\u201d in the <em><strong>modules<\/strong><\/em> repo.<\/li>\n<\/ul>\n<p>The modified folder structure for your Terraform code will now look something like this:<\/p>\n<p><a href=\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/Terraform-modules-layout-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8281\" src=\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/Terraform-modules-layout-1.png\" alt=\"Terraform modules layout-1\" width=\"672\" height=\"758\" srcset=\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/Terraform-modules-layout-1.png 672w, https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/Terraform-modules-layout-1-266x300.png 266w\" sizes=\"auto, (max-width: 672px) 100vw, 672px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">To create this folder structure, initially, you would have to move the <em><strong>stage<\/strong><\/em>, <em><strong>prod<\/strong><\/em>, and <em><strong>global<\/strong><\/em> folders into the folder called <em><strong>live<\/strong><\/em>. Next, configure the <em><strong>live<\/strong><\/em> and <em><strong>modules<\/strong><\/em> folders as single git repositories. Following is an example of how to do that for the <em><strong>modules<\/strong><\/em> folder:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>$ cd modules<br \/>\n$ git init<br \/>\n$ git add .<br \/>\n$ git commit -m &#8220;Initial commit of modules repo&#8221;<br \/>\n$ git remote add origin &#8220;(URL OF REMOTE GIT REPOSITORY)&#8221;<br \/>\n$ git push origin master<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">To use as a version number, you can add a tag to the <em><strong>modules<\/strong><\/em> repo. You can also use the GitHub UI to <a href=\"https:\/\/help.github.com\/en\/articles\/creating-releases\" target=\"_blank\" rel=\"nofollow noopener\">build a release<\/a> if you\u2019re using GitHub, which will create a tag under the hood. If you are not using GitHub, you can use the Git CLI:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>$ git tag -a &#8220;v0.0.1&#8221; -m &#8220;First release of webserver-cluster module&#8221;<br \/>\n$ git push \u2010\u2010follow-tags<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">You can now use this versioned module in both staging and production by defining a Git URL in the <em><strong>source<\/strong><\/em> parameter. If your <em><strong>modules<\/strong><\/em> repo was in the GitHub repo <em><strong>github.com\/foo\/modules<\/strong><\/em>, this is what that might look like in <em><strong>live\/stage\/services\/webserver-cluster\/main.tf<\/strong><\/em>.<\/p>\n<p><em><strong>Note:<\/strong><\/em> The double-slash in the Git URL is required as follows:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>module &#8220;webserver_cluster&#8221; {<br \/>\nsource = &#8220;github.com\/foo\/modules\/\/webserver-cluster?ref=v0.0.1&#8221;<\/p>\n<p>cluster_name = &#8220;webservers-stage&#8221;<br \/>\ninstance_type = &#8220;t2.micro&#8221;<br \/>\nmin_size = 2<br \/>\nmax_size = 2<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">The <em><strong>ref<\/strong><\/em> parameter permits you to define a particular Git submit using its sha1 hash, a branch name, or, as in this case, a particular Git tag. I usually suggest using Git tags as version numbers for modules. Branch names are not steady, as you always get the most recent commit on a branch, which can change each time you run the <em><strong>init<\/strong><\/em> command and the sha1 hashes are not much user-friendly. Git tags are as steady as a commit (actually, a tag is only a pointer to a commit) however they enable you to utilise a friendly, readable name.<\/p>\n<p style=\"text-align: justify;\">As you&#8217;ve updated your Terraform code to use a versioned module URL, you require informing Terraform to download the module code by re-running <em><strong>terraform init<\/strong><\/em>:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">$ terraform init<br \/>\nInitializing modules&#8230;<br \/>\nDownloading github.com\/foo\/modules?ref=v0.0.2<br \/>\n&#8211; webserver_cluster in .terraform\/modules\/services\/webserver-cluster(&#8230;)<\/div>\n<\/div>\n<p style=\"text-align: justify;\">You now can see that Terraform downloads the module code from Git as alternatively your local filesystem. You can run the <em><strong>apply<\/strong><\/em> command usually, once the module code has been downloaded.<\/p>\n<p style=\"text-align: justify;\"><em><strong>Note:<\/strong><\/em> If your Terraform module is in a private Git repository, to use that repo as a module <em><strong>source<\/strong><\/em>, you should give Terraform an approach to validate to that Git storehouse. I suggest using SSH auth so that you don\u2019t need to hard-code the credentials for your repo in the code itself. For example, with GitHub, an SSH <em><strong>source<\/strong><\/em> URL have to be of the form:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>source = &#8220;git::git@github.com:&lt;OWNER&gt;\/&lt;REPO&gt;.git\/\/&lt;PATH&gt;?ref=&lt;VERSION&gt;&#8221;<\/p>\n<\/div>\n<\/div>\n<p>For example:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>source = &#8220;git::git@github.com:gruntwork-io\/terraform-google-gke.git\/\/modules\/gke-cluster?ref=v0.1.2&#8221;<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">Now that you&#8217;re using versioned modules, let&#8217;s step into the way of making modifications. Suppose you made few changes to the <em><strong>webserver-cluster<\/strong><\/em> module and you require to test them out in staging. First, you needed to commit those changes to the <em><strong>modules<\/strong><\/em> repo:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>$ cd modules<br \/>\n$ git add .<br \/>\n$ git commit -m &#8220;Made some changes to webserver-cluster&#8221;<br \/>\n$ git push origin master<\/p>\n<\/div>\n<\/div>\n<p>After that, you will create a new tag in the <em><strong>modules<\/strong><\/em> repo:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>$ git tag -a &#8220;v0.0.2&#8221; -m &#8220;Second release of webserver-cluster&#8221;<br \/>\n$ git push \u2010\u2010follow-tags<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">And now you can update only the source URL applied in the staging environment (<em><strong>live\/stage\/services\/webserver-cluster\/main.tf<\/strong><\/em>) to use this latest version:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>module &#8220;webserver_cluster&#8221; {<br \/>\nsource = &#8220;github.com\/foo\/modules\/\/webserver-cluster?ref=v0.0.2&#8221;<\/p>\n<p>cluster_name = &#8220;webservers-stage&#8221;<br \/>\ninstance_type = &#8220;t2.micro&#8221;<br \/>\nmin_size = 2<br \/>\nmax_size = 2<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">In production (<em><strong>live\/prod\/services\/webserver-cluster\/main.tf<\/strong><\/em>), you can cheerfully keep on running v0.0.1 unchanged:<\/p>\n<div class=\"vlt-box\">\n<div class=\"box-content\">\n<p>module &#8220;webserver_cluster&#8221; {<br \/>\nsource = &#8220;github.com\/foo\/modules\/\/webserver-cluster?ref=v0.0.1&#8221;<\/p>\n<p>cluster_name = &#8220;webservers-prod&#8221;<br \/>\ninstance_type = &#8220;m4.large&#8221;<br \/>\nmin_size = 2<br \/>\nmax_size = 10<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<p style=\"text-align: justify;\">Once v0.0.2 has been wholly tested and proven in staging, you can then update production. In any case, if there ends up being a bug in v0.0.2 no big deal, as it does not affect the genuine users of your production environment. Fix the bug, deliver a new version, and repeat the entire process until you have something stable enough for production.<\/p>\n<h3>Conclusion<\/h3>\n<p style=\"text-align: justify;\">By specifying infrastructure-as-code in modules, you can use a type of coding best-practices to your infrastructure. You get to invest your time building modules instead of manually deploying code; you can validate each change to a module via code reviews and automated tests; you can create versioned releases of each module and document the changes in every release, and you can securely evaluate different versions of a module in different environments and turn back to previous versions, if you hit a problem.<\/p>\n<p style=\"text-align: justify;\">All of this can dramatically increase your ability to build infrastructure quickly and reliably. You can sum up complicated pieces of infrastructure behind simple APIs that can be used again all over your tech stack.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, we are discussing how to use and write reusable Terraform modules. We recommend using the file layout for Terraform projects: How do you avoid code redundancy during the use of such a file layout? For example, how do you avoid copying and pasting code for the same app installed in various environments, [&hellip;]<\/p>\n","protected":false},"author":19,"featured_media":8284,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[41,4],"tags":[1012,1011],"class_list":["post-8279","post","type-post","status-publish","format-standard","has-post-thumbnail","placeholder-for-hentry","category-howtos","category-web-hosting-faq","tag-aws","tag-terraform-modules"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>How to Write Reusable Terraform Modules - AWS<\/title>\n<meta name=\"description\" content=\"We\u2019ll explain about writing reusable terraform modules. With Terraform, you can write your code inside of a Terraform module and make the code reusable.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Write Reusable Terraform Modules - AWS\" \/>\n<meta property=\"og:description\" content=\"We\u2019ll explain about writing reusable terraform modules. With Terraform, you can write your code inside of a Terraform module and make the code reusable.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Hosting FAQs by MilesWeb\" \/>\n<meta property=\"article:published_time\" content=\"2019-09-13T11:46:37+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-02-19T07:04:29+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png\" \/>\n\t<meta property=\"og:image:width\" content=\"800\" \/>\n\t<meta property=\"og:image:height\" content=\"445\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Ajit\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ajit\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/\"},\"author\":{\"name\":\"Ajit\",\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/#\/schema\/person\/7cd39cafedd7652b49b849e5e331cd48\"},\"headline\":\"How to Write Reusable Terraform Modules &#8211; AWS\",\"datePublished\":\"2019-09-13T11:46:37+00:00\",\"dateModified\":\"2022-02-19T07:04:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/\"},\"wordCount\":3077,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png\",\"keywords\":[\"AWS\",\"Terraform Modules\"],\"articleSection\":[\"How-Tos\",\"Web Hosting FAQ\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/\",\"url\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/\",\"name\":\"How to Write Reusable Terraform Modules - AWS\",\"isPartOf\":{\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png\",\"datePublished\":\"2019-09-13T11:46:37+00:00\",\"dateModified\":\"2022-02-19T07:04:29+00:00\",\"author\":{\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/#\/schema\/person\/7cd39cafedd7652b49b849e5e331cd48\"},\"description\":\"We\u2019ll explain about writing reusable terraform modules. With Terraform, you can write your code inside of a Terraform module and make the code reusable.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#primaryimage\",\"url\":\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png\",\"contentUrl\":\"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png\",\"width\":800,\"height\":445,\"caption\":\"How to Write Reusable Terraform Modules - AWS\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.milesweb.in\/hosting-faqs\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Write Reusable Terraform Modules &#8211; AWS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/#website\",\"url\":\"https:\/\/www.milesweb.in\/hosting-faqs\/\",\"name\":\"Web Hosting FAQs by MilesWeb\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.milesweb.in\/hosting-faqs\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/#\/schema\/person\/7cd39cafedd7652b49b849e5e331cd48\",\"name\":\"Ajit\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.milesweb.in\/hosting-faqs\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/6d48014b3dcf0691486425b0f8443591d31e1e2f623206cd11a25fdffa417819?s=96&d=blank&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/6d48014b3dcf0691486425b0f8443591d31e1e2f623206cd11a25fdffa417819?s=96&d=blank&r=g\",\"caption\":\"Ajit\"},\"description\":\"With over 8+ years of experience in the digital marketing industry, I have achieved extensive exposure to result-oriented methodologies. And expertise in different domains like Datacentre Services, Cloud computing technology, Web hosting industry and many more.\",\"url\":\"https:\/\/www.milesweb.in\/hosting-faqs\/author\/ajit\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Write Reusable Terraform Modules - AWS","description":"We\u2019ll explain about writing reusable terraform modules. With Terraform, you can write your code inside of a Terraform module and make the code reusable.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/","og_locale":"en_US","og_type":"article","og_title":"How to Write Reusable Terraform Modules - AWS","og_description":"We\u2019ll explain about writing reusable terraform modules. With Terraform, you can write your code inside of a Terraform module and make the code reusable.","og_url":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/","og_site_name":"Web Hosting FAQs by MilesWeb","article_published_time":"2019-09-13T11:46:37+00:00","article_modified_time":"2022-02-19T07:04:29+00:00","og_image":[{"width":800,"height":445,"url":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png","type":"image\/png"}],"author":"Ajit","twitter_misc":{"Written by":"Ajit","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#article","isPartOf":{"@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/"},"author":{"name":"Ajit","@id":"https:\/\/www.milesweb.in\/hosting-faqs\/#\/schema\/person\/7cd39cafedd7652b49b849e5e331cd48"},"headline":"How to Write Reusable Terraform Modules &#8211; AWS","datePublished":"2019-09-13T11:46:37+00:00","dateModified":"2022-02-19T07:04:29+00:00","mainEntityOfPage":{"@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/"},"wordCount":3077,"commentCount":0,"image":{"@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#primaryimage"},"thumbnailUrl":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png","keywords":["AWS","Terraform Modules"],"articleSection":["How-Tos","Web Hosting FAQ"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/","url":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/","name":"How to Write Reusable Terraform Modules - AWS","isPartOf":{"@id":"https:\/\/www.milesweb.in\/hosting-faqs\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#primaryimage"},"image":{"@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#primaryimage"},"thumbnailUrl":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png","datePublished":"2019-09-13T11:46:37+00:00","dateModified":"2022-02-19T07:04:29+00:00","author":{"@id":"https:\/\/www.milesweb.in\/hosting-faqs\/#\/schema\/person\/7cd39cafedd7652b49b849e5e331cd48"},"description":"We\u2019ll explain about writing reusable terraform modules. With Terraform, you can write your code inside of a Terraform module and make the code reusable.","breadcrumb":{"@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#primaryimage","url":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png","contentUrl":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-content\/uploads\/2019\/09\/How-to-Write-Reusable-Terraform-Modules-AWS.png","width":800,"height":445,"caption":"How to Write Reusable Terraform Modules - AWS"},{"@type":"BreadcrumbList","@id":"https:\/\/www.milesweb.in\/hosting-faqs\/how-to-write-reusable-terraform-modules-aws\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.milesweb.in\/hosting-faqs\/"},{"@type":"ListItem","position":2,"name":"How to Write Reusable Terraform Modules &#8211; AWS"}]},{"@type":"WebSite","@id":"https:\/\/www.milesweb.in\/hosting-faqs\/#website","url":"https:\/\/www.milesweb.in\/hosting-faqs\/","name":"Web Hosting FAQs by MilesWeb","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.milesweb.in\/hosting-faqs\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.milesweb.in\/hosting-faqs\/#\/schema\/person\/7cd39cafedd7652b49b849e5e331cd48","name":"Ajit","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.milesweb.in\/hosting-faqs\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/6d48014b3dcf0691486425b0f8443591d31e1e2f623206cd11a25fdffa417819?s=96&d=blank&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6d48014b3dcf0691486425b0f8443591d31e1e2f623206cd11a25fdffa417819?s=96&d=blank&r=g","caption":"Ajit"},"description":"With over 8+ years of experience in the digital marketing industry, I have achieved extensive exposure to result-oriented methodologies. And expertise in different domains like Datacentre Services, Cloud computing technology, Web hosting industry and many more.","url":"https:\/\/www.milesweb.in\/hosting-faqs\/author\/ajit\/"}]}},"_links":{"self":[{"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/posts\/8279","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/users\/19"}],"replies":[{"embeddable":true,"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/comments?post=8279"}],"version-history":[{"count":3,"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/posts\/8279\/revisions"}],"predecessor-version":[{"id":16221,"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/posts\/8279\/revisions\/16221"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/media\/8284"}],"wp:attachment":[{"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/media?parent=8279"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/categories?post=8279"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.milesweb.in\/hosting-faqs\/wp-json\/wp\/v2\/tags?post=8279"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}