Mon Feb 05
Terraform — Usando Múltiplos Providers
Quando gerenciamos infraestrutura com Terraform, é comum ter recursos em múltiplas regiões AWS no mesmo projeto.
This approach is not just about checking off a list for robustness, speed, or compliance. It involves creating a resilient setup that performs well for users worldwide and complies with the necessary regulations. Let’s explore how setting up multiple AWS providers, each designed for a specific region, can make a significant difference.
Multi-Region Deployment: Bringing Your App Closer to Users Imagine wanting your app to be as accessible and speedy as possible for users all over the globe. By deploying your app in both the US East (N. Virginia) and Europe (Paris) regions, you’re essentially bringing your app closer to your users. This means faster connection times and a better overall user experience, regardless of geographical distance.
Disaster Recovery: Keeping the Lights On Preparation is key when it comes to potential service disruptions. You’re setting up a safety net with your primary infrastructure in the EU (Ireland) and a US West (Oregon) backup. Should anything go awry in one region, your setup can seamlessly pivot to the backup, minimizing downtime and keeping your app live with minimal fuss.
Cross-Region Resource Access: Bridging the Gap In some scenarios, resources located in different regions need to interact. Picture an EC2 instance in the EU (Frankfurt) that relies on data from an S3 bucket in the US East (N. Virginia). This inter-region setup is crucial for workflows that involve collecting data from one location and processing it in another, ensuring smooth operation across your infrastructure.
After understanding different regions’ implementation scenarios within the same Terraform project, we can proceed with the practical part.
Requirements
- AWS Credentials Configuration — The first step is to set up AWS credentials, which are essential for the AWS provider to authenticate and create resources. This requires an AWS account with appropriate permissions. https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html
- Terraform Installation — This publication does not focus on installing Terraform, as it can be done by following the instructions in the official Terraform documentation. For more information on installing Terraform, consult the documentation at the link: Terraform Installation Guide.
- **Project repository **— The project is available on GitHub. Feel free to clone and use it.
We already know how to create a Terraform project. If not, please refer to my previous posts, where I explained how to do so. We can focus on the multi-provider configuration only.
The approach to configuring multiple providers is very simple. It’s necessary to add a provider block with the new region. Let me show it.
Besides configuring the default provider, adding a new provider block and creating an alias for each region is mandatory. In that case, we are creating a provider for Virginia (USA) and another for Paris (Europe).
When configuring a provider, it is important to note that a consideration must be made. In the example below, we are setting up an alias for the Paris region. This means that the default region for the resource will be US East 1. Only when we set the alias to “Paris” will the resource be created in the Paris region. If you want, you could set the alias for both regions and in that case, it will be necessary to add the provider information for each resource on Terraform.
Setting up the us-east-1 (Virgínia) region as a default and eu-west-3 (Paris) as a secondary.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.34.0"
}
}
}
provider "aws" {
region = "us-east-1"
profile = "default"
}
provider "aws" {
region = "eu-west-3"
alias = "paris"
profile = "default"
}
We will create two different S3 buckets for this test in two AWS regions (Virginia and Paris). As you can see, we are setting up the provider information only for the resources we need to be created in the Paris region. As Virginia is our default region, we don’t need to pass that information on the bucket_virginia resource block.
resource "aws_s3_bucket" "bucket_virginia" {
bucket = var.bucket_virginia
}
resource "aws_s3_bucket" "bucket_paris" {
provider = aws.paris
bucket = var.bucket_paris
}
The current terraform plandoes not display the region for the buckets. Therefore, we need to execute terraform apply to create the resources and validate them.
terraform-multi-providers git:(main) ✗ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_s3_bucket.bucket_paris will be created
+ resource "aws_s3_bucket" "bucket_paris" {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = "template-bucket-paris"
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = false
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
}
# aws_s3_bucket.bucket_virginia will be created
+ resource "aws_s3_bucket" "bucket_virginia" {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = "template-bucket-virginia"
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = false
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ s3_paris_region = (known after apply)
+ s3_virgina_region = (known after apply)
After running the terraform applycommand, we can validate the bucket creation
➜ terraform-multi-providers git:(main) ✗ terraform apply --auto-approve
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_s3_bucket.bucket_paris will be created
+ resource "aws_s3_bucket" "bucket_paris" {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = "template-bucket-paris"
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = false
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
}
# aws_s3_bucket.bucket_virginia will be created
+ resource "aws_s3_bucket" "bucket_virginia" {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = "template-bucket-virginia"
+ bucket_domain_name = (known after apply)
+ bucket_prefix = (known after apply)
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = false
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ object_lock_enabled = (known after apply)
+ policy = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ tags_all = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ s3_paris_region = (known after apply)
+ s3_virgina_region = (known after apply)
aws_s3_bucket.bucket_paris: Creating...
aws_s3_bucket.bucket_virginia: Creating...
aws_s3_bucket.bucket_paris: Creation complete after 1s [id=template-bucket-paris]
aws_s3_bucket.bucket_virginia: Creation complete after 3s [id=template-bucket-virginia]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
s3_paris_region = "template-bucket-paris.s3.eu-west-3.amazonaws.com"
s3_virgina_region = "template-bucket-virginia.s3.us-east-1.amazonaws.com"
We could validate the correct region for those created buckets based on the Terraform apply output shown above or in the AWS console.
Cleaning Up Your Environment
After exploring the concepts and configurations we’ve discussed, it’s crucial to dismantle the created resources to prevent any unintended charges and keep your cloud environment clean. Here’s a step-by-step guide to safely tear down your Terraform-managed infrastructure.
Step 1: Review the Resources
Before destroying resources, take a moment to review what will be removed. This helps avoid accidental deletion of essential components.
Let’s call terraform plan --destroy command.
terraform-multi-providers git:(main) ✗ terraform plan --destroy
aws_s3_bucket.bucket_paris: Refreshing state... [id=template-bucket-paris]
aws_s3_bucket.bucket_virginia: Refreshing state... [id=template-bucket-virginia]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# aws_s3_bucket.bucket_paris will be destroyed
- resource "aws_s3_bucket" "bucket_paris" {
- arn = "arn:aws:s3:::template-bucket-paris" -> null
- bucket = "template-bucket-paris" -> null
- bucket_domain_name = "template-bucket-paris.s3.amazonaws.com" -> null
- bucket_regional_domain_name = "template-bucket-paris.s3.eu-west-3.amazonaws.com" -> null
- force_destroy = false -> null
- hosted_zone_id = "Z3R1K369G5AVDG" -> null
- id = "template-bucket-paris" -> null
- object_lock_enabled = false -> null
- region = "eu-west-3" -> null
- request_payer = "BucketOwner" -> null
- tags = {} -> null
- tags_all = {} -> null
- grant {
- id = "3a227dd001b07b71e5dd8709d2cfc3ebe52c2139d619c8aba776e667031e0f78" -> null
- permissions = [
- "FULL_CONTROL",
] -> null
- type = "CanonicalUser" -> null
}
- server_side_encryption_configuration {
- rule {
- bucket_key_enabled = false -> null
- apply_server_side_encryption_by_default {
- sse_algorithm = "AES256" -> null
}
}
}
- versioning {
- enabled = false -> null
- mfa_delete = false -> null
}
}
# aws_s3_bucket.bucket_virginia will be destroyed
- resource "aws_s3_bucket" "bucket_virginia" {
- arn = "arn:aws:s3:::template-bucket-virginia" -> null
- bucket = "template-bucket-virginia" -> null
- bucket_domain_name = "template-bucket-virginia.s3.amazonaws.com" -> null
- bucket_regional_domain_name = "template-bucket-virginia.s3.us-east-1.amazonaws.com" -> null
- force_destroy = false -> null
- hosted_zone_id = "Z3AQBSTGFYJSTF" -> null
- id = "template-bucket-virginia" -> null
- object_lock_enabled = false -> null
- region = "us-east-1" -> null
- request_payer = "BucketOwner" -> null
- tags = {} -> null
- tags_all = {} -> null
- grant {
- id = "3a227dd001b07b71e5dd8709d2cfc3ebe52c2139d619c8aba776e667031e0f78" -> null
- permissions = [
- "FULL_CONTROL",
] -> null
- type = "CanonicalUser" -> null
}
- server_side_encryption_configuration {
- rule {
- bucket_key_enabled = false -> null
- apply_server_side_encryption_by_default {
- sse_algorithm = "AES256" -> null
}
}
}
- versioning {
- enabled = false -> null
- mfa_delete = false -> null
}
}
Plan: 0 to add, 0 to change, 2 to destroy.
Changes to Outputs:
- s3_paris_region = "template-bucket-paris.s3.eu-west-3.amazonaws.com" -> null
- s3_virgina_region = "template-bucket-virginia.s3.us-east-1.amazonaws.com" -> null
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
This command provides a preview of all the resources Terraform intends to delete. Review this list carefully to ensure it aligns with your expectations.
Step 2: Destroy the Infrastructure
Once you’ve confirmed that the right resources are marked for deletion, proceed with the following command:
➜ terraform-multi-providers git:(main) ✗ terraform destroy
aws_s3_bucket.bucket_paris: Refreshing state... [id=template-bucket-paris]
aws_s3_bucket.bucket_virginia: Refreshing state... [id=template-bucket-virginia]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# aws_s3_bucket.bucket_paris will be destroyed
- resource "aws_s3_bucket" "bucket_paris" {
- arn = "arn:aws:s3:::template-bucket-paris" -> null
- bucket = "template-bucket-paris" -> null
- bucket_domain_name = "template-bucket-paris.s3.amazonaws.com" -> null
- bucket_regional_domain_name = "template-bucket-paris.s3.eu-west-3.amazonaws.com" -> null
- force_destroy = false -> null
- hosted_zone_id = "Z3R1K369G5AVDG" -> null
- id = "template-bucket-paris" -> null
- object_lock_enabled = false -> null
- region = "eu-west-3" -> null
- request_payer = "BucketOwner" -> null
- tags = {} -> null
- tags_all = {} -> null
- grant {
- id = "3a227dd001b07b71e5dd8709d2cfc3ebe52c2139d619c8aba776e667031e0f78" -> null
- permissions = [
- "FULL_CONTROL",
] -> null
- type = "CanonicalUser" -> null
}
- server_side_encryption_configuration {
- rule {
- bucket_key_enabled = false -> null
- apply_server_side_encryption_by_default {
- sse_algorithm = "AES256" -> null
}
}
}
- versioning {
- enabled = false -> null
- mfa_delete = false -> null
}
}
# aws_s3_bucket.bucket_virginia will be destroyed
- resource "aws_s3_bucket" "bucket_virginia" {
- arn = "arn:aws:s3:::template-bucket-virginia" -> null
- bucket = "template-bucket-virginia" -> null
- bucket_domain_name = "template-bucket-virginia.s3.amazonaws.com" -> null
- bucket_regional_domain_name = "template-bucket-virginia.s3.us-east-1.amazonaws.com" -> null
- force_destroy = false -> null
- hosted_zone_id = "Z3AQBSTGFYJSTF" -> null
- id = "template-bucket-virginia" -> null
- object_lock_enabled = false -> null
- region = "us-east-1" -> null
- request_payer = "BucketOwner" -> null
- tags = {} -> null
- tags_all = {} -> null
- grant {
- id = "3a227dd001b07b71e5dd8709d2cfc3ebe52c2139d619c8aba776e667031e0f78" -> null
- permissions = [
- "FULL_CONTROL",
] -> null
- type = "CanonicalUser" -> null
}
- server_side_encryption_configuration {
- rule {
- bucket_key_enabled = false -> null
- apply_server_side_encryption_by_default {
- sse_algorithm = "AES256" -> null
}
}
}
- versioning {
- enabled = false -> null
- mfa_delete = false -> null
}
}
Plan: 0 to add, 0 to change, 2 to destroy.
Changes to Outputs:
- s3_paris_region = "template-bucket-paris.s3.eu-west-3.amazonaws.com" -> null
- s3_virgina_region = "template-bucket-virginia.s3.us-east-1.amazonaws.com" -> null
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_s3_bucket.bucket_paris: Destroying... [id=template-bucket-paris]
aws_s3_bucket.bucket_virginia: Destroying... [id=template-bucket-virginia]
aws_s3_bucket.bucket_paris: Destruction complete after 0s
aws_s3_bucket.bucket_virginia: Destruction complete after 1s
Destroy complete! Resources: 2 destroyed.
Terraform will ask for confirmation before executing the destruction. Type yes and press Enter to proceed. Depending on the complexity and quantity of your resources, this step might take a few minutes.
In conclusion, utilizing Terraform for managing infrastructure across multiple AWS regions can enhance global accessibility and user experience and ensure robust disaster recovery. It also facilitates seamless cross-region resource interaction. By configuring multiple providers, each tailored to a specific region, we can deploy resources efficiently where they are needed the most. In this practical guide, we demonstrated how to deploy S3 buckets in the US East (Virginia) and Europe (Paris) regions by following the steps for configuring providers for these distinct locations. Ensuring a tidy and cost-effective infrastructure management practice is possible with the steps for environmental cleanup. This approach highlights the power and flexibility of Terraform in multi-region cloud environments, making it a valuable tool for developers and operations teams aiming for a resilient, high-performing global infrastructure.
Publicado originalmente no Medium.