Giới thiệu
Ở bài trước chúng ta đã tìm hiểu về cách khởi tạo thư mục dự án và cách viết tệp tin cấu hình Terraform. Ở bài này chúng ta sẽ tìm hiểu về vòng đời của một resource trong Terraform, nó sẽ đi qua các bước gì kể từ khi nó được tạo ra và bị xóa đi.
Ta sẽ dùng Terraform để tạo một S3 (AWS Simple Cloud Storage) trên AWS để tìm hiểu về vòng đời của một resource.
Những hàm Terraform sẽ gọi trong một vòng đời
Tất cả các resource type
của Terraform đều Implement một CRUD Interface, trong CRUD Interface này sẽ có các hàm là Create()
, Read()
, Update()
, Delete()
và những hàm này sẽ được thực thi nếu gặp đúng điều kiện phù hợp. Còn data type
của Terraform thì Implement một Read Interface chỉ có một hàm là Read()
, hình minh họa.
Create()
sẽ được gọi trong quá trình tạo resource, Read()
được gọi trong quá trình plan
, Update()
được gọi trong quá trình cập nhật resource, và Delete()
được gọi trong quá trình xóa resource.
Ví dụ về S3
Bây giờ ta sẽ viết tệp tin Terraform để tạo S3 và nói qua từng hàm ở trên. Tạo một Wordspace tên là s3, sau đó tạo một tệp tin tên là main.tf
với code như sau:
provider "aws" {
region = "us-west-2"
}
resource "aws_s3_bucket" "terraform-bucket" {
bucket = "terraform-series-bucket"
tags = {
Name = "Terraform Series"
}
}
Ở tệp tin trên trên ta dùng resource là aws_s3_bucket
, đây là resource dùng để tạo S3 Bucket trên AWS Cloud, trong đó trường bucket
sẽ là tên Bucket của ta. Sau khi viết xong thì ta chạy câu lệnh init
để Terraform tải Provider xuống Workspace hiện tại.
terraform init
Plan
Như đã nói ở bài trước, trước khi ta tạo resource, ta nên chạy terraform plan
trước để xem những resource nào sẽ được tạo ra.
Và bên cạnh việc hiển thị cho ta xem những resource nào sẽ được tạo ra, thì nếu ta đã có resource rồi mà ta thay đổi giá trị gì trong tệp tin Terraform, thì plan
sẽ hiển thị cho ta là resource nào sẽ được cập nhật lại dựa theo State của resource trước đó đã được tạo ra.
Và nếu ta không thay đổi gì trong tệp tin Terraform, thì khi ta chạy plan
nó sẽ hiển thị là không có resource nào được thêm vào hoặc được cập nhật.
Quá trình plan
sẽ in ra cho ta những kết quả rất hữu ích, chỉ cần đọc những gì quá trình plan
in ra là ta sẽ biết resource trên hạ tầng của ta sẽ như thế nào. Khi ta chạy câu lệnh plan
, thì Terraform sẽ thực hiện 3 bước chính như sau (nếu các bạn có ý định đi phỏng vấn thì đọc kĩ phần plan
này nhé 🤣):
- Đọc tệp tin cấu hình và tệp tin State - Terraform sẽ đọc tệp tin cấu hình của bạn và tệp tin State (nếu có tồn tại) trước để lấy thông tin về resource
- Sau đó nó sẽ xác định những hành động nào sẽ được thực hiện - Terraform sẽ thực hiện tính toán để xác định hành động nào sẽ được thực thi, có thể là
Create()
,Read()
,Update()
,Delete()
, hoặc không làm gì cả(No-op)
- Output
Biểu đồ minh họa của quá trình plan
.
Tạo S3
Giờ ta sẽ chạy câu lệnh apply
để tạo S3 trên AWS, khi ta chạy câu lệnh apply
nó sẽ có thêm bước xác nhận và bắt ta nhập vào yes
, nếu bạn muốn bỏ qua bước xác nhận thì khi chạy ta thêm vào thuộc tính -auto-approve
.
terraform apply -auto-approve
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
+ create
Terraform will perform the following actions:
# aws_s3_bucket.terraform-bucket will be created
+ resource "aws_s3_bucket" "terraform-bucket" {
...
}
Plan: 1 to add, 0 to change, 0 to destroy.
aws_s3_bucket.terraform-bucket: Creating...
aws_s3_bucket.terraform-bucket: Still creating... [10s elapsed]
aws_s3_bucket.terraform-bucket: Creation complete after 15s [id=terraform-series-bucket]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Khi ta chạy xong câu lệnh apply
Terraform sẽ tạo ra một tệp tin tên là terraform.tfstate
, bạn bấm vào thì sẽ thấy thông tin của S3. Mở AWS Web Console lên bạn sẽ thấy S3 Bucket của ta đã được tạo ra.
Làm sao Terraform tạo được S3 Bucket này? Thì trong quá trình apply
, Terraform sẽ gọi hàm Create()
của aws_s3_bucket resource.
Trong hàm Create()
trên có chứa code để gọi API lên AWS để thực hiện tạo S3 Bucket, nên khi Terraform gọi tới hàm này thì S3 Bucket sẽ được tạo ra, minh họa như bên dưới.
No-op
Khi ta đã tạo resource xong và nếu ta không sửa gì cả, thì khi ta thực thi plan
Terraform sẽ đi qua bước No-op. Bây giờ nếu ta chạy câu lệnh plan
thì đầu tiên Terraform sẽ đọc tệp tin cấu hình của ta, tiếp theo nó phát hiện có tệp tin State thì nó đọc tệp tin State, minh họa như bên dưới.
Sau khi đọc tệp tin State xong, Terraform sẽ kiểm tra S3 Bucket có tồn tại trong tệp tin State hay không, nếu có Terraform sẽ thực thi hàm Read()
của aws_s3_bucket resource.
Read()
chứa code để gọi API lên AWS và đọc thông tin của S3 Bucket hiện tại, sau đó nó sẽ so sánh với S3 trong tệp tin State. Nếu không có gì thay đổi hàm Read()
sẽ trả về kết quả là không có gì thay đổi, và terraform sẽ không thực thi hành động nào cả.
Cập nhật S3
Trong Terraform không có câu lệnh update
, ta chỉ cần sửa tệp tin cấu hình và chạy lại câu lệnh apply
, Terrform sẽ tự xác định có thực hiện cập nhật resource hay không. Ta sửa lại tên của S3 Bucket.
provider "aws" {
region = "us-west-2"
}
resource "aws_s3_bucket" "terraform-bucket" {
bucket = "terraform-series-bucket-update"
tags = {
Name = "Terraform Series"
}
}
Sau đó ta chạy câu lệnh plan
lại.
terraform plan
aws_s3_bucket.terraform-bucket: Refreshing state... [id=terraform-series-bucket]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_s3_bucket.terraform-bucket must be replaced
-/+ resource "aws_s3_bucket" "terraform-bucket" {
+ acceleration_status = (known after apply)
~ arn = "arn:aws:s3:::terraform-series-bucket" -> (known after apply)
...
}
Plan: 1 to add, 0 to change, 1 to destroy.
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you
run "terraform apply" now.
Bạn sẽ thấy là S3 Bucket của ta sẽ được Terraform cập nhật lại bằng cách xóa và tạo lại. Nghĩa là trước tiên Terraform sẽ xóa S3 Bucket cũ, sau đó nó sẽ tạo lại S3 Bucket mới với tên khác. Tại sao lại như vậy? Thì trường bucket
ở trong aws_s3_bucket
resource là một thuộc tính Force New.
Trong Terraform, resource sẽ có hai loại thuộc tính là Force New với Normal Update:
- Force New: resource sẽ được xóa và tạo lại, xóa resource cũ trước và tạo ra lại resouce mới
- Normal Update: resource được cập nhật bình thường, không cần phải xóa resouce cũ
Một thuộc tính sẽ thuộc loại nào thì tùy thuộc vào Provider. Ở trên vì ta thay đổi thuộc tính Force New của aws_s3_bucket
nên nó sẽ được xóa và tạo lại. Vì việc xóa và tạo lại sẽ gặp rất nhiều vấn đề, nên ta cần chạy câu lệnh plan
để xác định tại sao resource của ta lại như vậy, nhớ là luôn luôn nên chạy plan trước.
Vì S3 Bucket của ta mới tạo và không có gì trong đó hết, ta cứ chạy terraform apply
để nó cập nhật bình thường.
terraform apply -auto-approve
aws_s3_bucket.terraform-bucket: Refreshing state... [id=terraform-series-bucket]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_s3_bucket.terraform-bucket must be replaced
-/+ resource "aws_s3_bucket" "terraform-bucket" {
+ acceleration_status = (known after apply)
~ arn = "arn:aws:s3:::terraform-series-bucket" -> (known after apply)
...
}
Plan: 1 to add, 0 to change, 1 to destroy.
aws_s3_bucket.terraform-bucket: Destroying... [id=terraform-series-bucket]
aws_s3_bucket.terraform-bucket: Destruction complete after 1s
aws_s3_bucket.terraform-bucket: Creating...
aws_s3_bucket.terraform-bucket: Still creating... [10s elapsed]
aws_s3_bucket.terraform-bucket: Creation complete after 15s [id=terraform-series-bucket-update]
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
Sau khi chạy xong bạn sẽ thấy S3 Bucket với tên mới đã được tạo ta.
Hình minh họa.
Xóa S3
Ta xóa resource bằng câu lệnh destory
. Giống với apply
, ta có thể bỏ qua bước xác nhận bằng cách truyền thêm thuộc tính -auto-approve
.
terraform destroy -auto-approve
aws_s3_bucket.terraform-bucket: Refreshing state... [id=terraform-series-bucket-update]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
- destroy
Terraform will perform the following actions:
# aws_s3_bucket.terraform-bucket will be destroyed
- resource "aws_s3_bucket" "terraform-bucket" {
- acl = "private" -> null
- arn = "arn:aws:s3:::terraform-series-bucket-update" -> null
...
}
Plan: 0 to add, 0 to change, 1 to destroy.
aws_s3_bucket.terraform-bucket: Destroying... [id=terraform-series-bucket-update]
aws_s3_bucket.terraform-bucket: Destruction complete after 1s
Destroy complete! Resources: 1 destroyed.
Khi ta chạy câu lệnh destroy
, thì nó sẽ đọc trong tệp tin State của ta xem có resource đó không, nếu có thì nó sẽ thực hiện hàm Delete()
function của aws_s3_bucket resource.
Hình minh họa.
Sau khi ta chạy câu lệnh destroy
xong, thì Workspace của ta sẽ như sau:
.
├── main.tf
├── terraform.tfstate
└── terraform.tfstate.backup
Ta thấy có thêm tệp tin terraform.tfstate.backup
, tệp tin này chủ yếu để ta xem lại State trước đó của các resource.
Khi ta xóa toàn bộ cấu hình trong tệp tin Terraform và chạy câu lệnhapply
thì tương ứng như ta chạy câu lệnhdestroy
.
Ta đã nói xong về vòng đời của một resource trong Terraform. Giờ ta sẽ bàn về một vấn để rất hay xảy ra, là nếu mà có ai đó thay đổi cấu hình của resource chúng ta bên ngoài Terraform thì sao? Terraform sẽ xử lý việc đó như thế nào?
Resource Drift
Resource Drift là vấn đề khi cấu hình resource của ta bị thay đổi bên ngoài Terraform, với AWS thì có thể là do ai đó dùng Web Console để thay đổi cấu hình gì đó của resource mà được ta tạo bằng Terraform, dùng lại ví dụ ở trên ta tạo lại S3.
provider "aws" {
region = "us-west-2"
}
resource "aws_s3_bucket" "terraform-bucket" {
bucket = "terraform-series-bucket-update"
tags = {
Name = "Terraform Series"
}
}
terraform apply -auto-approve
...
Plan: 1 to add, 0 to change, 0 to destroy.
aws_s3_bucket.terraform-bucket: Creating...
aws_s3_bucket.terraform-bucket: Still creating... [10s elapsed]
aws_s3_bucket.terraform-bucket: Creation complete after 15s [id=terraform-series-bucket-update]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Sau đó ta lên Web Console của AWS, ta sửa lại trường tags
của S3 Bucket.
Terraform sẽ không có tự động phát hiện và cập nhật lại tệp tin Terraform của ta, nó không có thần kì như vậy 😂. Mà khi ta chạy câu lệnh apply
, nó sẽ phát hiện thay đổi và cập nhật lại trường tags
mà ta thay đổi ngoài Terraform thành giống với tags
ta viết trong tệp tin cấu hình. Bạn chạy câu lệnh plan
trước để xem.
terraform plan
aws_s3_bucket.terraform-bucket: Refreshing state... [id=terraform-series-bucket-update]
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
# aws_s3_bucket.terraform-bucket has been changed
~ resource "aws_s3_bucket" "terraform-bucket" {
id = "terraform-series-bucket-update"
~ tags = {
~ "Name" = "Terraform Series" -> "Terraform Series Drift"
}
~ tags_all = {
~ "Name" = "Terraform Series" -> "Terraform Series Drift"
}
# (9 unchanged attributes hidden)
# (1 unchanged block hidden)
}
...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_s3_bucket.terraform-bucket will be updated in-place
~ resource "aws_s3_bucket" "terraform-bucket" {
id = "terraform-series-bucket-update"
~ tags = {
~ "Name" = "Terraform Series Drift" -> "Terraform Series"
}
~ tags_all = {
~ "Name" = "Terraform Series Drift" -> "Terraform Series"
}
# (9 unchanged attributes hidden)
# (1 unchanged block hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you
run "terraform apply" now.
Chạy lại câu lệnh apply
thì ta sẽ thấy tags
sẽ được cập nhật lại như cũ.
terraform apply -auto-approve
...
Plan: 0 to add, 1 to change, 0 to destroy.
aws_s3_bucket.terraform-bucket: Modifying... [id=terraform-series-bucket-update]
aws_s3_bucket.terraform-bucket: Still modifying... [id=terraform-series-bucket-update, 10s elapsed]
aws_s3_bucket.terraform-bucket: Modifications complete after 13s [id=terraform-series-bucket-update]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Vấn đề Resource Drift ta sẽ nói kĩ hơn ở bài khác.
Kết luận
Vậy là ta đã tìm hiểu xong về vòng đời của một resource trong Terraform. Bài tiếp theo ta sẽ tìm hiểu về Functional Programming bên trong Terraform.
Tác giả @Quân Huỳnh
Nếu bài viết có gì sai hoặc cần cập nhật thì liên hệ Admin.
Tham gia nhóm chat của DevOps VN tại Telegram.
Kém tiếng Anh và cần nâng cao trình độ giao tiếp: Tại sao bạn học không hiệu quả?