Thursday, November 21, 2024

Ví dụ về sử dụng module ở repo khác trong Terraform để triển khai dịch vụ trên AWS

-

Tổng quan.

Bài này chỉ ra cách triển khai không sử dụng phương thức sao chép các đoạn code trên các cụm máy chủ web bằng cách sử dụng một module trong một repo khác để sử dụng phiên bản khác của module trong nhiều môi trường. 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.

Bài này chỉ ra cách triển khai mà không sử dụng phương thức sao chép các đoạn code trên các cụm máy chủ web bằng cách sử dụng một module trong một repo khác để sử dụng phiên bản khác của module trong nhiều môi trường

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

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

Và đây là cách bố trí các file ở một repo khác.

modules
    └── services/
        └── webserver-cluster/
            ├── main.tf
            └── (etc)

Phần này sử dụng chung cho cả hai môi trường:

  • Ví dụ Terraform Remote State nằm trong thư mục live/global/s3
  • Ví dụ về module cluster webserver trong một repo khác: terraform-aws-repo-examples/modules/services/webserver-cluster/

Sử dụng cho stage:

  • Ví dụ về Terraform MySQL trên RDS (stage): live/stage/data-stores/mysql
  • Ví dụ về cụm máy chủ web Terraform (stage): live/stage/services/webserver-cluster

Sử dụng cho Prod:

  • Ví dụ về Terraform MySQL trên RDS (Prod): live/prod/data-stores/mysql
  • Ví dụ về Terraform Web Server Cluster (Prod): live/prod/services/webserver-cluster

Lưu ý: Các file trên các bạn tạo xong rồi push lên git nhé.

Tạo other repo.

– terraform-aws-repo-examples/modules/services/webserver-cluster/main.tf

# 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("${path.module}/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 = "${var.cluster_name}-instance"
  
  lifecycle {
    create_before_destroy = true
  }
}

# Create a Security Group Rule
resource "aws_security_group_rule" "allow_server_http_inbound" {
  type = "ingress"
  security_group_id = "${aws_security_group.instance.id}"
  
  from_port	  = "${var.server_port}"
  to_port	  = "${var.server_port}"
  protocol	  = "tcp"
  cidr_blocks = ["0.0.0.0/0"]

}

# Create a Security Group for an ELB
resource "aws_security_group" "elb" {
  name = "${var.cluster_name}-elb"
}

# Create a Security Group Rule, inbound
resource "aws_security_group_rule" "allow_http_inbound" {
  type              = "ingress"
  security_group_id = "${aws_security_group.elb.id}"
  
  from_port	  = 80
  to_port	  = 80
  protocol	  = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
}

# Create a Security Group Rule, outbound
resource "aws_security_group_rule" "allow_all_outbound" {
  type              = "egress"
  security_group_id = "${aws_security_group.elb.id}"
  
  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   = "${var.instance_type}"
  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 = "${var.min_size}"
  max_size = "${var.max_size}"
  
  tag {
    key                 = "Name"
    value               = "${var.cluster_name}"
    propagate_at_launch = true
  }
}

# Create an ELB
resource "aws_elb" "example" {
  name               = "${var.cluster_name}"
  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}/"
  }
}

Đoạn code này sử dụng Terraform để tạo ra một infra đơn giản trên AWS, bao gồm một ELB, một Autoscaling Group và một Launch Configuration.

Trong đoạn code, các data source được sử dụng để thu thập thông tin như danh sách các availability zone, hoặc để truy xuất dữ liệu từ một remote state đã được lưu trữ trước đó trong một file S3.

Sau đó, các resource được định nghĩa để tạo ra các tài nguyên trên AWS, bao gồm:

  • aws_security_group được sử dụng để tạo một security group cho EC2 instance và ELB, với các security group rule để chỉ định các luồng truy cập (inbound/outbound) được phép.
  • aws_launch_configuration được sử dụng để cấu hình các thuộc tính của EC2 instance, bao gồm kích thước, hình ảnh và user data (một script sẽ được thực thi khi instance khởi động).
  • aws_autoscaling_group được sử dụng để tạo ra một nhóm các EC2 instance, được quản lý bởi Autoscaling Group, với số lượng tối thiểu và tối đa được xác định và được gắn thẻ với tên cluster_name.
  • aws_elb được sử dụng để tạo ra một Elastic Load Balancer (ELB) và cấu hình các thuộc tính của nó, bao gồm health check để đảm bảo rằng các instance đang hoạt động đúng cách.

Tổng quan, đoạn code này cung cấp một khung khôi phục và mở rộng cho các ứng dụng được chạy trên EC2 instance trên AWS.

– terraform-aws-repo-examples/modules/services/webserver-cluster/outputs.tf

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

# Output variable: Auto Scaling Group name
output "asg_name" {
  value = "${aws_autoscaling_group.example.name}"
}

# Output variable: ELB Security Group Id
output "elb_security_group_id" {
  value = "${aws_security_group.elb.id}"
}

Đoạn code này định nghĩa 3 biến output cho Terraform sử dụng sau khi deploy. Output là các giá trị được xuất ra từ quá trình thực thi các tài nguyên cụ thể trong code. Các biến output được định nghĩa như sau:

  • Biến elb_dns_name là một output trả về DNS Name của ELB được tạo ra, thông qua việc sử dụng resource aws_elb để tạo ELB.
  • Biến asg_name là một output trả về tên của Autoscaling Group, thông qua việc sử dụng resource aws_autoscaling_group để tạo Autoscaling Group.
  • Biến elb_security_group_id là một output trả về ID của Security Group được tạo ra cho ELB, thông qua việc sử dụng resource aws_security_group để tạo Security Group.

Những giá trị được trả về bởi các biến output này có thể được sử dụng trong các module khác hoặc làm đầu vào cho những công cụ bên ngoài Terraform.

– terraform-aws-repo-examples/modules/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}" &

Đoạn code này là một script shell, chạy trên máy ảo EC2, được sử dụng để tạo nội dung cho trang web đơn giản. Script này sẽ tạo một file index.html chứa nội dung trang web đơn giản, bao gồm tiêu đề “Hello, World” và hai dòng văn bản tương ứng với địa chỉ và cổng của máy chủ cơ sở dữ liệu. Sau đó, script sẽ sử dụng Busybox để khởi động một máy chủ web HTTP đơn giản, lắng nghe kết nối đến cổng được chỉ định (được đặt trong biến server_port) và phục vụ trang web index.html.

Lệnh nohup được sử dụng để chạy Busybox web server ở chế độ daemon, tức là nó sẽ tiếp tục chạy ngay cả khi phiên ssh bị gián đoạn hoặc ngắt kết nối.

– terraform-aws-repo-examples/modules/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: Cluster name
variable "cluster_name" {
  description = "The name to use for all the cluster resources"
}

# Input variable: DB remote state bucket name
variable "db_remote_state_bucket" {
  description = "The name of the S3 bucket for the database's remote state"
}

# Input variable: DB remote state bucket key
variable "db_remote_state_key" {
  description = "The path for database's remote state in S3"
}

# Input variable: Instance type
variable "instance_type" {
  description = "The type of EC2 Instances to run (e.g. t2.micro)"
}

# Input variable: Instance min size
variable "min_size" {
  description = "The minimum number of EC2 Instances in the ASG"
}

# Input variable: Instance max size
variable "max_size" {
  description = "The maximum number of EC2 Instances in the ASG"
}

Đoạn code trên định nghĩa một tập hợp các biến đầu vào (input variables) cho một ứng dụng đang chạy trên AWS. Mỗi biến đầu vào có một mô tả ngắn gọn về mục đích của nó và một giá trị mặc định (nếu có). Các biến đầu vào được sử dụng để cấu hình ứng dụng và chạy trên một tập hợp các tài nguyên AWS như EC2 instances, Auto Scaling Groups, S3 Buckets, v.v. Các biến này sẽ được sử dụng trong các file cấu hình (configuration files) để cấu hình các tài nguyên này.

Tạo file S3 chung tại thư mục global sử dụng chung cho cả hai môi trường.

– /live/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
  }
}

Đoạn code trên có ý nghĩa để tạo một tài nguyên S3 bucket trong môi trường AWS với các thuộc tính như sau:

  • Bucket name được định nghĩa trong biến bucket_name.
  • Versioning được bật cho bucket bằng thuộc tính versioning, điều này sẽ cho phép phiên bản các đối tượng được lưu trữ trong bucket.
  • Lifecycle policy được định nghĩa bằng thuộc tính lifecycle. Trong ví dụ này, prevent_destroy được đặt là true, nghĩa là khi áp dụng một tài nguyên terraform destroy để xóa bucket s3 này, sẽ bị từ chối và không thực hiện xóa bucket.

Ngoài ra, đoạn code cũng sử dụng biến var.bucket_name để giá trị của bucket name có thể được thiết lập từ bên ngoài, để linh hoạt hơn trong việc triển khai.

– /live/global/s3/outputs.tf

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

Đoạn code trên định nghĩa một output variable có tên “s3_bucket_arn” cho module Terraform, nó trả về Amazon Resource Name (ARN) của S3 bucket đã được tạo ra trước đó thông qua resource “aws_s3_bucket”.

Output variable này sẽ trả về giá trị của thuộc tính “arn” của resource “aws_s3_bucket”. Khi chạy lệnh “terraform apply”, giá trị này sẽ hiển thị ra để bạn có thể sử dụng nó trong các bước triển khai tiếp theo hoặc để lưu lại cho mục đích sử dụng sau này.

– /live/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 trên là cấu hình cho Terraform backend sử dụng một bucket S3 để lưu trữ trạng thái (state) của Terraform.

  • backend "s3": đây là backend được chọn để lưu trữ trạng thái của Terraform, trong trường hợp này là S3.
  • bucket = "terraform-state-my-bucket": đây là tên của bucket S3 được sử dụng để lưu trữ trạng thái của Terraform.
  • key = "multi-repo-example/live/prod/data-stores/mysql/terraform.tfstate": đây là đường dẫn đến file state của Terraform trong bucket S3. Nó cần được chỉ định để Terraform biết nơi lưu trữ trạng thái.
  • region = "eu-west-1": đây là khu vực của bucket S3 được sử dụng để lưu trữ trạng thái của Terraform.

Với cấu hình này, Terraform sẽ lưu trữ trạng thái của infra được quản lý bởi Terraform trong bucket S3 đã được chỉ định. Khi chạy các lệnh Terraform, nó sẽ truy cập vào bucket này để lấy hoặc lưu trạng thái. Việc sử dụng S3 làm backend giúp đảm bảo tính toàn vẹn của trạng thái và cho phép nhiều người dùng truy cập và chia sẻ trạng thái đó.

Tạo file mysql.

– /live/prod/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    = "multi-repo-example/live/prod/data-stores/mysql/terraform.tfstate"
    region = "eu-west-1"
  }
}

Đoạn code trên là cấu hình cho Terraform backend sử dụng một bucket S3 để lưu trữ trạng thái (state) của Terraform.

  • backend "s3": đây là backend được chọn để lưu trữ trạng thái của Terraform, trong trường hợp này là S3.
  • bucket = "terraform-state-my-bucket": đây là tên của bucket S3 được sử dụng để lưu trữ trạng thái của Terraform.
  • key = "multi-repo-example/live/prod/data-stores/mysql/terraform.tfstate": đây là đường dẫn đến file state của Terraform trong bucket S3. Nó cần được chỉ định để Terraform biết nơi lưu trữ trạng thái.
  • region = "eu-west-1": đây là khu vực của bucket S3 được sử dụng để lưu trữ trạng thái của Terraform.

Với cấu hình này, Terraform sẽ lưu trữ trạng thái của infra được quản lý bởi Terraform trong bucket S3 đã được chỉ định. Khi chạy các lệnh Terraform, nó sẽ truy cập vào bucket này để lấy hoặc lưu trạng thái. Việc sử dụng S3 làm backend giúp đảm bảo tính toàn vẹn của trạng thái và cho phép nhiều người dùng truy cập và chia sẻ trạng thái đó.

– /live/prod/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_prod"
  username            = "admin"
  password            = "${var.db_password}"
  skip_final_snapshot = true
}

Đoạn code trên được sử dụng để cấu hình và triển khai một instance của Amazon RDS (Relational Database Service) MySQL trên AWS sử dụng Terraform.

  • provider "aws" { region = "eu-west-1" }: đây là khai báo cấu hình cho provider của Terraform. Ở đây chúng ta đang sử dụng provider AWS và chọn khu vực là “eu-west-1”.
  • resource "aws_db_instance" "example" { ... }: đây là khai báo một resource trong Terraform. Ở đây chúng ta đang khai báo tạo một instance RDS MySQL với tên là “example_database_prod” trên AWS.
  • engine = "mysql": đây là loại động cơ cơ sở dữ liệu được sử dụng để tạo instance. Ở đây chúng ta đang sử dụng MySQL.
  • allocated_storage = 10: đây là dung lượng được cấp phát cho instance RDS, ở đây là 10GB.
  • instance_class = "db.t2.micro": đây là loại instance được sử dụng để triển khai, ở đây là “db.t2.micro”. Loại này được sử dụng cho các ứng dụng nhỏ và thích ứng với khối lượng công việc nhẹ.
  • name = "example_database_prod": đây là tên của instance RDS.
  • username = "admin"password = "${var.db_password}": đây là tên đăng nhập và mật khẩu để truy cập vào instance RDS.
  • skip_final_snapshot = true: đây là tùy chọn để không tạo snapshot cuối cùng khi instance bị xóa.

– /live/prod/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}"
}

Đoạn code trên là khai báo đầu ra (output) trong Terraform, được sử dụng để trả về các giá trị từ các resource đã tạo.

  • output "address" { value = "${aws_db_instance.example.address}" }: ở đây chúng ta đang xuất ra địa chỉ của instance RDS MySQL vừa được tạo ra trong đoạn code trước đó. Ví dụ: address = "example_database_prod.some-random-string.eu-west-1.rds.amazonaws.com"
  • output "port" { value = "${aws_db_instance.example.port}" }: ở đây chúng ta xuất ra cổng của instance RDS MySQL được tạo ra. Ví dụ: port = 3306

Điều này cho phép các giá trị này được sử dụng trong các module và mô-đun khác của Terraform để triển khai hạ tầng hoặc để hiển thị cho người dùng cuối.

– /live/prod/data-stores/mysql/vars.tf

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

Đoạn code trên là khai báo một biến đầu vào (input variable) trong Terraform. Biến này được sử dụng để truyền giá trị vào các module hoặc resource khi chúng được triển khai.

  • variable "db_password" { description = "The password for the database" }: ở đây chúng ta đang khai báo biến đầu vào “db_password” với mô tả là “The password for the database”. Khi triển khai, người dùng sẽ được yêu cầu cung cấp giá trị cho biến này. Điều này cho phép các giá trị được truyền vào từ bên ngoài cho các biến hoặc các tham số trong đoạn code Terraform, giúp tăng tính linh hoạt và khả năng tái sử dụng của code trong Terraform.

Tạo file webserver-cluster.

– /live/prod/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    = "multi-repo-example/live/prod/services/webserver-cluster/terraform.tfstate"
    region = "eu-west-1"
  }
}

Đoạn code trên định nghĩa Terraform backend sử dụng S3 bucket để lưu trữ trạng thái của Terraform (Terraform state).

  • terraform: khai báo một block Terraform.
  • backend "s3": khai báo S3 là backend để lưu trữ trạng thái của Terraform.
  • bucket = "terraform-state-my-bucket": S3 bucket được sử dụng để lưu trữ trạng thái Terraform.
  • key = "multi-repo-example/live/prod/services/webserver-cluster/terraform.tfstate": tên key trong S3 bucket được sử dụng để lưu trữ trạng thái Terraform.
  • region = "eu-west-1": khu vực AWS sẽ được sử dụng để lưu trữ S3 bucket.

Khi chạy Terraform, trạng thái của hạ tầng được quản lý bởi Terraform sẽ được lưu trữ trong S3 bucket đã được chỉ định. Điều này cho phép các thành viên của nhóm hoặc các máy chủ khác nhau có thể truy cập và sử dụng trạng thái này để quản lý cùng một hạ tầng.

– /live/prod/services/webserver-cluster/main.tf

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

# Use Module
module "webserver_cluster" {
  source = "git::git@github.com:alfonsof/terraform-aws-repo-examples.git//modules/services/webserver-cluster?ref=v0.0.1"
  
  cluster_name           = "werservers-prod"
  db_remote_state_bucket = "${var.db_remote_state_bucket}"
  db_remote_state_key    = "${var.db_remote_state_key}"

  instance_type = "t2.micro"
  min_size      = 2
  max_size      = 10
}

# Create an Autoscaling Schedule
resource "aws_autoscaling_schedule" "scale_out_during_business_hours" {
  scheduled_action_name = "scale-out-during-business-hours"
  min_size              = 2
  max_size              = 10
  desired_capacity      = 10
  recurrence            = "0 9 * * *"
  
  autoscaling_group_name = "${module.webserver_cluster.asg_name}"
}

# Create an Autoscaling Schedule
resource "aws_autoscaling_schedule" "scale_in_at_night" {
  scheduled_action_name = "scale-in-at-night"
  min_size              = 2
  max_size              = 10
  desired_capacity      = 2
  recurrence            = "0 17 * * *"

  autoscaling_group_name = "${module.webserver_cluster.asg_name}"
}

Đoạn code trên là một tập hợp các cấu hình Terraform được sử dụng để tạo ra một nhóm máy chủ webserver trong môi trường sản phẩm (prod) trên nền tảng AWS. Cụ thể:

  • Đoạn code đầu tiên cấu hình AWS provider với region là “eu-west-1”.
  • Sau đó, module “webserver_cluster” được sử dụng để tạo một nhóm máy chủ webserver với các thông số như instance_type, min_size, max_size được định nghĩa trong module và được truyền vào thông qua các biến đầu vào. Module này được lấy từ repository Terraform trên GitHub với ref là “v0.0.1”.
  • Tiếp theo, hai tài nguyên được tạo ra là aws_autoscaling_schedule để lập lịch tự động cho việc scale-up và scale-down của nhóm máy chủ webserver. Cụ thể, tài nguyên đầu tiên có tên là “scale_out_during_business_hours” được đặt để scale-up từ 2 đến 10 instance khi bắt đầu giờ làm việc (9 giờ sáng) và tài nguyên thứ hai có tên là “scale_in_at_night” được đặt để scale-down từ 10 đến 2 instance khi đến giờ nghỉ tối (17 giờ chiều).

– /live/prod/services/webserver-cluster/outputs.tf

# Output variable: DNS Name of ELB
output "elb_dns_name" {
  value = "${module.webserver_cluster.elb_dns_name}"
}

Đoạn code này là khai báo một biến đầu ra (output variable) trong Terraform để lưu trữ DNS Name của Elastic Load Balancer (ELB). Cụ thể, giá trị của biến đầu ra này được lấy từ biến elb_dns_name trong module webserver_cluster mà chúng ta đã sử dụng ở trên.

Với đoạn code này, chúng ta có thể sử dụng giá trị của biến đầu ra để hiển thị tên miền của ELB sau khi nó được tạo ra bởi module webserver_cluster. Ví dụ: nếu giá trị của biến đầu ra là “my-elb.example.com”, thì chúng ta có thể sử dụng giá trị này để truy cập ELB bằng tên miền “my-elb.example.com”.

– /live/prod/services/webserver-cluster/vars.tf

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

# Input variable: DB remote state bucket key
variable "db_remote_state_key" {
  description = "The path for database's remote state in S3"
  default     = "multi-repo-example/live/prod/data-stores/mysql/terraform.tfstate"
}

Đoạn code này định nghĩa 2 biến đầu vào trong Terraform:

  • Biến “db_remote_state_bucket”: là tên của bucket S3 được sử dụng để lưu trữ state của cơ sở dữ liệu trong Terraform. Biến này có thể được override bằng giá trị khác khi chạy Terraform.
  • Biến “db_remote_state_key”: là đường dẫn của file state của cơ sở dữ liệu trong bucket S3 được sử dụng để lưu trữ state của cơ sở dữ liệu trong Terraform. Biến này cũng có thể được override bằng giá trị khác khi chạy Terraform.

Nếu không có giá trị được cung cấp cho 2 biến này, Terraform sẽ sử dụng giá trị mặc định đã được định nghĩa trong đoạn code.

– /live/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    = "multi-repo-example/live/stage/data-stores/mysql/terraform.tfstate"
    region = "eu-west-1"
  }
}

Đoạn code này sử dụng Terraform backend với đối tượng backend được cấu hình sử dụng S3 bucket để lưu trữ trạng thái Terraform.

Cụ thể, đoạn code này chỉ định S3 bucket và key cho trạng thái của Terraform. Ví dụ này cấu hình cho trạng thái ở “multi-repo-example/live/stage/data-stores/mysql/terraform.tfstate” trong bucket “terraform-state-my-bucket” ở khu vực “eu-west-1”.

Việc lưu trữ trạng thái Terraform trên S3 bucket giúp cho việc quản lý và chia sẻ giữa các nhà phát triển trên dự án trở nên dễ dàng hơn.

– /live/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_stage"
  username            = "admin"
  password            = "${var.db_password}"
  skip_final_snapshot = true
}

Đoạn code này được sử dụng để cấu hình AWS provider và tạo một instance database trên AWS bằng Terraform.

Cụ thể, đoạn code bắt đầu bằng việc cấu hình provider cho AWS với region được chọn là “eu-west-1”. Sau đó, đoạn code định nghĩa một resource là “aws_db_instance” với tên là “example”, đại diện cho một instance database MySQL trên AWS. Các thuộc tính được định nghĩa bao gồm:

  • engine: định nghĩa engine được sử dụng cho instance database, ở đây là MySQL
  • allocated_storage: dung lượng được cấp phát cho instance database, ở đây là 10 GB
  • instance_class: loại instance được sử dụng, ở đây là db.t2.micro
  • name: tên của instance database, ở đây là “example_database_stage”
  • username: tên đăng nhập cho instance database, ở đây là “admin”
  • password: mật khẩu đăng nhập cho instance database, sử dụng biến đầu vào “db_password”
  • skip_final_snapshot: không tạo snapshot khi xóa instance database.

Với cấu hình này, Terraform sẽ tạo một instance database MySQL trên AWS với các thuộc tính đã được cấu hình và sử dụng mật khẩu được định nghĩa trong biến đầu vào “db_password”.

– /live/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}"
}

Đoạn code trên định nghĩa 2 biến đầu ra (output) trong Terraform, để truy cập đến địa chỉ và cổng của một instance của AWS RDS (Relational Database Service) đang chạy.

Cụ thể, biến đầu ra “address” sử dụng giá trị của thuộc tính “address” trong đối tượng AWS RDS instance đã được tạo và lưu trong biến “aws_db_instance.example”. Tương tự, biến đầu ra “port” sử dụng giá trị của thuộc tính “port” trong đối tượng AWS RDS instance.

Những biến đầu ra này có thể được sử dụng bởi những module khác trong quá trình triển khai (deployment) hệ thống.

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

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

Đoạn code trên định nghĩa một biến đầu vào (input variable) trong Terraform với tên là “db_password” được sử dụng để chứa mật khẩu cho cơ sở dữ liệu. Biến này được sử dụng để cấu hình các tài nguyên liên quan đến cơ sở dữ liệu như tài nguyên “aws_db_instance” (được khai báo ở phía dưới), cho phép người dùng cung cấp giá trị cho biến này khi triển khai (apply) hoặc chỉnh sửa (plan) infra.

– /live/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    = "multi-repo-example/live/stage/services/webserver-cluster/terraform.tfstate"
    region = "eu-west-1"
  }
}

Đoạn code này định nghĩa backend cho Terraform sử dụng S3 bucket để lưu trữ state file của infrastructure. Terraform backend là nơi lưu trữ các thông tin về trạng thái của tài nguyên đang được quản lý bởi Terraform.

Cụ thể, backend được sử dụng là S3 bucket. bucket là tên của bucket S3 được sử dụng để lưu trữ state file, key là đường dẫn của state file, region là khu vực của S3 bucket.

Với cấu hình này, Terraform sẽ sử dụng backend là S3 bucket có tên là “terraform-state-my-bucket” ở khu vực “eu-west-1”, và state file sẽ được lưu trữ ở đường dẫn “multi-repo-example/live/stage/services/webserver-cluster/terraform.tfstate”.

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

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

# Use Module
module "webserver_cluster" {
  source = "git::git@github.com:alfonsof/terraform-aws-repo-examples.git//modules/services/webserver-cluster?ref=v0.0.2"
  
  cluster_name           = "werservers-stage"
  db_remote_state_bucket = "${var.db_remote_state_bucket}"
  db_remote_state_key    = "${var.db_remote_state_key}"
  
  instance_type = "t2.micro"
  min_size      = 2
  max_size      = 2
}

# Create a Security Group Rule
resource "aws_security_group_rule" "allow_testing_inbound" {
  type              = "ingress"
  security_group_id = "${module.webserver_cluster.elb_security_group_id}"

  from_port   = 12345
  to_port     = 12345
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
}

Đoạn code này sử dụng Terraform để tạo và cấu hình một cluster web server trên Amazon Web Services (AWS). Chi tiết ý nghĩa từng phần như sau:

  • Phần provider "aws" cấu hình AWS provider với khu vực eu-west-1.
  • Phần module "webserver_cluster" sử dụng một module từ Github để tạo một cluster web server trên AWS. Module được lấy từ địa chỉ git@github.com:alfonsof/terraform-aws-repo-examples.git và chỉ định phiên bản v0.0.2. Các biến đầu vào được cung cấp cho module gồm:
    • cluster_name: tên của cluster.
    • db_remote_state_bucketdb_remote_state_key: đường dẫn đến state file của module terraform-aws-repo-examples để lưu trữ trạng thái của database.
    • instance_type: loại instance EC2.
    • min_sizemax_size: số lượng instance tối thiểu và tối đa trong cluster.
  • Phần resource "aws_security_group_rule" "allow_testing_inbound" tạo một rule cho phép traffic vào từ port 12345 được truy cập vào security group của ELB được tạo ra bởi module.

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

# Output variable: DNS Name of ELB
output "elb_dns_name" {
  value = "${module.webserver_cluster.elb_dns_name}"
}

Đoạn code trên định nghĩa một biến đầu ra (output variable) trong Terraform. Biến đầu ra này trả về tên miền DNS của Elastic Load Balancer (ELB) được tạo ra bởi module webserver_cluster.

Cụ thể, elb_dns_name là tên biến đầu ra được định nghĩa, giá trị của nó là tên miền DNS của ELB được truyền từ module webserver_cluster.

Sau khi chạy code trong Terraform, giá trị của biến đầu ra này sẽ được hiển thị trong kết quả đầu ra (output) của lệnh terraform apply. Giá trị này có thể được sử dụng bởi các module hoặc code Terraform khác.

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

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

# Input variable: DB remote state bucket key
variable "db_remote_state_key" {
  description = "The path for database's remote state in S3"
  default     = "multi-repo-example/live/stage/data-stores/mysql/terraform.tfstate"
}

Đoạn code trên định nghĩa hai biến đầu vào (input variables) là db_remote_state_bucketdb_remote_state_key dùng để chỉ định tên và đường dẫn của S3 bucket để lưu trữ trạng thái của cơ sở dữ liệu (database) trong một môi trường cụ thể (ở đây là môi trường stage).

  • db_remote_state_bucket là tên của S3 bucket được sử dụng để lưu trữ trạng thái (state) của cơ sở dữ liệu.
  • db_remote_state_key là đường dẫn trong S3 bucket chứa trạng thái của cơ sở dữ liệu, được định nghĩa bằng đường dẫn tương đối đến file terraform.tfstate của module.

Nếu giá trị cho các biến này không được chỉ định khi chạy Terraform, giá trị mặc định sẽ được sử dụng là terraform-state-my-bucket cho biến db_remote_state_bucket, và multi-repo-example/live/stage/data-stores/mysql/terraform.tfstate cho biến db_remote_state_key.

Chi phí triển khai.

Chi phí triển khai và sử dụng một infra AWS phụ thuộc vào nhiều yếu tố, bao gồm nhưng không giới hạn: số lượng tài nguyên được triển khai, thời gian sử dụng tài nguyên và vùng địa lý. Nếu bạn muốn biết chi phí cụ thể cho việc triển khai và sử dụng project này, bạn có thể tính toán chi phí sử dụng AWS Calculator dựa trên thông số của bạn. Nếu bạn muốn giảm chi phí, bạn có thể sử dụng một số chức năng miễn phí của AWS hoặc tìm hiểu cách tối ưu hóa infra để sử dụng hiệu quả các tài nguyên của bạn.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4,956FansLike
256FollowersFollow
223SubscribersSubscribe
spot_img

Related Stories