Block trong terraform 🐡

Local block

Có một nơi để định nghĩa các biến local có thể sử dụng trong module. Local values cho phép define name và value để có thể tái sử dụng và chỉ có thể truy cập được ở trong module mà chúng được định nghĩa (không phải global scope). Local values được định nghĩa trong block này là bất biến, không thể bị thay đổi sau khi được định nghĩa. Dí dụ như bạn cần định nghĩa danh sách subnet IDs được tham chiếu từ nhiều resource:

  locals {
    subnet_ids = [aws_subnet.public_1.id, aws_subnet.public_2.id] 
  }

Data block

Trong bài trước, khi cấu hình tạo mới EC2 instance ta phải define cụ thể giá trị của ami, điều này gây ra sự bất tiện khi tìm kiếm, giá trị được định nghĩa có thể bị thay đổi và thường là những giá trị không thể hiện thông tin cho cấu hình.

Data block là một tính năng của Terraform cho phép tạo ra các tham số được lưu trữ trong tệp Terraform, như một dạng của dữ liệu môi trường. Khi sử dụng data block, có thể định nghĩa một tham số và ánh xạ giá trị của tham số từ một nguồn dữ liệu bên ngoài, ví dụ như AWS Marketplace hay AWS Systems Manager. Điều này giúp cho code Terraform trở nên an toàn và linh hoạt hơn.

Block này thường được dùng để gọi API lên hạ tầng qua Provider và lấy thông tin về resource, nó sẽ không thực hiện hành động tạo resource trên hạ tầng. Cập nhật file main.tf lại như sau:

  provider "aws" {
    region = "ap-southeast-1"
  }

  data "aws_ami" "al2023" {
    most_recent = true

    filter {
      name   = "name"
      values = ["al2023-ami-2023.*-x86_64"]
    }
  }

  resource "aws_instance" "hello" {
    ami           = data.aws_ami.al2023.id
    instance_type = "t2.micro"
    tags = {
      Name = "HelloWorld"
    }
  }

Block data "aws_ami" "al2023" tìm kiếm thông tin chi tiết của AWS AMI theo điều kiện:

  • most_recent trả về giá trị AMI cuối khớp với filter.
  • filter block chỉ rõ việc filter theo name và cung cấp regex pattern khớp với AMI name "al2023-ami-2023.*-x86_64".

Khi chạy, block này được chạy trước. Terraform sử dụng AWS API và fetch về thông tin chi tiết của AMI. Sau đó, kết quả sẽ có thể sử dụng ở nơi khác bằng cách sử dụng value từ biến data, ở ví dụ trên sử dụng AMI ID cho việc khởi tạo EC2.

Dynamic block 💪

Hãng phim phương nam xin trân trọng giới thiệu một tính năng khác cực kỳ mạnh mẽ trong Terraform là dynamic block. Block này được định nghĩa bên trong resource, data, provider, etc... cho phép tạo các block động từ các collection, list hay map, giúp giảm việc lặp lại khi gõ bàn phím, linh hoạt, tái sử dụng, dễ dàng bảo trì, nhà sạch thì mát, code sạch ngon hơn.

Ví dụ, để tạo nhiều AWS security groups cho phép truy cập từ một map CIDR block sẽ define dynamic "resource" block như sau:

  locals {
    map = {
      "HTTP" = {
        port = 80,
        cidr_blocks = ["0.0.0.0/0"],
      }
      "SSH" = {
        port = 22,
        cidr_blocks = ["10.0.0.0/16"],
      }
      "HTTPS" = {
        port = 443,
        cidr_blocks = ["0.0.0.0/0"],
      }
    }
  }
  resource "aws_security_group" "mysg" {
    name        = "webserver"
    description = "Inbound Rules for WebServer"

    dynamic "ingress" {
      for_each = local.map
      iterator = each
      content {
        description = each.key
        from_port   = each.value.port
        to_port     = each.value.port
        protocol    = "tcp"
        cidr_blocks = each.value.cidr_blocks
      }
    }
  }

Sử dụng "for_each" meta-parameter để lặp lại việc tạo Inbound Rules từ dynamic "ingress" block với giá trị lấy từ map trong locals block. Với mỗi cặp key-value trong biến locals.map, tạo ra một ingress role với value tương ứng.