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.
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
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.
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.
Bấm vào terraform-series-s3-backend ta sẽ thấy state file của ta.
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ư:
- Senior Backend Engineer (Java). Link JD: https://tuyendung.hoang-phuc.com/job/senior-backend-engineer-1022
- Senior Front-end Engineer (VueJS). https://tuyendung.hoang-phuc.com/job/senior-frontend-engineer-1021
- Junior Backend Engineer (Java). https://tuyendung.hoang-phuc.com/job/junior-backend-engineer-1067
- Junior Front-end Engineer (VueJS). https://tuyendung.hoang-phuc.com/careers/job/1068
- App (Flutter). https://tuyendung.hoang-phuc.com/job/mobile-app-engineer-flutter-1239
- Senior Data Engineer. https://tuyendung.hoang-phuc.com/job/seniorjunior-data-engineer-1221
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 [email protected]
. Cảm ơn các bạn đã đọc.
Nguồn: viblo.asia