<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Dileep</title>
    <description>The latest articles on Forem by Dileep (@sdileep).</description>
    <link>https://forem.com/sdileep</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F184795%2Fa4fba234-4a64-4ecb-bb55-75cd3a34449c.png</url>
      <title>Forem: Dileep</title>
      <link>https://forem.com/sdileep</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sdileep"/>
    <language>en</language>
    <item>
      <title>How to manage a multi-region, multi-environment infrastructure on AWS using Terraform</title>
      <dc:creator>Dileep</dc:creator>
      <pubDate>Sat, 11 Jan 2020 06:50:25 +0000</pubDate>
      <link>https://forem.com/sdileep/manage-a-multi-environment-multi-region-infrastructure-on-aws-using-terraform-1p2p</link>
      <guid>https://forem.com/sdileep/manage-a-multi-environment-multi-region-infrastructure-on-aws-using-terraform-1p2p</guid>
      <description>&lt;p&gt;In one of my recent engagements, I had to work out an approach to manage AWS infrastructure across multiple regions, and for various environments, using Terraform. &lt;/p&gt;

&lt;p&gt;As any sane copy-paste-tweak developer would, I did "google" for &lt;em&gt;inspiration&lt;/em&gt; but ended up finding content that solved partially, either only for multi-environment or multi-region scenarios, or wasn't thought through (for example, no isolation of state between regions). For anyone in a similar need, here's something to build upon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;An understanding of &lt;a href="https://www.terraform.io/docs/configuration/index.html"&gt;Terraform&lt;/a&gt; and the concepts of &lt;a href="https://www.terraform.io/docs/modules/usage.html"&gt;Modules&lt;/a&gt;, &lt;a href="https://www.terraform.io/docs/backends/index.html"&gt;Backends&lt;/a&gt;, &lt;a href="https://www.terraform.io/docs/state/workspaces.html"&gt;Workspaces&lt;/a&gt;, &lt;a href="https://www.terraform.io/docs/state/remote.html"&gt;Remote State&lt;/a&gt; &amp;amp; &lt;a href="https://www.terraform.io/docs/providers/aws/index.html"&gt;AWS provider&lt;/a&gt; would be required to make sense of the content in this post:&lt;/p&gt;

&lt;p&gt;The following tools would be required to experiment with the provided sample code :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/cli"&gt;AWS Command Line Interface&lt;/a&gt; with access to AWS configured&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.terraform.io/downloads.html"&gt;Terraform&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What do we have to play with?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Module
&lt;/h3&gt;

&lt;p&gt;Terraform's &lt;code&gt;module&lt;/code&gt; system helps us create configurable infrastructure templates that could be reused across various environments (&lt;em&gt;product-a&lt;/em&gt; deployed to &lt;em&gt;development/production&lt;/em&gt;) or across various products (standard &lt;em&gt;s3/DynamoDB/SNS/etc&lt;/em&gt; templates)&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;p&gt;Terraform's &lt;code&gt;backend&lt;/code&gt; configuration for AWS &lt;code&gt;s3&lt;/code&gt; remote state uses the following configuration variables to organize infrastructure state: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bucket&lt;/code&gt;: name of the &lt;code&gt;s3&lt;/code&gt; bucket where state would be stored&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;workspace_key_prefix&lt;/code&gt;: custom prefix on state file path&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;workspace&lt;/code&gt;: name of the workspace&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;key&lt;/code&gt;: state file name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;code&gt;s3&lt;/code&gt;, state file could then be located at &lt;code&gt;&amp;lt;bucket&amp;gt;/&amp;lt;workspace_key_prefix&amp;gt;/&amp;lt;workspace&amp;gt;/&amp;lt;key&amp;gt;&lt;/code&gt;. If we substitute &lt;code&gt;workspace&lt;/code&gt; with &lt;em&gt;ap-southeast-1&lt;/em&gt; or &lt;em&gt;ap-southeast-2&lt;/em&gt;, if we substitute the variables &lt;code&gt;workspace_key_prefix&lt;/code&gt; with &lt;em&gt;product-a&lt;/em&gt; and &lt;code&gt;key&lt;/code&gt; with &lt;em&gt;terraform.tfstate&lt;/em&gt;, we end up with state files stored as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bucket
    └──product-a
        ├──ap-southeast-1
        │   └── terraform.tfstate
        └──ap-southeast-2
            └── terraform.tfstate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This sets up grouping infrastructure states at a product/project level while establishing isolation between deployments to different regions while storing all those states conveniently in one place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;Using the terraform module and backend systems, the infrastructure-as-source code repository layout &amp;amp; Terraform backend configuration snippet described in the section provides us with a way to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;establish a structure in which common or a product/project's infrastructure is templatised for reuse across various enviroments&lt;/li&gt;
&lt;li&gt;fine tune product/project's infrastructure at an environment level while even adding environment specific infrastructure for those non-ideal cases&lt;/li&gt;
&lt;li&gt;maintain state at a region level so that we could have better isolation, canary deploy, etc.,&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Source Layout
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── environments
│   ├── development
│   |   ├── ap-southeast-1.tfvars
│   |   ├── ap-southeast-2.tfvars
│   |   ├── variables.tf
│   |   ├── main.tf
│   |   ├── provider.tf
│   |   ├── terraform.tf
│   |   └── terraform.tfvars
│   ├── test
│   |   ├── ap-southeast-1.tfvars
│   |   ├── ap-southeast-2.tfvars
│   |   └── ...
│   ├── stage
│   |   ├── ap-southeast-1.tfvars
│   |   └── ...
│   └── production
│   |   └── ...
└── modules
    ├── aws-s3
    │   ├── main.tf
    │   ├── provider.tf
    │   └── variables.tf
    ├── product-a
    │   ├── main.tf
    │   ├── provider.tf
    │   └── variables.tf
    └── sub-system-x
        ├── main.tf
        ├── provider.tf
        └── variables.tf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;environments&lt;/code&gt;: folder to isolate various environment (&lt;em&gt;development&lt;/em&gt;/&lt;em&gt;test&lt;/em&gt;/&lt;em&gt;stage&lt;/em&gt;/&lt;em&gt;production&lt;/em&gt;) specific configuration. This also helps with flexibility of maintaining environment specific infrastructure for those, common, non-ideal scenarios. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;modules&lt;/code&gt;: folder to host reusable resource sets grouped at product/project or at a sub-system or common infrastructure components level. This folder doesn't have to exist in the same repository -  it does here as an example and might very well serve the purpose of more than handful of usecases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Region specific configurations are managed through their respective &lt;code&gt;&amp;lt;workspace&amp;gt;.tfvars&lt;/code&gt; file. For example, &lt;code&gt;environments/development/ap-southeast-2.tfvars&lt;/code&gt; file for &lt;em&gt;ap-southeast-2&lt;/em&gt; region in &lt;em&gt;development&lt;/em&gt; environment. &lt;/p&gt;

&lt;p&gt;Also, &lt;code&gt;terraform.tfvars&lt;/code&gt; file found inside &lt;em&gt;development&lt;/em&gt;/&lt;em&gt;test&lt;/em&gt;/&lt;em&gt;stage&lt;/em&gt;/&lt;em&gt;production&lt;/em&gt; folder under &lt;em&gt;environments&lt;/em&gt; could be used to set common configuration for a given environment, across all regions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Backend Configuration
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform {
  required_version = "~&amp;gt; 0.12.6"

  backend "s3" {
    bucket               = "terraform-state-bucket"
    dynamodb_table       = "terraform-state-lock-table"
    encrypt              = true
    key                  = "terraform.tfstate"
    region               = "ap-southeast-2"
    workspace_key_prefix = "product-a"
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note&lt;/em&gt; : The configuration described in this post and the included sample presume state bucket per environment. But, if the need is to store state from all environments in a common bucket, we could update &lt;code&gt;workspace_key_prefix&lt;/code&gt; value to include environment in it. For example, with &lt;em&gt;product-a/development&lt;/em&gt; or &lt;em&gt;product-a/production&lt;/em&gt;, we end up with state under following path in &lt;code&gt;s3&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bucket
    └──product-a
        ├──development
        │   ├──ap-southeast-1
        │   │   └── terraform.tfstate
        │   └──ap-southeast-2
        │       └── terraform.tfstate
        └──production
            ├──ap-southeast-1
            │   └── terraform.tfstate
            └──ap-southeast-2
                └── terraform.tfstate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;Source for a sample setup could be found at &lt;a href="https://github.com/sdileep/tf-multi-region"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with the setup
&lt;/h2&gt;

&lt;p&gt;Navigate to the environment folder, &lt;code&gt;development&lt;/code&gt; for example, on the terminal.&lt;br&gt;
&lt;em&gt;Note:&lt;/em&gt; Working configuration to access AWS environment is presumed&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initialize terraform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To get started, first initialize your local terraform state information&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;List out the available workspaces&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform workspace list
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create a new workspace (if it doesn't exist already)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#terraform workspace new &amp;lt;workspace-name&amp;gt;&lt;/span&gt;
terraform workspace new ap-southeast-2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Select a workspace&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#terraform workspace select &amp;lt;workspace-name&amp;gt;&lt;/span&gt;
terraform workspace &lt;span class="k"&gt;select &lt;/span&gt;ap-southeast-2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Plan &amp;amp; apply changes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#terraform plan -var-file=&amp;lt;workspace-name&amp;gt;.tfvars&lt;/span&gt;
&lt;span class="c"&gt;#terraform apply -var-file=&amp;lt;workspace-name&amp;gt;.tfvars&lt;/span&gt;

terraform plan &lt;span class="nt"&gt;-var-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ap-southeast-2.tfvars
terraform apply &lt;span class="nt"&gt;-var-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ap-southeast-2.tfvars
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Repeat for other regions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For &lt;em&gt;ap-southeast-1&lt;/em&gt; region:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform workspace new ap-southeast-1
terraform workspace &lt;span class="k"&gt;select &lt;/span&gt;ap-southeast-1 
terraform plan &lt;span class="nt"&gt;-var-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ap-southeast-1.tfvars
terraform apply &lt;span class="nt"&gt;-var-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ap-southeast-1.tfvars
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Hopefully, this note helps a mate out!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>terraform</category>
      <category>devops</category>
      <category>distributedsystems</category>
    </item>
  </channel>
</rss>
