- vừa được xem lúc

Terraform Series - Bài 7 - Terraform Backend: S3 Standard Backend

0 0 20

Người đăng: Quân Huỳnh

Theo Viblo Asia

Giới thiệu

Chào các bạn tới với series về Terraform, ở bài trước chúng ta đã nói về lý thuyết của Terraform Backend. Ở bài này chúng ta sẽ thực hành sử dụng Terraform Standard Backend, cụ thể là S3 Standard Backend. Ta sẽ tìm hiểu Terraform S3 Backend sẽ bao gồm các thành phần gì, tạo nó ra sao và ứng dụng nó vào dự án của ta thế nào.

Mô hình đơn giản của S3 Standard Backend như sau.

image.png

Developing an S3 backend

Architecture

Trước khi sử dụng S3 backend thì ta cần phải tạo nó trước, cấu trúc của một S3 backend gồm những thành phần:

  • IAM
  • DynamoDB
  • S3 bucket - KMS

image.png

Từng thành phần trên sẽ được sử dụng như sau:

  • IAM được sử dụng để terraform assume role, để terraform có quyền ghi vào dynamodb table và fetch/store state vào bên trong S3.
  • Dynamodb được terraform dùng để ghi lock key của một process vào bên trong nó, vì dynamodb có tốc độ đọc và ghi nhanh tới mức milisecond nên nó rất thích hợp để lock state của một process.
  • S3 bucket dùng để lưu trữ state khi terraform chạy xong, KMS được S3 sử dụng để mã hóa dữ liệu state khi nó được lưu vào bên trong S3.

Developing

Giờ thì ta sẽ tiến hành tạo S3 backend, phía dưới các resource mà ta sẽ sử dụng để tạo S3 backend.

Tạo một một folder và file main.tf + variables.tf + versions.tf với nội dung.

provider "aws" { region = var.region
}
variable "region" { type = string default = "us-west-2"
} variable "project" { description = "The project name to use for unique resource naming" default = "terraform-series" type = string
} variable "principal_arns" { description = "A list of principal arns allowed to assume the IAM role" default = null type = list(string)
}
terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 4.0" } }
}

Sau đó chạy câu lệnh terraform init. Oke, vậy là bước chuẩn bị đã xong, tiếp theo ta tạo file dynamodb.tf.

resource "aws_dynamodb_table" "dynamodb_table" { name = "${var.namespace}-s3-backend" hash_key = "LockID" billing_mode = "PAY_PER_REQUEST" attribute { name = "LockID" type = "S" } tags = local.tags
}

Đây là DynamoDB Table resource để chứa lock state của ta, ta định nghĩa table này sẽ có một trường là LockID với type là String đây là cấu hình bắt buộc mà terraform quy định cho table mà dùng để lưu lock state.

Tiếp theo ta tạo file iam.tf chứa các IAM resource.

data "aws_caller_identity" "current" {} locals { principal_arns = var.principal_arns != null ? var.principal_arns : [data.aws_caller_identity.current.arn]
} data "aws_iam_policy_document" "policy_doc" { statement { actions = ["s3:ListBucket"] resources = [aws_s3_bucket.s3_bucket.arn] } statement { actions = ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"] resources = ["${aws_s3_bucket.s3_bucket.arn}/*"] } statement { actions = ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:DeleteItem"] resources = [aws_dynamodb_table.dynamodb_table.arn] }
}

Data source aws_caller_identity dùng để lấy thông tin về aws account mà ta đang chạy. Biến principal_arns sẽ chứa tất cả đối tượng mà ta cho phép nó assume role với aws account của ta.

Từ biểu thức so sánh var.principal_arns != null ? var.principal_arns : [data.aws_caller_identity.current.arn] ở trên => nếu ta không truyền biến này vào khi chạy terraform thì nó sẽ chỉ cho phép account mà ta dùng để chạy terraform có quyền assume role.

Resoruce aws_iam_policy_document dùng để định nghĩa các policy của ta, policy document ở trên sẽ định nghĩa quyền cần thiết để ta có thể thực hiện hành động lên trên DynamoDB, S3, KSM. Tiếp theo ta sẽ gắn policy document này vào policy và role.

...
resource "aws_iam_policy" "policy" { name = "${title(var.namespace)}S3BackendPolicy" path = "/" policy = data.aws_iam_policy_document.policy_doc.json
} resource "aws_iam_role" "iam_role" { name = "${title(var.namespace)}S3BackendRole" assume_role_policy = <<-EOF { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "AWS": ${jsonencode(local.principal_arns)} }, "Effect": "Allow" } ] } EOF tags = local.tags
} resource "aws_iam_role_policy_attachment" "policy_attach" { role = aws_iam_role.iam_role.name policy_arn = aws_iam_policy.policy.arn
}

Sau đó ta tạo file s3.tf.

resource "aws_s3_bucket" "s3_bucket" { bucket = "${var.namespace}-s3-backend" force_destroy = false tags = local.tags
} resource "aws_s3_bucket_acl" "s3_bucket" { bucket = aws_s3_bucket.s3_bucket.id acl = "private"
} resource "aws_s3_bucket_versioning" "s3_bucket" { bucket = aws_s3_bucket.s3_bucket.id versioning_configuration { status = "Enabled" }
} resource "aws_kms_key" "kms_key" { tags = local.tags
} resource "aws_s3_bucket_server_side_encryption_configuration" "s3_bucket" { bucket = aws_s3_bucket.s3_bucket.id rule { apply_server_side_encryption_by_default { sse_algorithm = "aws:kms" kms_master_key_id = aws_kms_key.kms_key.arn } }
}

Resource aws_s3_bucket ta dùng để định nghĩa s3 bucket, aws_s3_bucket_acl ta dùng để định nghĩa access control list của s3, ta nên để là private.

Tiếp theo và quan trong là để S3 có thể dùng để lưu trữ state, ta phải bật versioning cho nó, ta làm bằng resource aws_s3_bucket_versioning. Cuối cùng là ta bật SSE (Server Side Encryption) cho bucket của ta bằng resource aws_s3_bucket_server_side_encryption_configuration.

Oke, vậy là ta đã chuẩn bị đủ các resource cho S3 backend, tiếp theo ta cập nhật lại file main.tf để nó output ra giá trị của S3 backend mà ta sẽ cần để sử dụng cho các terraform project khác.

...
locals { tags = { project = var.project }
} data "aws_region" "current" {} resource "aws_resourcegroups_group" "resourcegroups_group" { name = "${var.namespace}-s3-backend" resource_query { query = <<-JSON { "ResourceTypeFilters": [ "AWS::AllSupported" ], "TagFilters": [ { "Key": "project", "Values": ["${var.project}"] } ] } JSON }
} output "config" { value = { bucket = aws_s3_bucket.s3_bucket.bucket region = data.aws_region.current.name role_arn = aws_iam_role.iam_role.arn dynamodb_table = aws_dynamodb_table.dynamodb_table.name }
}

Bạn sẽ để ý thấy có resource tên là aws_resourcegroups_group, thằng này chủ yếu được dùng để group resource lại cho ta dẽ quản lý thôi, lát mình sẽ show cho các bạn xem.

Giờ bạn chạy câu lệnh terraform plan để tạo S3 backend, sau khi chạy xong ta sẽ thấy output như dưới, đây là các giá trị ta sẽ cần.

config = { "bucket" = "terraform-series-s3-backend" "dynamodb_table" = "terraform-series-s3-backend" "region" = "us-west-2" "role_arn" = "arn:aws:iam::<ACCOUNT_ID>:role/HpiS3BackendRole"
}

Để kiểm tra các resource của S3 backend, ta truy cập AWS Console https://console.aws.amazon.com/resource-groups/home, bạn sẽ thấy resource group của ta.

image.png

Bấm vào nó bạn sẽ thấy chi tiết của từng resource của S3 backend. Oke, tiếp theo ta sẽ tiến hành sử dụng S3 backend này vào trong project 😁.

Using S3 backend

Để sử dụng S3 backend cho một project, ta cấu cần cấu hình như sau.

terraform { backend "s3" { bucket = <bucket-name> key = <path> region = <region> encrypt = true role_arn = <arn-role> dynamodb_table = <dynamodb-table-name> }
}

Ta sẽ khai báo một block tên là terraform với backend là s3 với các giá trị sau:

  • bucket: s3 bucket name.
  • key: path ta lưu state trong bucket.
  • role_arn: IAM role mà có quyền cần thiết.
  • dynamodb_table: table dùng để save lock state.

Giờ ta sẽ làm ví dụ tạo một EC2 mà sử dụng S3 backend. Tạo một folder và file main.tf.

terraform { backend "s3" { bucket = "terraform-series-s3-backend" key = "test-project" region = "us-west-2" encrypt = true role_arn = "arn:aws:iam::<ACCOUNT_ID>:role/HpiS3BackendRole" dynamodb_table = "terraform-series-s3-backend" }
} provider "aws" { region = "us-west-2"
} data "aws_ami" "ami" { most_recent = true filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] } owners = ["099720109477"]
} resource "aws_instance" "server" { ami = data.aws_ami.ami.id instance_type = "t3.micro" lifecycle { create_before_destroy = true } tags = { Name = "Server" }
} output "public_ip" { value = aws_instance.server.public_ip
}

Chạy terraform init sau đó ta chạy terraform plan, sau khi nó chạy xong bạn sẽ thấy terraform.tfstate sẽ không còn nằm ở local nữa. Mà ta sẽ cần lên trên S3 bucket để xem state file của ta.

Truy cập AWS S3 Console https://s3.console.aws.amazon.com/s3/buckets.

image.png

Bấm vào terraform-series-s3-backend ta sẽ thấy state file của ta.

image.png

Oke, s3 backend của ta đã được implement thành công 😁.

Kết luận

Vậy là ta đã tìm hiểu xong về S3 backend, cách tạo ra nó và cách sử dụng nó. Khi ta làm việc với team thì ta nên sử dụng S3 backend cho project của ta, vừa centralized được state file, vừa giải quyết được vấn để conflict khi nhiều người chạy terraform project cùng một lúc. Nếu có thắc mắc hoặc cần giải thích rõ thêm chỗ nào thì các bạn có thể hỏi dưới phần comment. Ở bài tiếp theo ta nói về cách config và triển khai Terraform dùng S3 Standard Backend.

Mục tìm kiếm đồng đội

Hiện tại thì bên công ty mình, là Hoàng Phúc International, với hơn 30 năm kinh nghiệm trong lĩnh vực thời trang. Và là trang thương mại điện tử về thời trang lớn nhất Việt Nam. Team công nghệ của HPI đang tìm kiếm đồng đội cho các vị trí như:

Với mục tiêu trong vòng 5 năm tới về mảng công nghệ là:

  • Sẽ có trang web nằm trong top 10 trang web nhanh nhất VN với 20 triệu lượt truy cập mỗi tháng.
  • 5 triệu loyal customers và có hơn 10 triệu transactions mỗi năm.

Team đang xây dựng một hệ thống rất lớn với rất nhiều vấn để cần giải quyết, và sẽ có rất nhiều bài toàn thú vị cho các bạn. Nếu các bạn có hứng thú trong việc xây dựng một hệ thống lớn, linh hoạt, dễ dàng mở rộng, và performance cao với kiến trúc microservices thì hãy tham gia với tụi mình.

Nếu các bạn quan tâm hãy gửi CV ở trong trang tuyển dụng của Hoàng Phúc International hoặc qua email của mình nha _@.com. Cảm ơn các bạn đã đọc.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Đề thi interview DevOps ở Châu Âu

Well. Chào mọi người, mình là Rice - một DevOps Engineers ở đâu đó tại Châu Âu.

0 0 65

- vừa được xem lúc

In calculus, love also means zero.

Mình nhớ hồi năm 2 đại học, thầy giáo môn calculus, trong một giây phút ngẫu hứng, đã đưa ra cái definition này. Lúc đấy mình cũng không nghĩ gì nhiều.

0 0 51

- vừa được xem lúc

Chuyện thay đổi

Thay đổi là một thứ gì đó luôn luôn đáng sợ. Cách đây vài tháng mình có duyên đi làm cho một banking solution tên là X.

0 0 30

- vừa được xem lúc

Pet vs Cattle - Thú cưng và gia súc

Khái niệm. Pets vs Cattle là một khái niệm cơ bản của DevOps. Bài viết này sẽ nói về sự phát triển của các mô hình dịch vụ từ cốt lõi Pets and Cattle. 1.

0 0 22

- vừa được xem lúc

Git workflow được Google và Facebook sử dụng có gì hay ho

Với developer thì Git hẳn là công cụ rất quen thuộc và không thể thiếu rồi. Thế nhưng có mấy ai thực sự hiểu được Git.

0 0 66

- vừa được xem lúc

Kubernetes - Học cách sử dụng Kubernetes Namespace cơ bản

Namespace trong Kubernetes là gì. Tại sao nên sử dụng namespace.

0 0 96