Chào anh chị em gần xa, cũng đã rất lâu rồi tôi không có dịp viết bài về kỹ thuật, nhân dịp xây dựng lại website dạy học CuliOps, ngoài việc muốn chia sẽ những kinh nghiệm của mình, tôi cũng muốn bài viết sẽ là công cụ để quảng bá CuliOps đến anh chị em. Và vì cũng rất lâu rồi tôi mới viết bài, nên nếu có gì sai sót mong các anh chị em bỏ qua và góp ý để cho chất lượng các bài tiếp theo sẽ tốt hơn.
Bài viết sẽ tập trung vào việc làm thế nào để thiết kế và cấu trúc cho một dự án mà hạ tầng được quản lý bằng IaC(Infrastructure as Code), cụ thể ở đây là Terraform. Tại sao lại là Terraform mà không phải các IaC tools khác. Tôi nghĩ về phương diện các ngôn ngữ khai báo trong việc quản lý hạ tầng, Terraform cho tôi cảm giác có thể lập trình nhiều hơn so với CloudFormation(AWS). Điều này có nghĩa, tôi có thể viết code, test code, build CI/CD giống như 1 ngôn ngữ bình thường ở một mức độ vừa đủ.
Nhiều anh chị đọc đến đây sẽ thắc mắc, nếu thích lập trình để quản lý hạ tầng sao không dùng Pulumi hay các CDKs, cơ bản vì nó đòi hỏi kỹ năng lập trình quá nhiều, bạn sẽ tốn thời gian và nhân lực hơn để xây dựng và bảo trì các thành phần hạ tầng cho một dự án. Tôi nghĩ CDK sẽ tốt cho các công ty mà ở đó có team chuyên xây dựng và phát triển các công cụ dành riêng cho nội bộ(Internal Developer Platform - IDP), nói chung là các công ty thừa tiền, nhân lực, hoặc đang muốn chuyển đổi và chuẩn hoá quy trình nội bộ bằng các giải pháp công nghệ.
Do đó, trong bài viết này một yêu cầu cơ bản đó là bạn đang hoặc đã sử dụng Terraform một thời gian, bạn đang chuẩn bị ứng dụng Terraform vào trong hạ tầng của mình. Hoặc dành cho các bạn đã từng sử dụng các CaC(Configuration as Code) như Ansible, và nay muốn tìm hiểu Terraform.
Tôi nghĩ 1 pattern đang được sử dụng phổ biến hiện này, chính là thiết kế terraform code thành các module khác nhau. Mỗi module là nơi tập hợp các terraform code, để triển khai một thành phần cơ bản, hoặc có thể là kết hợp nhiều thành phần với nhau. Mục đích, có khả năng sử dụng lại terraform code. Tuy nhiên, việc tạo ra 1 module để có thể dễ dàng sử dụng và khả năng mở rộng cho module cũng là một vấn đề cần chú ý. Rất tiếc, trong phạm vi bài viết này tôi không thể đi sâu vào chi tiết làm thế nào để viết một module đủ tốt, mà hẹn các anh chị ở một bài viết khác.
module "database" {
source = "../modules/rds"
name = "culiops-${local.env}-${local.country_code}"
}
Như các bạn đã biết, mỗi Terraform workspace sẽ cần chỉ định nơi để chứa dữ liệu trạng thái, để Terraform có thể theo dõi tài nguyên nào đang có sự thay đổi.
Và ở trên, như tôi có chia sẽ một số trường hợp thực tế, trong một vài trường hợp khi bạn cần truy cập dữ liệu hạ tầng giữa các terraform workspaces. Ví dụ như, khi triển khai hạ tầng trên một quốc gia hay một môi trường, tôi cần truy cập các tài nguyên đang được chia sẽ và dùng chung, lúc này tôi sẽ sử dụng một terraform resource có tên terraform_remote_state.
data "terraform_remote_state" "vpc" {
backend = "remote"
config = {
organization = "hashicorp"
workspaces = {
name = "vpc-prod"
}
}
}
# Terraform >= 0.12
resource "aws_instance" "foo" {
# ...
subnet_id = data.terraform_remote_state.vpc.outputs.subnet_id
}
Nếu anh chị đã từng sử dụng AWS public cloud, chắc sẽ không còn xa lạ với khái niệm về IAM Role và Assume Role. Assume một role là một hoạt động cho phép một đối tượng trong AWS IAM sử dụng một tập hợp thông tin đăng nhập bảo mật tạm thời của role đó để truy cập tài nguyên AWS. Tôi không chắc GCP hay Azure có những khái niệm tương tự hay không, nếu có hỗ trợ, tôi khuyên các bạn nên sử dụng.
Một vấn đề tôi nghĩ trong một số ít anh chị, có thể sẽ có thói quen dùng một tài khoản người dùng có quyền administrator hoặc root account để triển khai tài nguyên hạ tầng cho tất cả các dịch vụ. Việc này có thể giúp các bạn tiết kiệm thời gian để triển khai vì các bạn sẽ không cần phải suy nghĩ về vấn đề cần quyền hạn gì để truy cập tài nguyên.
Tuy nhiên, nó cũng có một vấn đề, đó là khi một ai đó từ developer team từ dịch vụ này cần truy cập tài nguyên hạ tầng, mà không thể truy cập tài nguyên của dịch vụ khác. Khi các bạn thiết kế mỗi một dịch vụ sẽ sử dụng một assume role khác nhau, đồng nghĩa việc truy cập và thao tác tài nguyên trên dịch vụ này sẽ không ảnh hưởng đến dịch vụ khác. Và lúc này, bạn chỉ cần cho phép developer team của dịch vụ nào assume role đến role của dịch vụ đó.
Hoặc, nếu bạn đang sử dụng Atlantis hoặc Terraform Cloud cho team collaboration , việc thiết lập này có thể giới hạn các quyền cần thiết và tối thiểu để uỷ quyền cho Atlantis/Terraform Cloud truy cập và thay đổi tài nguyên hạ tầng của anh chị.
provider "aws" {
region = "us-east-2"
assume_role {
role_arn = ""
}
}
Trên là một số mẫu thiết kế tôi đúc kết được trong quá trình triển khai hạ tầng bằng Terraform, nếu anh chị biết thêm mẫu thiết kế nào hoặc bất kỳ góp ý nào thì hãy comment hoặc đóng góp ý kiến để tôi có thể cập nhật cho bài viết trở nên phong phú và chất lượng.
Tôi có sử dụng vài từ tiếng Anh trong bài viết, vì thực sự tôi không biết phải dịch sao cho sát nghĩa, nên tôi nghĩ cứ giữ tiếng Anh có khi anh chị lại dễ hiểu hơn.
Tôi dự định sẽ viết tất cả trong một bài, nhưng có vẽ nó khá dài đối với anh chị, nên tôi xin phép tổng kết bài 1 tại đây. Bài 2 tôi sẽ tập trung đưa ra 1 trường hợp thực tế và cách tôi áp dụng các thiết kế ở trên cho một dự án mà tôi đã thực hiện. Tôi cũng sẽ trình bày cách tôi tổ chức và sắp xếp các Terraform workplaces như thế nào.