Thursday, November 21, 2024

Ví dụ về file layout trong Terraform

-

Tổng quan.

Đây là một ví dụ về cấu trúc file của Terraform trên AWS (Amazon Web Services). Ví dụ này sử dụng Terraform AWS Provider để tương tác với nhiều tài nguyên được hỗ trợ bởi AWS thông qua các API của nó và ví dụ này triển khai trên Terraform phiên bản 0.10.x.

Cấu hình các khóa truy cập AWS của bạn.

Vì lý do bảo mật, nên sử dụng người dùng IAM thay vì tài khoản gốc để truy cập vào AWS.

Cấu hình thông tin xác thực AWS để sử dụng bởi Terraform có thể được thực hiện theo nhiều cách khác nhau, nhưng đây là những cách tiếp cận được khuyến khích:

Cách 1: Cài đặt thông tin xác thực AWS trên hệ thống local của bạn, đối với Linux, macOS hoặc Unix:

~/.aws/credentials

Hoặc đối với Windows nằm tại.

C:\Users\USERNAME\.aws\credentials

File này nên chứa các dòng theo định dạng dưới, lưu ý hãy thay thế các giá trị thông tin xác thực AWS của bạn vào các giá trị <your_access_key_id> và <your_secret_access_key> trong file.

[default]
aws_access_key_id = <your_access_key_id>
aws_secret_access_key = <your_secret_access_key>

Cách 2: Đặt các biến môi trường AWS_ACCESS_KEY_ID và AWS_SECRET_ACCESS_KEY.

Để đặt các biến này trên Linux, macOS hoặc Unix, sử dụng lệnh export:

export AWS_ACCESS_KEY_ID=<your_access_key_id>
export AWS_SECRET_ACCESS_KEY=<your_secret_access_key>

Đối với windows hãy sử dụng set:

set AWS_ACCESS_KEY_ID=<your_access_key_id>
set AWS_SECRET_ACCESS_KEY=<your_secret_access_key>

Giới thiệu sơ về project Terraform này.

Đây là một ví dụ về cấu trúc file của Terraform trên AWS (Amazon Web Services). Thư mục chính có hai thư mục con là “global” và “stage”. Trong thư mục “global” có một ví dụ về cách sử dụng “Terraform Remote State” để quản lý trạng thái từ xa, cụ thể là lưu trữ trên S3. Thư mục “stage” chứa hai thư mục con là “services” và “data-stores”. Trong thư mục “services”, ví dụ cho việc triển khai một cụm máy chủ web bằng “Terraform Web Server Cluster”. Trong thư mục “data-stores”, có một ví dụ về cách triển khai máy chủ MySQL trên RDS bằng “Terraform MySQL on RDS”. Tổng quan về cấu trúc thư mục này cho phép người dùng tổ chức và quản lý các file Terraform của họ theo cách hợp lý và có thể mở rộng.

Và đây là cách bố trí các file của Terraform:

global
    └── s3/
        ├── main.tf
        └── (etc)

stage
    ├── services/
    │   └── webserver-cluster/
    │       ├── main.tf
    │       └── (etc)
    └── data-stores/
        └── mysql/
            ├── main.tf
            └── (etc)

Tạo thư mục và file Terraform khởi tạo bucket S3.

Tạo thư mục s3.

mkdir -p global/s3

Trong thư mục global/s3 chúng ta tạo các file lần lượt như sau:

– global/s3/main.tf

# Configure the AWS provider
provider "aws" {
  region = "eu-west-1"
}

# Create a S3 bucket
resource "aws_s3_bucket" "terraform_state" {
  bucket		  = "${var.bucket_name}"
  
  versioning {
    enabled = true
  }  
  
  lifecycle {
    prevent_destroy = true
  }
}

– outputs.tf

# Output variable: S3 bucket
output "s3_bucket_arn" {
  value = "${aws_s3_bucket.terraform_state.arn}"
}

– global/s3/vars.tf

# Input variable: S3 bucket name
variable "bucket_name" {
  description = "The name of the S3 bucket. Must be globally unique."
  default = "terraform-state-my-bucket"
}

Đoạn code này là một file cấu hình Terraform để triển khai tạo một bucket S3 trên AWS và lưu trữ state file của Terraform trên bucket S3 này. Cụ thể, đoạn code bao gồm:

  • Phần cấu hình AWS Provider để thiết lập kết nối với AWS và sử dụng region “eu-west-1”.
  • Phần tạo resource “aws_s3_bucket” để tạo một bucket S3 với tên là “${var.bucket_name}”. Đối tượng này có hai cấu hình được thiết lập:
    • versioning: bật chế độ versioning trên bucket S3.
    • lifecycle: thiết lập prevent_destroy = true để ngăn ngừa xóa bucket S3 bằng cách sử dụng lệnh “terraform destroy”.
  • Phần khai báo biến đầu vào “bucket_name” để chứa tên của bucket S3 cần tạo. Biến này được mặc định là “terraform-state-my-bucket”.
  • Phần khai báo biến đầu ra “s3_bucket_arn” để hiển thị ARN của bucket S3 vừa tạo sau khi chạy lệnh “terraform apply”. ARN được lưu vào biến và có thể được sử dụng trong các module khác của Terraform.

Sau khi chạy lệnh “terraform apply”, Terraform sẽ tạo một bucket S3 với tên “${var.bucket_name}” và lưu trữ state file của Terraform trên bucket S3 này. Biến đầu ra “s3_bucket_arn” sẽ hiển thị ARN của bucket S3 vừa tạo, cho phép bạn sử dụng bucket này trong các module khác của Terraform.

Tạo thư mục chứa mysql và webserver-cluster.

Tiếp theo chúng ta tạo tiếp 2 thư mục /stage/data-stores/mysql/ và /stage/services/webserver-cluster/

mkdir -p /stage/data-stores/mysql/
mkdir -p /stage/services/webserver-cluster/

Tạo file Terraform cho mysql.

Lần lượt tạo các file nằm trong 2 thư mục này như sauL:

– /stage/data-stores/mysql/backend.tf

# Define Terraform backend using a S3 bucket for storing the Terraform state
terraform {
  backend "s3" {
    bucket = "terraform-state-my-bucket"
    key = "file-layout/stage/data-stores/mysql/terraform.tfstate"
    region = "eu-west-1"
  }
}

– /stage/data-stores/mysql/main.tf

# Configure the AWS provider
provider "aws" {
  region = "eu-west-1"
}

# Create a DB instance
resource "aws_db_instance" "example" {
  engine              = "mysql"
  allocated_storage   = 10
  instance_class      = "db.t2.micro"
  name                = "example_database"
  username            = "admin"
  password            = "${var.db_password}"
  skip_final_snapshot = true
}

– /stage/data-stores/mysql/outputs.tf

# Output variable: DB instance address
output "address" {
  value = "${aws_db_instance.example.address}"
}

# Output variable: DB instance port
output "port" {
  value = "${aws_db_instance.example.port}"
}

– /stage/data-stores/mysql/vars.tf

# Input variable: DB password
variable "db_password" {
  description = "The password for the database"
}

Đoạn code trên có chức năng tạo ra một instance database trên AWS RDS (Relational Database Service) và sử dụng S3 bucket để lưu trữ Terraform state.

Phần đầu tiên định nghĩa backend cho Terraform bằng S3 bucket với bucket name “terraform-state-my-bucket” và key là “file-layout/stage/data-stores/mysql/terraform.tfstate”.

Phần tiếp theo là cấu hình AWS provider với region là “eu-west-1”.

Tiếp theo là tạo một instance database trên AWS RDS bằng cách sử dụng resource “aws_db_instance”. Các thuộc tính của instance database bao gồm engine, allocated_storage, instance_class, name, username, password và skip_final_snapshot.

Sau đó, đoạn code định nghĩa hai output variables: “address” và “port” để xuất ra địa chỉ và cổng của instance database.

Cuối cùng, đoạn code định nghĩa một input variable “db_password” để lưu trữ mật khẩu cho instance database.

Tạo file Terraform cho webserver-cluster.

– /stage/services/webserver-cluster/backend.tf

# Define Terraform backend using a S3 bucket for storing the Terraform state
terraform {
  backend "s3" {
    bucket  = "terraform-state-my-bucket"
    key     = "file-layout-example/stage/services/webserver-cluster/terraform.tfstate"
    region  = "eu-west-1"
  }
}

– /stage/services/webserver-cluster/main.tf

# Configure the AWS provider
provider "aws" {
  region = "eu-west-1"
}

# Data source: query the list of availability zones
data "aws_availability_zones" "all" {}

# Data source: DB remote state
data "terraform_remote_state" "db" {
  backend = "s3"
  
  config {
    bucket = "${var.db_remote_state_bucket}"
    key    = "${var.db_remote_state_key}"
    region = "eu-west-1"
  }
}

# Data source: Template file
data "template_file" "user_data" {
  template = "${file("user-data.sh")}"
  
  vars {
    server_port = "${var.server_port}"
    db_address  = "${data.terraform_remote_state.db.address}"
    db_port     = "${data.terraform_remote_state.db.port}"
  }
}

# Create a Security Group for an EC2 instance
resource "aws_security_group" "instance" {
  name = "terraform-example-instance"
  
  ingress {
    from_port	  = "${var.server_port}"
    to_port		  = "${var.server_port}"
    protocol	  = "tcp"
    cidr_blocks	= ["0.0.0.0/0"]
  }

  lifecycle {
    create_before_destroy = true
  }
}

# Create a Security Group for an ELB
resource "aws_security_group" "elb" {
  name = "terraform-example-elb"
  
  ingress {
    from_port	  = 80
    to_port	    = 80
    protocol	  = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port	  = 0
    to_port	    = 0
    protocol	  = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# Create a Launch Configuration
resource "aws_launch_configuration" "example" {
  image_id	      = "ami-785db401"
  instance_type   = "t2.micro"
  security_groups = ["${aws_security_group.instance.id}"]
  user_data       = "${data.template_file.user_data.rendered}"
  
  lifecycle {
    create_before_destroy = true
  }
}

# Create an Autoscaling Group
resource "aws_autoscaling_group" "example" {
  launch_configuration = "${aws_launch_configuration.example.id}"
  availability_zones   = ["${data.aws_availability_zones.all.names}"]
  
  load_balancers       = ["${aws_elb.example.name}"]
  health_check_type    = "ELB"
  
  min_size = 2
  max_size = 10
  
  tag {
    key                 = "Name"
    value               = "terraform-asg-example"
    propagate_at_launch = true
  }
}

# Create an ELB
resource "aws_elb" "example" {
  name               = "terraform-asg-example"
  availability_zones = ["${data.aws_availability_zones.all.names}"]
  security_groups    = ["${aws_security_group.elb.id}"]
  
  listener {
    lb_port           = 80
    lb_protocol       = "http"
    instance_port     = "${var.server_port}"
    instance_protocol = "http"
  }
  
  health_check {
    healthy_threshold   = 2
    unhealthy_threshold = 2
    timeout             = 3
    interval            = 30
    target              = "HTTP:${var.server_port}/"
  }
}

– /stage/services/webserver-cluster/outputs.tf

# Output variable: DNS Name of ELB
output "elb_dns_name" {
  value = "${aws_elb.example.dns_name}"
}

– /stage/services/webserver-cluster/user-data.sh

#!/bin/bash
cat > index.html <<EOF
<h1>Hello, World</h1>
<p>DB address: ${db_address}</p>
<p>DB port: ${db_port}</p>
EOF
nohup busybox httpd -f -p "${server_port}" &

– /stage/services/webserver-cluster/vars.tf

# Input variable: server port
variable "server_port" {
  description = "The port the server will use for HTTP requests"
  default     = "8080"
}

# Input variable: DB remote state bucket name
variable "db_remote_state_bucket" {
  description = "The name of the S3 bucket used for the database's remote state storage"
  default     =  "terraform-state-my-bucket"
}

# Input variable: DB remote state bucket key
variable "db_remote_state_key" {
  description = "The name of the key in the S3 bucket used for the database's remote state storage"
  default     = "file-layout-example/stage/data-stores/mysql/terraform.tfstate"
}

Đoạn code này sử dụng Terraform để triển khai một ứng dụng web trên Amazon Web Services (AWS) bao gồm:

  • Định nghĩa backend cho Terraform sử dụng một bucket S3 để lưu trữ trạng thái của Terraform.
  • Cấu hình provider AWS sử dụng khu vực eu-west-1.
  • Sử dụng các data source của AWS để lấy thông tin về danh sách các khu vực có thể sử dụng và truy cập trạng thái của một resource khác lưu trữ trong một bucket S3 khác.
  • Định nghĩa các resource của AWS như security group, launch configuration, autoscaling group và Elastic Load Balancer (ELB) để triển khai ứng dụng web, sử dụng các thông số được cấu hình.
  • Định nghĩa một biến đầu vào để xác định cổng của server và hai biến đầu vào khác để xác định thông tin lưu trữ trạng thái từ một bucket S3 khác.

Trong chi tiết hơn, các resource được tạo ra bao gồm:

  • aws_security_group: định nghĩa một security group cho EC2 instance.
  • aws_security_group: định nghĩa một security group cho ELB.
  • aws_launch_configuration: định nghĩa một Launch Configuration cho EC2 instance.
  • aws_autoscaling_group: định nghĩa một Autoscaling Group, bao gồm launch configuration, ELB và các khu vực khả dụng, cùng với các thông số tối thiểu và tối đa cho số lượng instances.
  • aws_elb: định nghĩa một Elastic Load Balancer (ELB) với các thông số như listener, health check và security group.
  • output: định nghĩa một biến đầu ra cho DNS của ELB.

Đoạn code này cũng bao gồm một file user-data.sh, được sử dụng để tạo một trang web đơn giản chứa thông tin về địa chỉ và cổng của database lưu trữ trạng thái.

Chi phí triển khai

Việc tính toán chi phí cho ví dụ này phụ thuộc vào nhiều yếu tố như địa lý, kích thước của hệ thống, mức độ sử dụng tài nguyên, thời gian sử dụng và nhiều yếu tố khác nữa. Tuy nhiên, bạn có thể dùng bộ tính giá của AWS để ước tính chi phí cụ thể cho ví dụ này. Hãy lưu ý rằng việc sử dụng tài nguyên của AWS sẽ phát sinh chi phí, vì vậy bạn nên cẩn thận khi thiết kế và triển khai hệ thống để tránh lãng phí tài nguyên và tài chính.

Để tính toán chi phí cho các tài nguyên đang chạy trên AWS, bạn có thể sử dụng AWS Simple Monthly Calculator. Đây là một bộ tính chi phí trực tuyến cung cấp thông tin về giá cho các dịch vụ AWS phổ biến nhất.

Để sử dụng bộ tính này, bạn có thể thực hiện các bước sau:

  • Truy cập trang AWS Simple Monthly Calculator trên trình duyệt của bạn.
  • Chọn dịch vụ AWS mà bạn muốn tính toán chi phí.
  • Nhập thông tin về tài nguyên và số lượng.
  • Chỉnh sửa các cài đặt chi tiết (nếu cần).
  • Tính toán chi phí.

Với ví dụ trên, bạn có thể thêm các tài nguyên vào bộ tính, cung cấp thông tin chi tiết về mỗi tài nguyên, và sau đó tính toán chi phí ước tính. Chú ý rằng chi phí thực tế có thể khác so với chi phí ước tính, do một số yếu tố như tần suất sử dụng và các điều kiện giá khác nhau.

Nếu bạn triển khai và xoá ngay sau đó, thì chi phí phát sinh sẽ khá ít. Tuy nhiên, có một số chi phí nhỏ liên quan đến việc sử dụng các dịch vụ AWS như S3, RDS, EC2, ELB, … Ví dụ, chi phí cho việc lưu trữ S3 bucket hoặc chi phí cho việc sử dụng RDS DB instance trong thời gian ngắn. Chi phí sử dụng các dịch vụ này sẽ được tính dựa trên thời gian sử dụng và các tài nguyên đã sử dụng.

Ngoài ra, chi phí có thể tăng lên nếu bạn sử dụng các tính năng khác của các dịch vụ này hoặc nếu bạn để lại các tài nguyên chưa xoá sau khi triển khai. Do đó, nếu bạn muốn giảm thiểu chi phí, bạn nên xoá các tài nguyên không sử dụng sau khi triển khai hoàn tất.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4,956FansLike
256FollowersFollow
223SubscribersSubscribe
spot_img

Related Stories