EP3: Ngôn ngữ HCL và Cấu trúc File Terraform Cơ bản

Dat Ngo TienDat Ngo Tien
9 min read

Bạn đã cài đặt xong Terraform, AWS CLI và cả VS Code rồi chứ? Tuyệt vời! Vậy là môi trường làm việc của chúng ta đã sẵn sàng. Giờ đây, câu hỏi đặt ra là: "Làm thế nào để 'nói chuyện' với Terraform và yêu cầu nó tạo ra các tài nguyên trên AWS?" Câu trả lời chính là HCL - HashiCorp Configuration Language.

Trong bài viết này, chúng ta sẽ cùng nhau:

  • Tìm hiểu HCL là gì và tại sao Terraform lại chọn nó.

  • Khám phá cú pháp cơ bản của HCL: blocks, arguments, comments.

  • Làm quen với các kiểu dữ liệu phổ biến trong HCL.

  • Hiểu cấu trúc của một tệp tin Terraform (.tf) cơ bản.

  • Thực hành với một ví dụ nhỏ để làm quen.

Nào, hãy cùng giải mã ngôn ngữ của Terraform!

HCL là gì? Ngôn ngữ Giao tiếp với Terraform

HCL (HashiCorp Configuration Language) là một ngôn ngữ cấu hình được phát triển bởi HashiCorp. Nó được thiết kế với mục tiêu cân bằng giữa việc dễ đọc, dễ viết cho con ngườidễ phân tích, xử lý cho máy tính. HCL là ngôn ngữ chính bạn sẽ sử dụng để viết các tệp tin cấu hình cho Terraform, cũng như nhiều công cụ khác của HashiCorp như Vault, Consul, Nomad.

Đặc điểm chính của HCL:

  • Khai báo (Declarative): Thay vì chỉ thị từng bước thực hiện (imperative), với HCL, bạn mô tả "trạng thái mong muốn" của hạ tầng. Ví dụ, bạn khai báo "Tôi muốn một máy chủ AWS EC2 loại t2.micro, chạy AMI X". Terraform sẽ tự động tìm cách để đạt được trạng thái đó.

  • Cú pháp rõ ràng, trực quan: HCL được thiết kế để mô tả hạ tầng, nên cú pháp của nó khá gần gũi và dễ hiểu, ngay cả với người mới.

  • Tập trung vào cấu hình: Không phải là một ngôn ngữ lập trình đa năng, HCL tập trung vào việc định nghĩa cấu hình và các mối quan hệ giữa chúng.

Cú pháp Cơ bản của HCL (Basic Syntax of HCL)

Cấu hình Terraform được viết trong các tệp tin văn bản có đuôi .tf. Hãy cùng xem xét các thành phần cú pháp chính:

  1. Blocks (Khối):

    • Blocks là những "container" chính chứa đựng các cấu hình. Mỗi block định nghĩa một đối tượng hoặc một phần cấu hình cụ thể.

    • Một block bao gồm:

      • Block Type (Loại khối): Ví dụ: terraform, provider, resource, variable, output, data.

      • Labels (Nhãn - nếu có): Một số block type có thể có một hoặc nhiều nhãn để phân biệt. Ví dụ, provider "aws" (nhãn là "aws"), resource "aws_instance" "my_server" (nhãn là "aws_instance" và "my_server").

      • Block Body (Thân khối): Được bao bọc bởi dấu ngoặc nhọn { }, chứa các arguments (đối số) định nghĩa cấu hình cho block đó.

<!-- end list -->

Terraform

    # Ví dụ một block "provider"
    provider "aws" { # "provider" là block type, "aws" là label
      # Đây là thân khối (block body)
      region = "ap-southeast-1" # Đây là một argument
    }
  1. Arguments (Đối số):

    • Arguments nằm bên trong thân khối, dùng để gán giá trị cho các thuộc tính cấu hình.

    • Cú pháp: identifier = expression (tên đối số = giá trị).

    • Ví dụ: region = "ap-southeast-1", instance_type = "t2.micro".

  2. Identifiers (Định danh):

    • Là tên được sử dụng cho arguments, block types, và labels. Chúng có thể chứa chữ cái, số, dấu gạch dưới (_), và dấu gạch nối (-).
  3. Expressions (Biểu thức):

    • Là các giá trị được gán cho arguments. Giá trị này có thể là:

      • Một giá trị cố định (literal value) như chuỗi, số, boolean.

      • Một tham chiếu đến giá trị khác (ví dụ: giá trị của một biến, thuộc tính của một resource khác).

      • Kết quả của một hàm (function call).

  4. Comments (Chú thích):

    • Dùng để giải thích code, giúp người khác (và chính bạn trong tương lai) hiểu rõ hơn về cấu hình. Comments sẽ được Terraform bỏ qua khi xử lý.

    • Single-line comments (chú thích một dòng): Bắt đầu bằng # hoặc //. Terraform

        # Đây là một comment
        // Đây cũng là một comment
      
    • Multi-line comments (chú thích nhiều dòng): Bắt đầu bằng /* và kết thúc bằng */. Terraform

        /*
        Đây là
        một comment
        trên nhiều dòng.
        */
      

Các Kiểu Dữ liệu Cơ bản trong HCL (Basic Data Types in HCL)

HCL hỗ trợ các kiểu dữ liệu cơ bản sau:

  • string (Chuỗi):

    • Một chuỗi các ký tự, được đặt trong dấu ngoặc kép "".

    • Ví dụ: "Hello, Terraform!", "ap-southeast-1", "ami-0c55b31ad0d39a457".

    • Nội suy chuỗi (String Interpolation): Bạn có thể nhúng giá trị của biến hoặc biểu thức vào trong chuỗi bằng cú pháp ${...}. Terraform

        variable "instance_name" {
          type    = string
          default = "MyServer"
        }
      
        resource "aws_instance" "example" {
          # ...
          tags = {
            Name = "Instance: ${var.instance_name}" # Nội suy biến instance_name
          }
        }
      
  • number (Số):

    • Các giá trị số, có thể là số nguyên hoặc số thực.

    • Ví dụ: 80, 443, 3.14159.

  • bool (Boolean):

    • Chỉ có hai giá trị: true hoặc false.

    • Ví dụ: enabled = true.

  • list (Danh sách):

    • Một danh sách các giá trị có thứ tự, được đặt trong dấu ngoặc vuông [], các phần tử cách nhau bởi dấu phẩy. Các phần tử trong list có thể cùng kiểu hoặc khác kiểu (nhưng thường là cùng kiểu).

    • Ví dụ: ["subnet-123", "subnet-456"], [80, 443, 22].

  • map (Ánh xạ) / object (Đối tượng):

    • Một tập hợp các cặp key = value, được đặt trong dấu ngoặc nhọn {}. Keys phải là chuỗi, values có thể thuộc bất kỳ kiểu dữ liệu nào.

    • map: Các keys không được định nghĩa trước, linh hoạt.

    • object: Các keys (thuộc tính) và kiểu dữ liệu của chúng được định nghĩa trước (thường thấy trong khai báo variable với type object(...)).

    • Ví dụ (map): Terraform

        tags = {
          Name        = "My EC2 Instance"
          Environment = "Development"
          Project     = "Terraform Learning"
        }
      
  • null:

    • Đại diện cho một giá trị không tồn tại hoặc bị bỏ qua. Hữu ích khi bạn muốn một đối số là tùy chọn.

Cấu trúc một File Terraform Cơ bản (.tf)

Các tệp tin cấu hình Terraform thường có đuôi là .tf. Khi bạn chạy lệnh terraform apply (hoặc plan, init), Terraform sẽ đọc tất cả các tệp .tf trong thư mục làm việc hiện tại và gộp chúng lại thành một cấu hình tổng thể.

Một tệp main.tf đơn giản thường bắt đầu với các khối sau:

  1. Khối terraform {} (Terraform Block):

    • Chứa các thiết lập liên quan đến hành vi của chính Terraform.

    • Quan trọng nhất là khối required_providers {} bên trong nó, dùng để khai báo các providers mà cấu hình của bạn cần và phiên bản của chúng. Việc chỉ định phiên bản giúp đảm bảo tính ổn định và tránh các thay đổi không mong muốn khi provider được cập nhật.

  2. Khối provider {} (Provider Block):

    • Khai báo và cấu hình một provider cụ thể (ví dụ: aws, azurerm, google).

    • Mỗi provider có các đối số cấu hình riêng. Ví dụ, provider aws thường yêu cầu region.

Đây là ví dụ về cấu trúc file main.tf cơ bản cho AWS:

Terraform

# main.tf

# Khối cấu hình Terraform
terraform {
  required_version = ">= 1.0" # Chỉ định phiên bản Terraform tối thiểu

  required_providers {
    aws = {
      source  = "hashicorp/aws" # Nguồn của provider trên Terraform Registry
      version = "~> 5.0"        # Chỉ định phiên bản provider, ví dụ: phiên bản 5.x mới nhất
                                # Dấu ~> (pessimistic constraint operator) cho phép các bản vá lỗi (patch)
                                # mà không tự động nâng cấp lên phiên bản lớn (major) tiếp theo.
    }
  }
}

# Khối cấu hình Provider AWS
provider "aws" {
  region = "ap-southeast-1" # Ví dụ: chọn region Singapore
  # Thông tin xác thực (Access Key, Secret Key) thường được Terraform lấy
  # từ AWS CLI đã cấu hình (aws configure) hoặc biến môi trường.
  # Không nên hardcode credentials ở đây!
}

# Các khối "resource", "variable", "output", "data" sẽ được thêm vào đây sau.
# Ví dụ:
# resource "aws_s3_bucket" "my_bucket" {
#   bucket = "my-unique-terraform-learning-bucket-12345" # Tên bucket phải là duy nhất toàn cầu
# }

Thực hành nhỏ:

  1. Trong thư mục dự án bạn đã tạo ở Bài 2 (ví dụ terraform-aws-project), tạo một tệp mới tên là main.tf.

  2. Sao chép nội dung ví dụ trên vào tệp main.tf của bạn. Bạn có thể thay đổi region nếu muốn.

  3. Mở Terminal/Command Prompt trong thư mục dự án.

  4. Chạy lệnh terraform init. Lệnh này sẽ đọc khối required_providers và tải xuống plugin AWS provider từ Terraform Registry.

  5. Chạy lệnh terraform fmt. Lệnh này sẽ tự động định dạng lại code trong main.tf cho đúng chuẩn.

  6. Chạy lệnh terraform validate. Lệnh này sẽ kiểm tra cú pháp của file cấu hình. Nếu không có lỗi, bạn sẽ thấy thông báo "Success! The configuration is valid."

Ở bước này, chúng ta chưa tạo bất kỳ tài nguyên nào trên AWS, chỉ đơn giản là làm quen với cấu trúc file và một số lệnh Terraform cơ bản.

Lời khuyên khi viết HCL

  • Sử dụng terraform fmt thường xuyên: Luôn chạy lệnh này trước khi commit code để đảm bảo code của bạn được định dạng nhất quán. Nhiều IDE có thể tự động chạy lệnh này khi lưu file.

  • Viết comments rõ ràng: Giải thích mục đích của các khối code phức tạp hoặc các quyết định thiết kế quan trọng.

  • Tổ chức file hợp lý: Khi dự án lớn hơn, hãy chia cấu hình ra nhiều file (ví dụ: providers.tf, variables.tf, ec2.tf, s3.tf, outputs.tf) để dễ quản lý.

  • Giữ cho code đơn giản và dễ đọc: Ưu tiên sự rõ ràng hơn là viết code quá phức tạp hoặc "thông minh" một cách không cần thiết.

Kết luận

Chúc mừng bạn đã làm quen với HCL - ngôn ngữ chính để giao tiếp với Terraform! Bạn đã hiểu về blocks, arguments, các kiểu dữ liệu cơ bản và cấu trúc của một tệp .tf. Việc thực hành với terraform init, fmt, và validate cũng giúp bạn hình dung rõ hơn về quy trình làm việc ban đầu.

Trong Bài 4: Kết nối Terraform với AWS - Giới thiệu AWS Provider và Xác thực, chúng ta sẽ đi sâu hơn vào cách cấu hình AWS provider, đảm bảo Terraform có thể "nói chuyện" và "ra lệnh" cho tài khoản AWS của bạn. Chúng ta cũng sẽ bắt đầu định nghĩa những tài nguyên AWS thực sự đầu tiên!

0
Subscribe to my newsletter

Read articles from Dat Ngo Tien directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Dat Ngo Tien
Dat Ngo Tien

Hi friend. Nice to meet you in here. Hope you will find useful information on the blog. Follow and chill with me.