Giới thiệu
Ở bài trước chúng ta đã nói về khái niệm Infrastructure as Code là gì và tại sao nên xài Terraform, và cũng làm một ví dụ đơn giản đầu tiên về Terraform. Ở bài này chúng ta sẽ tìm hiểu chi tiết hơn về cách khởi tạo thư mục dự án và cách viết tệp tin cấu hình cho Terraform.
Tiếp tục ví dụ đơn giản là ta sẽ tạo một EC2 trên AWS Cloud. Để tạo Infrastructure mới, ta sẽ làm theo các bước sau đây. Tạo Workspace => viết tệp tin cấu hình => khởi tạo Workspace với terraform init
=> kiểm tra resrource nào sẽ được tạo ra với terraform plan
=> tạo resource với terraform apply
.
Tạo Workspace và viết cấu hình
Đầu tiên ta sẽ tạo một Workspace, đơn giản là tạo một thư mục thôi. Tạo một thư mục tên là ec2
, sau đó ta tạo một tệp tin tên là main.tf
(này bạn đặt tên gì cũng được) ở trong thư mục. Dán đoạn code sau vào.
provider "aws" {
region = "us-west-2"
}
resource "aws_instance" "hello" {
ami = "ami-09dd2e08d601bff67"
instance_type = "t2.micro"
tags = {
Name = "HelloWorld"
}
}
Tiếp theo ta chạy câu lệnh terraform init
, để nó tải aws provider
xuống thư mục hiện tại để Terraform có thể sử dụng những Provider này và gọi API lên AWS để tạo resource cho ta. Về cú pháp và ý nghĩa của cú pháp trong cấu hình Terraform trên thì các bạn xem ở bài trước.
Khởi tạo workspace
terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.68.0...
- Installed hashicorp/aws v3.68.0 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
...
Sau khi bạn chạy câu lệnh init
xong, bạn sẽ thấy có một thư mục tên là .terraform
được tạo ra, đây là thư mục chứa code của Provider. Cấu trúc thư mục sau khi ta chạy câu lệnh init
.
├── .terraform
│ └── providers
│ └── registry.terraform.io
│ └── hashicorp
│ └── aws
│ └── 3.68.0
│ └── linux_amd64
│ └── terraform-provider-aws_v3.68.0_x5
├── .terraform.lock.hcl
└── main.tf
Kiểm tra resrource nào sẽ được tạo ra
Sau khi khởi tạo Workspace xong, thì trước khi ta tạo resource thực tế, ta cần xem qua là những resrource nào sẽ được tạo, bước này thì không bắt buộc. Nhưng để kĩ càng thì khi làm ta cứ chạy qua bước này, để kiểm tra resource sẽ ra sao trước khi ta tạo nó trên hạ tầng thực sự của ta. Để kiểm tra resrource, ta chạy câu lệnh terraform plan
.
terraform plan
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_instance.hello will be created
+ resource "aws_instance" "hello" {
+ ami = "ami-09dd2e08d601bff67"
+ arn = (known after apply)
...
}
Plan: 1 to add, 0 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.
Khi bạn chạy câu lệnh plan
thì Terraform sẽ hiển thị ra cho bạn những resouce nào sẽ được tạo, ở dòng hiển thị gần cuối bạn sẽ thấy là Plan: 1 to add, 0 to change, 0 to destroy.
, nghĩa là sẽ có 1 resource được thêm vào hạ tầng hiện tại của ta.
Ngoài việc hiển thị những resource sẽ được tạo, câu lệnh này cũng sẽ kiểm tra lỗi cú pháp của tệp tin cấu hình Terraform và sẽ báo lỗi nếu ta không viết đúng cú pháp.
Khi có quá nhiều resource và câu lệnhplan
bị chậm, ta có thể tăng tốc nó lên bằng việc thêm vào thuộc tính-parallelism=n
. Ví dụ như sau:terraform plan -parallelism=2
Nếu bạn cần lưu lại kết quả của câu lệnh plan
, bạn sử dụng thêm thuộc tính -out
khi chạy. Ví dụ ta sẽ lưu lại kết quả của câu lệnh plan
trong tệp tin JSON.
terraform plan -out plan.out
terraform show -json plan.out > plan.json
Tạo resource
Sau khi ta kiểm tra xong thì để tạo resource ta chạy câu lệnh sau.
terraform apply
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_instance.hello will be created
+ resource "aws_instance" "hello" {
+ ami = "ami-09dd2e08d601bff67"
+ arn = (known after apply)
...
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
Khi ta chạy câu lệnh apply
thì Terraform sẽ chạy câu lệnh plan
lại trước, cho ta xem trước resource, và nó sẽ hiện chỗ để hỏi ta là có muốn tạo những resource này không, nếu có thì bạn nhập 'yes'
, chỉ khi ta nhập đúng giá trị này thì resource của ta mới được tạo ra.
Nếu bạn thấy ủa sao câu lệnh apply
cũng chạy plan
, thì ta chạy câu lệnh plan
trước làm quái gì cho mệt vậy? Thì thật ra những câu lệnh trên được thiết kế cho quá trình CI/CD. Ta có thể chạy câu lệnh plan
trước, với thuộc tính -out
để xem trước resource, sau đó ta sẽ chạy câu lệnh apply
với kết quả của plan
trước đó, như sau:
Đầu tiên là sẽ chạy Job để kiểm tra resource.
terraform plan -out plan.out
Nếu mọi thứ ok thì Job trên sẽ thành công và tiếp theo ta sẽ chạy Job để tạo resource.
terraform apply "plan.out"
Ok, quay lại câu lệnh apply
ở trên, bạn nhập vào yes
để nó tạo EC2 trên AWS cho ta.
...
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_instance.hello: Creating...
aws_instance.hello: Still creating... [10s elapsed]
aws_instance.hello: Still creating... [20s elapsed]
aws_instance.hello: Still creating... [30s elapsed]
aws_instance.hello: Still creating... [40s elapsed]
aws_instance.hello: Creation complete after 42s [id=i-0c0285db1ffe968a2]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Khi chạy xong thì bạn sẽ thấy có một tệp tin mới được tạo ra là terraform.tfstate
.
.
├── .terraform
│ └── providers
│ └── registry.terraform.io
│ └── hashicorp
│ └── aws
│ └── 3.68.0
│ └── linux_amd64
│ └── terraform-provider-aws_v3.68.0_x5
├── .terraform.lock.hcl
├── main.tf
└── terraform.tfstate
Đây là tệp tin Terraform dùng để lưu lại trạng thái của tất resource của ta, để nó quản lý và theo dõi tất cả các resource trên hạ tầng. Bạn bấm vào sẽ thấy nó lưu những giá trị của EC2.
{
"version": 4,
"terraform_version": "1.0.0",
"serial": 1,
"lineage": "fa28c290-92d6-987f-c49d-bc546b296c2b",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "aws_instance",
"name": "hello",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"ami": "ami-09dd2e08d601bff67",
...
}
Ta đã hoàn thành việc tạo EC2 trên AWS. Để xóa resource thì các bạn chạy câu lệnh terraform destroy
, khi bạn chạy thì nó cũng sẽ chạy câu lệnh plan
trước để liệt kê ra những resource mà nó sẽ xóa, và hỏi bạn có muốn xóa hay không, bạn nhập yes
thì Terraform sẽ xóa EC2 cho ta. Sau khi Terraform nó chạy xong, bạn mở tệp tin terraform.tfstate
lên thì thấy bây giờ trường resources trong tệp tin này nó sẽ là rỗng.
{
"version": 4,
"terraform_version": "1.0.0",
"serial": 3,
"lineage": "fa28c290-92d6-987f-c49d-bc546b296c2b",
"outputs": {},
"resources": []
}
Ở trên là các bước ta cần thực hiện để tạo một hạ tầng mới. Và bên cạnh việc ta sử dụng resource block
để tạo hạ tầng, thì Terraform có cung cấp cho ta một block khác dùng để truy vấn và tìm kiếm dữ liệu trên AWS, block này sẽ giúp ta tạo hạ tầng một cách linh hoạt hơn nhiều thay vì phải điền cứng giá trị của resource. Ví dụ như ở trên thì trường ami
của EC2 ta để cứng giá trị là ami-09dd2e08d601bff67, để biết được giá trị này thì ta phải lên AWS để kiếm, với lại nếu ta dùng giá trị này thì người khác đọc cũng không biết được giá trị này là thuộc AMI loại gì.
Data block
Terraform cung cấp cho ta một block tên là data
, được dùng để gọi API lên hạ tầng thông qua Provider của ta và lấy thông tin về một resource nào đó, block này nó sẽ không thực hiện hành động tạo resource trên hạ tầng. Ta cập nhật tệp tin main.tf
lại như sau:
provider "aws" {
region = "us-west-2"
}
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
owners = ["099720109477"] # Canonical Ubuntu AWS account id
}
resource "aws_instance" "hello" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
tags = {
Name = "HelloWorld"
}
}
Ở cấu hình trên thì ta sẽ dùng data block
để gọi API tới AWS Cloud và lấy thông tin về AMI (Amazon Machine Images), sau đó ở dưới resource block
ta thay đổi lại trường ami
bằng giá trị id mà ta lấy được từ block ở trên ra. Cú pháp của data block
.
Khi bạn chạy câu lệnh plan
, bạn sẽ thấy ở dòng Plan gần cuối nó vẫn chỉ hiển thị chỉ 1 resource sẽ được thêm do data block
không tạo ra resource, bên cạnh đó thì ở trường AMI nó sẽ in ra giá trị lấy được từ data block
.
terraform plan
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_instance.hello will be created
+ resource "aws_instance" "hello" {
+ ami = "ami-0892d3c7ee96c0bf7"
...
}
Plan: 1 to add, 0 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.
Minh họa như sau.
Sử dụng data block
sẽ giúp ta linh hoạt hơn trong việc viết code.
Kết luận
Vậy là ta đã biết cách viết cấu hình Terraform và chạy những câu lệnh gì để Terraform có thể tạo resource trên hạ tầng cho ta. Và để hiểu rõ hơn về cách Terraform tạo resource ra sao, ở bài tiếp theo ta sẽ nói về vòng đời của một resource 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ả?