Giới thiệu
Chào các bạn tới với series về Terraform, ở 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 cách sử dụng Terraform Cloud để xây dựng CI/CD cho infrastructure của ta. Sau đó chúng ta sẽ tìm hiểu một thuộc tính của Terraform mà giúp ta thực hiện Zero-downtime deployments.
CI/CD with 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 sử dụng là:
- Version control system workflow.
- CLI-driven workflow.
- API-driven workflow.
Với CLI-driven workflow giúp ta trong việc xây dựng Remote Backend, còn Version control system workflow (VCS) sẽ giúp ta trong việc xây dựng luồng CI/CD.
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.
Create github repository
Oke, 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 đó đă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.
Create 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.
Sau khi bạn bấm vào icon Github và kết nối tới github của bạn, nó sẽ dẫn ta qua bước thứ ba là chọn repository, các bạn chọn repository mà các bạn tạo cho ví dụ này, repo của mình tên là terraform-cloud-vcs-example
.
Sau đó nó sẽ dẫn ta qua bước cuối cùng, các bạn điền Workspace Name vào và bấm tạo workspace.
Đợi một chút để terraform cloud setup và bạn sẽ thấy workspace của ta hiện chữ Configuration uploaded successfully .
Oke, vậy là ta đã tạo workspace xong, bây giờ ta chỉ cần viết code và push nó lên github, Terraform Cloud VCS sẽ chạy và tạo infrastructure cho ta.
Implement CI/CD
Các bạn thêm 3 file sau vào repo.
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 code và push lên github.
git add .
git commit -m "init code"
git push
Sau đó ta 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 in ra cho ta plan step, 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à auto luôn, 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 comment, và bấm Confirm Plan.
Terraform Cloud sẽ trigger quá trình apply.
Đợi nó chạy xong.
Lúc này các bạn lên AWS Console thì sẽ thấy EC2 của ta đã được tạo.
Update resource
Bây giờ ta sẽ cập nhật lại instance_type của EC2 và push 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 bạn sẽ thấy Terraform Cloud tự động phát hiện code của ta đã thay đổi và trigger lại plan step mới.
Các bạn bấm Confirm & Apply.
Sau khi nó chạy xong ta sẽ thấy EC2 của ta được update lại với instance type mới.
Destroy resource
Khi xài Terraform Cloud để destroy cũng khá đơn giản. Các bạn bấm vào Settings, chọn Destruction and Deletion.
Sau đó ta chọn Delete from Terraform Cloud.
Nhập vào tên và bấn delete.
Nếu các bạn bấm Delete workspace thì resource của ta đã 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.
Zero-downtime deployment
Đối với EC2 của ta, 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 (ami, user_data), nên khi ta tiến hành quá trình apply thì resource EC2 hiện tại sẽ bị destroy 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ị downtime trong một khoảng thời gian dài.
Để tránh downtime trong trường hợp này, terraform cung cấp cho một meta argument tên là create_before_destroy
.
Use create_before_destroy
Đây là một meta argument giúp ta giải quyết được vấn đề zero-downtime deployment 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 block là lifecycle, trong đó ta sẽ khai báo thuộc tính create_before_destroy là true. Ok bây giờ bạn commit code và đẩy lên github, confirm cho Terraform Cloud 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.
Considering when use create_before_destroy
Thuộc tính create_before_destroy có thể rất thuận tiện, nhưng ta cần nê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 cho resource được, vì sẽ có một xài resource bị conflict.
Ví dụ như là đối với AWS thì S3 bucket là unique tê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 sẽ được tạo ra trước, nhưng bucket name của nó sẽ giống y như thằng cũ thì ta sẽ 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 cho nó còn resource nào thì không thể dùng.
No zero-downtime deployment
Tuy gọi là zero-downtime deployment, nhưng không phải lúc nào ta cũng có thể thực hiện việc này hoàn toàn được. Vì zero-downtime deployment là một vấn đề cần rất nhiều thứ để giải quyết và chỉ có thể áp dụng được với một số resource, như là cập nhật lại các resource mà chứa application, chứ không phải lúc nào ta cũng có thể áp dụng được zero-downtime deployment cho toàn bộ resource trong hệ thống của ta được.
Ví dụ đơn giản nhất là 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 để thực hiện zero-downtime deployment được, vì lúc này RDS của ta nó đâu có bị xóa và tạo lại đâu, nó chỉ cập nhật lại instance_type và bị downtime mà thôi.
Tất nhiên là cũng sẽ có cách để triển khai zero-downtime deployment cho database được, 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 được.
Ở 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 zero-downtime deployment cho database được, là blue/green deployment. Và cũng sẽ làm một ví dụ về blue/green deployment cho autoscaling group, đây là một trong những cách để giảm thiểu thời gian downtime cho hệ thống.
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 zero-downtime deployment cho resource của ta. 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. Hẹn gặp mọi người ở bài tiếp theo ta sẽ tìm hiểu về Blue/Green Deployment.
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