Giới thiệu
Ở bài trước chúng ta đã tìm hiểu về Remote Backend với Terraform Cloud. Ở bài này chúng ta sẽ tìm hiểu cách sử dụng Terraform Cloud để xây dựng CI/CD cho hạ tầng. Sau đó chúng ta sẽ tìm hiểu một thuộc tính của Terraform giúp ta thực hiện triển khai Zero-downtime.
CI/CD với Terraform Cloud
Như ta đã nói ở bài trước, khi ta tạo một Workspaces trên Terraform Cloud thì sẽ có ba cách là:
- Version Control System Workflow (VCS): xây dựng CI/CD
- CLI-driven Workflow: xây dựng Remote Backend
- API-driven Workflow
Với Terraform Cloud VCS việc xây dựng CI/CD rất dễ dàng, tất cả những gì chúng ta cần làm là tạo một Github Repository, kết nối Repository đó tới Terraform Cloud, sau đó ta chỉ việc đẩy code lên Github và Terraform Cloud sẽ thực hiện toàn bộ luồng CI/CD cho ta.
Tạo Github Repository
Trước tiên các bạn tạo một Repository trên Github, đây là Repository của mình cho ví dụ này https://github.com/hoalongnatsu/terraform-cloud-vcs-example
.
Sau đó ta đăng nhập vào Terraform Cloud, cách đăng ký tài khoản và cấu hình AWS Credentials các bạn xem ở bài trước, màn hình sau khi đăng nhập vào Terraform Cloud.
Tạo VCS Workspace
Ở trang Workspaces ta bấm New Workspaces, sau đó chọn Version control workflow.
Bước tiếp theo, chỗ Connect to a version control provider, các bạn bấm vào icon Github.
Tiếp theo các bạn chọn Repository mà các bạn tạo cho ví dụ này, của mình tên là terraform-cloud-vcs-example
.
Tiếp theo các bạn điền Workspace Name vào và bấm tạo Workspace.
Đợi một chút và ta sẽ thấy Workspace hiện chữ Configuration uploaded successfully .
Vậy là ta đã tạo Workspace xong, bây giờ ta chỉ cần viết code và đẩy nó lên Github. Terraform Cloud VCS sẽ chạy và tạo hạ tầng cho ta.
Thực hiện CI/CD
Các bạn thêm 3 tệp tin sau vào Repository.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
variable "region" {
type = string
default = "us-west-2"
}
provider "aws" {
region = var.region
}
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" "ansible_server" {
ami = data.aws_ami.ami.id
instance_type = "t3.micro"
}
Commit và đẩy lên Github.
git add .
git commit -m "init code"
git push
Quay lại UI của Terraform Cloud, các bạn bấm vào Action chọn Start new run.
Ta sẽ thấy Terraform Cloud thực thi bước plan
, thay vì chạy câu lệnh CLI và thấy tất cả resource của ta in ta trên Terminal. Thì Terraform Cloud sẽ in resource của ta trên UI rất trực quan và dễ hiểu.
Kéo xuống phía dưới ta sẽ thấy có chỗ để chúng ta bấm apply
. Ta có thể cấu hình bước này là tự động, nhưng đối với môi trường Production ta không nên cho phép nó auto apply
. Các bạn bấm Confirm & Apply.
Nhập vào bình luận, và bấm Confirm Plan.
Terraform Cloud sẽ thực thi quá trình apply
.
Đợi nó chạy xong.
Lúc này các bạn lên AWS Console kiểm tra thì sẽ thấy EC2 vừa được tạo bằng Terraform Cloud.
Cập nhật resource
Cập nhật lại instance_type
của EC2 và đẩy code lên lại Github.
resource "aws_instance" "ansible_server" {
ami = data.aws_ami.ami.id
instance_type = "t3.small" // t3.micro -> t3.small
}
git commit -am "update instance type"
git push
Lúc này Terraform Cloud tự động phát hiện code của ta đã thay đổi và thực thi lại bước plan
.
Các bạn bấm Confirm & Apply.
Sau khi nó chạy xong ta sẽ thấy EC2 được cập nhật lại với Instance Type mới.
Xóa resource
Với Terraform Cloud thì việc xóa resource khá đơn giản. Các bạn bấm vào Settings, chọn Destruction and Deletion.
Sau đó chọn Delete from Terraform Cloud.
Nhập vào tên.
Nếu các bạn bấm Delete workspace thì resource của ta sẽ bị xóa đi. Nhưng lúc này các bạn chưa xóa vội nhé, ta sẽ để nó lại để làm ví dụ tiếp theo.
Triển khai Zero-downtime
Đối với EC2 khi ta thay đổi giá trị ami
.
resource "aws_instance" "ansible_server" {
ami = data.aws_ami.ami.id // change here
instance_type = "t3.small"
}
Vì ami
của EC2 là một force-new attributes force-new attributes
, nên khi ta tiến hành quá trình apply
thì EC2 hiện tại sẽ bị xóa và một thằng mới sẽ được tạo ra. Đây là hành động mặc định của Terraform đối với các resource mà có force-new attributes
bị thay đổi. Điều này có thể dẫn tới hệ thống của ta bị đứng trong một khoảng thời gian.
Để tránh hệ thống bị đứng trong trường hợp này, Terraform cung cấp một Meta Argument tên là create_before_destroy
.
Sử dụng create_before_destroy
Đây là một Meta Argument giúp ta triển khai zero-downtime khi ta thay đổi force-new attributes
của một resource.
Thay vì Terraform sẽ hành động như mặc định là xóa resource trước rồi tạo resource mới sau, thì Terraform sẽ hành động ngược lại là sẽ tạo resource trước, kiểm tra resource đó được tạo xong rồi thì nó mới tiến hành xóa resource cũ.
Ta sử dụng thuộc tính create_before_destroy
như sau, cập nhật lại main.tf
resource "aws_instance" "ansible_server" {
ami = data.aws_ami.ami.id
instance_type = "t3.small"
lifecycle {
create_before_destroy = true
}
}
Ta thêm một thuộc tính là lifecycle
, trong đó ta sẽ khai báo thuộc tính create_before_destroy
là true
. Bây giờ bạn Commit và đẩy code lên Github, bấm Confirm cho Terraform Cloud chạy apply
, quan sát trên AWS Console chỗ EC2 thì ta sẽ thấy lúc này một con EC2 mới sẽ được tạo ra trước sau đó con cũ mới bị xóa đi.
Lưu ý
Thuộc tính create_before_destroy
có thể rất thuận tiện, nhưng ta cần lưu ý một điều là không phải lúc nào ta cũng có thể sử dụng thuộc tính này được, vì sẽ dẫn tới xung đột.
Ví dụ đối với AWS thì tên của S3 Bucket là duy nhất trên toàn bộ hệ thống của AWS, nên nếu ta dùng thuộc tính create_before_destroy
với S3 thì nó sẽ bị lỗi, vì lúc này S3 Bucket mới được tạo ra trước nhưng tên của nó sẽ giống y như cũ => dẫn tới việc gặp lỗi ngay.
Vì lý do trên nên ta cần xem xét cẩn thận khi dùng create_before_destroy
, ta phải xác định rõ resource nào ta có thể dùng create_before_destroy
và resource nào thì không.
Không có cái gọi là Zero-downtime
Tuy gọi là triển khai Zero-downtime nhưng không phải lúc nào ta cũng có thể thực hiện việc này được. Vì triển khai Zero-downtime là một vấn đề phức tạp và chỉ có thể áp dụng được với một số resource.
Ví dụ dịch vụ Database của AWS là RDS, khi ta thay đổi instance_type
của nó thì ta không thể sử dụng thuộc tính create_before_destroy
được. Vì lúc này RDS nó chỉ cập nhật lại instance_type
chứ không có xóa và tạo lại.
Tất nhiên là cũng sẽ có cách để triển khai Zero-downtime cho Database nhưng quá trình thực hiện sẽ rất phức tạp và cần kết hợp nhiều công cụ khác nhau chứ không thể chỉ dùng Terraform.
Ở bài tiếp theo mình sẽ nói về một khái niệm mà có thể giúp ta thực hiện triển khai Zero-downtime cho Database là Blue/Green Deployment.
Kết luận
Vậy là ta đã tìm hiểu xong về cách thực hiện CI/CD với Terraform Cloud, và một cách đơn giản để thực hiện triển khai Zero-downtime. Bài tiếp theo ta sẽ tìm hiểu về Blue/Green Deployment.
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ả?