DEV Community

Kunal Ahuja
Kunal Ahuja

Posted on

Say Hello to Terraform: Your Infrastructure's New Best Friend

Terraform image

Are you tired of maintaining cloud infrastructure? Meet Terraform, the tool that's about to make your life a whole lot easier!

What's Terraform, Anyway?

Think of Terraform as a magic wand for your infrastructure. Write down what you want instead of clicking buttons and manually configuring servers, databases, and networks. Terraform takes care of the rest.

How does it work:

Terraform talks to cloud platforms and other services using their APIs. Here are the steps involved:

  1. Write: You make a list of resources you need in the cloud. Want servers on AWS and a database on Google Cloud? No problem!
  2. Plan: Terraform looks at your list and the existing setup. It then creates a plan, saying, "Okay, I'll add this, change that, and remove that".
  3. Apply: If you like the plan, give Terraform the green light. It'll make all the changes in the right order, ensuring everything plays nicely together.

But How Does Terraform Know About All These Cloud Services?

Great question! Terraform has a massive library of "providers" - think of them as universal translators for different cloud services. These providers are created by HashiCorp (the company behind Terraform) and a community of helpful developers. You can find these providers in the Terraform Registry.

Let's Get Practical:

Creating a .NET Lambda Function with API Gateway and S3:

Now that we've understood the basics, let's dive into a real-world example. We're going to use Terraform to set up a .NET Lambda function, API Gateway, and an S3 bucket on AWS. This is a common setup for serverless applications.

Step 1: Set up the Lambda Function

// lambda.tf
resource "aws_lambda_function" "test-lambda" {
  function_name = "order-processing-function" //name of the lambda function
  filename      = "order_processor.zip" // location of the .Net Lambda function 
  role          = "arn:aws:iam::123456789012:role/lambda-order-processor-role"                    // role for the lambda function
  description   = "Processes incoming orders from the e-commerce platform"                // function description
  handler       = "OrderProcessor::OrderProcessor.Function::FunctionHandler" // execution function when the lambda is triggered
  runtime       = "dotnet8"                // lambda function's framework 
  memory_size   = 512                     // memory size allocated to lambda (MB)
  timeout       = 15                      // number of seconds after which the request gets timed out
  tags = {
    Name = "order-processor"
    Environment = "production"
  }
  publish = true
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the API Gateway

// api-gateway-tf
resource "aws_api_gateway_rest_api" "test-api" {
  name        = "order-processing-api"
  description = "API for the e-commerce order processing system"
}

resource "aws_api_gateway_resource" "base-resource" {
  rest_api_id = aws_api_gateway_rest_api.test-api.id // API Gateway's ID
  parent_id   = aws_api_gateway_rest_api.test-api.root_resource_id // root resource ID of the API
  path_part   = "{proxy+}" // allows the resource to handle any path under the API
}

resource "aws_api_gateway_method" "test-api-method" {
  rest_api_id   = aws_api_gateway_rest_api.test-api.id // API Gateway's ID
  resource_id   = aws_api_gateway_resource.base-resource.id // The ID of the API resource
  http_method   = "ANY" // allows any HTTP Method (GET, POST, PUT, DELETE) 
  authorization = "NONE" // No Auth is required.
}

resource "aws_api_gateway_integration" "test-api-integration" {
  rest_api_id = aws_api_gateway_rest_api.test-api.id // API Gateway's ID
  resource_id = aws_api_gateway_resource.base-resource.id // The ID of the API resource
  http_method = aws_api_gateway_method.test-api-method.http_method // The HTTP method from the API Gateway method
  integration_http_method = "POST" // POST is commonly used for Lambda proxy integration
  type                    = "AWS_PROXY" AWS_PROXY allows for Lambda proxy integration
  uri                     = aws_lambda_function.test-lambda.invoke_arn // URL for invoking the API Gateway
  passthrough_behavior    = "WHEN_NO_MATCH" // what to do when none of the mappings match.
}

resource "aws_api_gateway_deployment" "test-api-deployment" {
  depends_on  = [aws_api_gateway_integration.test-api-integration] // Ensures that the integration is created before the deployment occurs
  rest_api_id = aws_api_gateway_rest_api.test-api.id // API Gateway's ID
  stage_name  = "prod" // The name of the stage to which the API will be deployed
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Set up the S3 Bucket

// s3-bucket.tf
resource "aws_s3_bucket" "test-bucket" {
  bucket = "acme-order-attachments" // bucket name
  tags = {
    Name = "order-attachments"
    Environment = "production"
  }
}

resource "aws_s3_object" "test-object" {
  bucket = aws_s3_bucket.test-bucket.id // bucket id
  key    = "templates/order_confirmation.html" // object key, s3 objects work in key-value pairs, value being the object
  source = "./templates/order_confirmation.html" // location of the object
  content_type = "text/html" // content type of the object
  tags = {
    Name = "Order Confirmation Template"
    Version = "1.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Configure the AWS Provider

// providers.tf
// This configuration changes based on the provider
provider "aws" { // 
  region     = "us-west-2"
  access_key = "<access-key>"
  secret_key = "<secret-key>"
}
Enter fullscreen mode Exit fullscreen mode

How to Use This Terraform Configuration

Now that the list is created, let's walk through how to use it to create our infrastructure. But first, let's understand the structure of our Terraform project.

Understanding Terraform Files

  1. Code Files: This is where you define your main infrastructure components. In our case, lambda.tf, api-gateway.tf and s3-bucket.tf
  2. variables.tf: Used to define input variables for your Terraform configuration.
  3. providers.tf: Contains the provider configuration (in our case, the AWS provider).

Running Terraform Commands

  1. Initialize the Terraform working directory: Run terraform init init in your project directory. This command initializes the backend, installs the required provider plugins, and prepares your working directory for other commands.
   $ terraform init

   Initializing the backend...
   Initializing provider plugins...
   - Finding latest version of hashicorp/aws...
   - Installing hashicorp/aws v4.22.0...
   - Installed hashicorp/aws v4.22.0 (signed by HashiCorp)

   Terraform has been successfully initialized!
Enter fullscreen mode Exit fullscreen mode
  1. Preview the changes Terraform will make: Run terraform plan. This command creates an execution plan, showing you what actions Terraform will take to change your infrastructure to match the configuration.
   $ 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_lambda_function.test-lambda will be created
     + resource "aws_lambda_function" "test-lambda" {
         ...
       }

     # aws_api_gateway_rest_api.test-api will be created
     + resource "aws_api_gateway_rest_api" "test-api" {
         ...
       }

     ...

   Plan: 7 to add, 0 to change, 0 to destroy.
Enter fullscreen mode Exit fullscreen mode
  1. Apply the changes: If you're happy with the plan, run terraform apply to create the resources. Terraform will show you the plan again and ask for confirmation before making any changes.
   $ terraform apply

   ... [Terraform shows the plan] ...

   Do you want to perform these actions?
     Terraform will perform the actions described above.
     Only 'yes' will be accepted to approve.

   Enter a value: yes

   aws_lambda_function.test-lambda: Creating...
   aws_api_gateway_rest_api.test-api: Creating...
   ...

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

   Outputs:

   api_url = "https://abc123def.execute-api.us-west-2.amazonaws.com/prod"
Enter fullscreen mode Exit fullscreen mode

After running these commands, Terraform will have created all the resources we defined in our configuration. The API Gateway URL where you can send requests to your Lambda function will be displayed in the outputs.

Remember, when you're done with these resources or want to remove them:

  1. Destroy the resources: Run terraform destroy to remove all the resources managed by this Terraform configuration.
   $ terraform destroy

   ... [Terraform shows the destruction plan] ...

   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_lambda_function.test-lambda: Destroying...
   aws_api_gateway_rest_api.test-api: Destroying...
   ...

   Destroy complete! Resources: 7 destroyed.
Enter fullscreen mode Exit fullscreen mode

By following these steps, you can easily manage your infrastructure using Terraform. This approach allows you to version control your infrastructure, collaborate with team members, and easily replicate your setup across different environments.

Conclusion

Terraform simplifies infrastructure management by allowing you to define, version, and deploy your infrastructure as code. It promotes consistency across environments, facilitates collaboration among team members, and automates the provisioning process. By using Terraform, you can significantly reduce manual errors, speed up deployments, and easily manage complex, multi-cloud infrastructures.

Top comments (0)