0

🏗️🧠 Infrastructure as Code: hạ tầng không nên được dựng bằng tay - System Design P31

Infrastructure as Code (IaC): Khi Hạ Tầng Trở Thành "Công Dân Hạng Nhất" Của Phần Mềm

1. LỜI DẪN: CƠN ÁC MỘNG 2 GIỜ SÁNG VÀ KHOẢNG CÁCH GIỮA HAI TAB TRÌNH DUYỆT

Hãy tưởng tượng bạn là một Senior SRE đang trực chiến (on-call). Đồng hồ điểm 2 giờ sáng, hệ thống Production của công ty đột ngột "chết lâm sàng" ngay sau một đợt deploy tính năng mới. Điều kỳ quái là: cùng một bản build đó, cùng những cấu hình đó, mọi thứ chạy hoàn hảo trên môi trường Staging.

Bạn ngồi đó, mắt dán vào màn hình với hai tab trình duyệt mở song song bảng điều khiển Cloud Console của AWS. Một bên là Staging, một bên là Production. Bạn bắt đầu thực hiện một công việc mà mọi kỹ sư đều căm ghét: "mò kim đáy bể". Bạn so sánh từng dòng cấu hình Security Group, từng tham số của RDS, từng biến môi trường (environment variables). Sau hơn hai tiếng đồng hồ căng thẳng, bạn nhận ra sự khác biệt nằm ở một quy tắc Inbound Rule: Ở Staging là dải IP /24 (rộng), còn ở Production ai đó đã lén sửa thành /32 (chỉ một IP duy nhất) trong một đợt "hotfix" bằng tay tuần trước nhưng không hề ghi chép lại.

Cái giá của sự sai lệch đó là 2 giờ sập hệ thống và sự bất lực tột độ của đội ngũ kỹ thuật. Lúc này, bạn nhận ra một chân lý nghiệt ngã: Hạ tầng không phải là một thực thể tĩnh để chúng ta "đặt" code lên. Bản thân hạ tầng phải được đối xử như một phần mềm. Nó cần được phiên bản hóa, được kiểm tra (test), và được triển khai tự động. Đó chính là lúc triết lý Infrastructure as Code (IaC) không còn là một "option" hào nhoáng, mà là nền tảng sinh tồn của một hệ thống hiện đại.

2. NIỀM TIN PHỔ BIẾN VS. THỰC TẾ NGHIỆT NGÃ

Trong giới kỹ thuật, chúng ta thường bao biện cho việc quản lý hạ tầng thủ công bằng những lý do nghe có vẻ hợp lý, nhưng thực chất là những "quả bom hẹn giờ".

  • Kỳ vọng: "Team mình còn nhỏ, hạ tầng đơn giản, cứ lên UI Cloud bấm tay vài cái là xong cho nhanh. Khi nào hệ thống lớn, nhiều server thì dùng IaC sau."
    • Thực tế: Thao tác tay (ClickOps) là một loại nợ kỹ thuật vận hành (operational technical debt) với lãi suất kép cực cao. Sự nhanh chóng ban đầu đó sẽ bị trả giá bằng sự thiếu nhất quán (inconsistency). Chỉ cần một cú click nhầm, bạn tạo ra một lỗ hổng bảo mật hoặc một cấu hình sai lệch mà không có cách nào truy vết. "Khi nào lớn mới làm" thường dẫn đến việc "không bao giờ lớn nổi" vì team bị sa lầy vào việc vá lỗi vận hành.
  • Kỳ vọng: "Chỉ cần viết tài liệu hướng dẫn (Runbook/Wiki) thật kỹ, từng bước một, thì ai cũng có thể dựng lại hệ thống y hệt."
    • Thực tế: Tài liệu là một thực thể "chết" ngay khi nó vừa được viết xong. Con người không phải là máy móc; chúng ta thường xuyên bỏ sót bước, hiểu sai ý hoặc quên cập nhật tài liệu khi có thay đổi khẩn cấp (emergency hotfix). Một Runbook 50 bước để dựng một cụm Kubernetes bằng tay là một lời mời gọi cho thảm họa.
  • Kỳ vọng: "Logic code mới quan trọng, hạ tầng chỉ là phần cứng bên dưới, chỉ cần nó chạy được là đủ."
    • Thực tế: Một hệ thống không thể tái lập (non-reproducible) là một hệ thống không đáng tin cậy. Nếu toàn bộ Region của Cloud provider bị sập và bạn mất 48 giờ để "nhớ lại và bấm tay" dựng lại hạ tầng ở một Region khác, doanh nghiệp của bạn có thể đã phá sản trước khi server kịp online.

3. PHÂN TÍCH GỐC RỄ: TẠI SAO MANUAL INFRASTRUCTURE LÀ "BOM HẸN GIỜ"?

Dưới lăng kính của một SRE Lead, việc quản lý hạ tầng bằng tay tạo ra những lỗ hổng chí mạng về mặt quản trị và kỹ thuật:

Environment Drift (Sự sai lệch môi trường)

Đây là "kẻ giết người thầm lặng". Theo thời gian, các môi trường Dev, Staging và Production dần xa rời nhau do những thay đổi nhỏ, lẻ tẻ không được đồng bộ. Một kỹ sư sửa cấu hình timeout của Load Balancer trên Prod để xử lý một request đặc biệt, một người khác cài thêm một thư viện hệ thống trên Dev để test tính năng mới. Kết quả? Môi trường Staging không còn là "tấm gương" phản chiếu Production nữa. Mọi kết quả test trên Staging trở nên vô nghĩa, và rủi ro "deploy là chết" tăng lên theo từng ngày.

Tribal Knowledge (Kiến thức bộ lạc)

Khi hạ tầng nằm trong các cú click chuột, toàn bộ "sự thật" về hệ thống chỉ nằm trong đầu một vài cá nhân cựu trào – những người duy nhất biết tại sao port 8443 lại được mở hay tại sao instance này phải dùng dòng c5.xlarge mà không phải m5. Đây là rủi ro kinh doanh cực lớn. Nếu những cá nhân này nghỉ việc hoặc vắng mặt trong sự cố, hệ thống trở thành một "hộp đen" bất khả xâm phạm. Team còn lại sẽ rơi vào trạng thái sợ hãi, không dám thay đổi bất cứ thứ gì vì sợ làm sụp đổ toàn bộ kiến trúc.

Lack of Auditability & Compliance (Sự mù mờ về lịch sử)

Trong một hệ thống được quản lý thủ công, câu hỏi: "Ai đã thay đổi cấu hình này? Vào lúc nào? Tại sao?" thường chỉ nhận lại những cái lắc đầu. Điều này không chỉ gây khó khăn cho việc debug mà còn là thảm họa về bảo mật và tuân thủ (compliance). Với IaC, mọi thay đổi đều là một Commit, có người viết, có người review, và có lý do được ghi lại rõ ràng trong lịch sử Git.

4. TƯ DUY KỸ SƯ: IAC KHÔNG CHỈ LÀ TOOL, ĐÓ LÀ MỘT TRIẾT LÝ

IaC không đơn thuần là việc bạn chuyển từ bấm nút sang viết file .tf của Terraform hay .yaml của CloudFormation. Đó là một sự chuyển dịch hoàn toàn về tư duy quản trị hệ thống.

Declarative vs. Imperative (Khai báo vs. Mệnh lệnh)

Hãy tưởng tượng bạn đang đặt món trong nhà hàng.

  • Imperative (Mệnh lệnh): Bạn đi vào bếp và hướng dẫn đầu bếp: "Lấy cái chảo, bật lửa, đổ dầu, đập trứng, chiên trong 2 phút...". Nếu đầu bếp đang cầm cái chảo khác hoặc lửa đã bật sẵn, các bước của bạn có thể gây ra lỗi. Đây là cách các script Bash/Python vận hành.
  • Declarative (Khai báo): Bạn chỉ cần nói: "Tôi muốn một đĩa trứng ốp la chín vừa". Bạn không quan tâm đầu bếp làm thế nào, bạn chỉ mô tả trạng thái mong muốn (desired state). IaC hiện đại (như Terraform) đi theo hướng này. Bạn mô tả: "Tôi muốn có 5 server nằm sau một Load Balancer", và công cụ IaC sẽ tự tính toán những gì cần làm để đạt được trạng thái đó.

Reconciliation Loop (Vòng lặp điều hòa)

Đây là "bộ não" của IaC. Hệ thống sẽ liên tục kiểm tra giữa "Những gì bạn viết trong code" và "Những gì đang thực sự chạy trên Cloud". Nếu có ai đó lẻn lên UI để xóa một server, trong lần chạy tiếp theo, công cụ IaC sẽ nhận ra sự sai lệch (drift) và tự động tạo lại server đó để khớp với code. Đây là cơ chế tự chữa lành (self-healing) căn bản nhất.

Idempotency (Tính giao hoán)

Một thuộc tính cực kỳ quan trọng: Dù bạn chạy script IaC của mình 1 lần hay 100 lần, kết quả cuối cùng trên hạ tầng phải luôn giống nhau. Nó không tạo thêm 100 server nếu bạn đã có đủ số lượng yêu cầu. Điều này mang lại sự tự tin tuyệt đối cho kỹ sư khi triển khai hệ thống.

5. HÀNH TRÌNH TRƯỞNG THÀNH CỦA HỆ THỐNG (EVOLUTION THINKING)

Hạ tầng không tự nhiên mà trở nên hoàn hảo. Nó trải qua các giai đoạn tiến hóa mà ở mỗi bước, nỗi đau về vận hành sẽ ép chúng ta phải thay đổi.

  • Stage 1: ClickOps (Thủ công). Phù hợp cho việc tìm hiểu dịch vụ mới (Exploration). Nhưng ngay khi bạn có môi trường thứ hai, giai đoạn này phải kết thúc.
  • Stage 2: Infrastructure as Scripts (Bash/Python). Đội ngũ bắt đầu tự động hóa bằng script. Điểm gãy (Turning Point): Khi các script này trở thành một "đống spaghetti" dài 2000 dòng mà chỉ một người hiểu được. Script không quản lý được trạng thái (state) – nếu script chạy lỗi ở giữa chừng, bạn không biết cái gì đã tạo, cái gì chưa.
  • Stage 3: Provisioning (IaC chuyên dụng). Áp dụng Terraform, Pulumi hay CloudFormation. Hạ tầng được định nghĩa rõ ràng, có thể tái lập. Đây là lúc khái niệm "Source of Truth" chuyển từ Cloud Console sang Git.
  • Stage 4: Automated Deployment (GitOps). IaC kết hợp chặt chẽ với CI/CD. Việc thay đổi hạ tầng diễn ra qua Pull Request. Mọi thay đổi đều được kiểm tra (Plan) tự động để xem nó sẽ ảnh hưởng đến bao nhiêu tài nguyên trước khi áp dụng thực tế.
  • Stage 5: Platform Engineering & Self-service. Đội ngũ SRE/Platform cung cấp các Module IaC chuẩn hóa (đã được cấu hình sẵn bảo mật, logging, backup). Các team Product có thể tự "order" hạ tầng cho service của mình bằng cách gọi các Module này. Hạ tầng lúc này thực sự trở thành một nền tảng phục vụ sự phát triển của toàn doanh nghiệp.

6. PHÂN TÍCH ĐÁNH ĐỔ (TRADE-OFF ANALYSIS)

Làm IaC không phải là "miễn phí". Là một Senior, bạn phải nhìn thấy cả hai mặt của đồng xu:

Yếu tố Lợi ích (Benefits) Chi phí & Rủi ro (Cost & Risk)
Tốc độ (Velocity) Triển khai cả một hệ thống phức tạp trong 15 phút thay vì 3 ngày bấm tay. Đường cong học tập: Đội ngũ cần thời gian để học ngôn ngữ mới (HCL, YAML) và tư duy khai báo.
Độ tin cậy Đảm bảo môi trường Dev/Staging/Prod giống hệt nhau. Loại bỏ lỗi do con người. Blast Radius (Bán kính thiệt hại): Một dòng code sai trong IaC có thể xóa sổ toàn bộ hạ tầng Production chỉ trong vài giây.
Khả năng kiểm soát Review được hạ tầng qua code. Rollback nhanh chóng về phiên bản cũ. Quản lý State: File state (lưu trữ hiện trạng hạ tầng) cực kỳ nhạy cảm. Nếu file này mất hoặc bị hỏng, IaC sẽ "mù" và có thể phá hủy tài nguyên đang chạy.
Khả năng tái lập Dễ dàng nhân bản hệ thống sang các Region khác nhau để phục vụ mở rộng toàn cầu. Provider Lock-in: Code IaC thường gắn chặt với một Cloud Provider (AWS/GCP/Azure). Chuyển Cloud là phải viết lại gần như toàn bộ.

Lời khuyên từ Senior: Nếu bạn đang làm MVP cực nhỏ và thay đổi cấu hình mỗi 5 phút, hãy dùng UI để thử nghiệm. Nhưng ngay khi bạn có server thứ hai, hoặc có thành viên thứ hai gia nhập team, hãy bắt đầu codify hạ tầng ngay lập tức. Đừng đợi đến khi "nợ" quá dày mới trả.

7. GÓC NHÌN SENIOR: NHỮNG BÀI HỌC "XƯƠNG MÁU" TỪ PRODUCTION

Dưới đây là những gì mà các tutorial trên mạng thường không nói cho bạn biết, nhưng thực tế sẽ khiến bạn mất ngủ:

Sự cố State Lock và Corruption

Khi nhiều người cùng sửa hạ tầng, nếu không có cơ chế Locking (như dùng S3 + DynamoDB cho Terraform state), hai lệnh apply chạy song song có thể làm hỏng file trạng thái. Kết quả: Công cụ IaC nghĩ rằng cơ sở dữ liệu Production chưa tồn tại và cố gắng tạo mới (đồng nghĩa với việc xóa cái cũ). Luôn luôn phải có chiến lược quản lý State tập trung và an toàn.

"Cuộc đua" xoay vòng Secret (Secret Rotation Marathon)

Tôi từng chứng kiến một kỹ sư push nhầm AWS_ACCESS_KEY vào Git chứa code IaC. Thảm họa không nằm ở việc xóa commit đó (Git không bao giờ thực sự xóa được lịch sử trừ khi bạn force push). Thảm họa là chúng ta phải thực hiện "rotation" cho hàng chục Secret key trên toàn hệ thống ngay lập tức.Bài học: Tuyệt đối không hard-code Secret vào IaC. Hãy sử dụng các giải pháp như AWS Secrets Manager hoặc HashiCorp Vault và gọi chúng qua tham số.

Thảm họa từ lệnh "Destroy" và Destructive Changes

Có những thay đổi trong IaC trông rất vô hại (như đổi tên một Resource) nhưng Cloud Provider lại thực hiện bằng cách: Xóa đi và Tạo lại. Nếu Resource đó là một Database chứa 10TB dữ liệu mà bạn không bật tính năng prevent_destroy hay deletion_protection, bạn vừa mới xóa sổ tài sản quý giá nhất của công ty. Một Senior Engineer luôn phải kiểm tra kỹ lệnh plan để xem có dòng nào mang màu đỏ (Delete) hay không trước khi nhấn xác nhận.

Những "Tài nguyên ma" (Ghost Resources)

Đôi khi việc triển khai IaC bị thất bại giữa chừng (do timeout hoặc lỗi API của Cloud). Kết quả là một số tài nguyên đã được tạo nhưng không được ghi nhận vào file State. Những tài nguyên này nằm đó, tiêu tốn tiền bạc nhưng không ai quản lý được. Một SRE giỏi phải biết cách "Import" những tài nguyên này ngược lại vào code để đưa chúng vào tầm kiểm soát.

8. TỔNG KẾT VÀ BÀI HỌC CỐT LÕI

Hạ tầng được quản lý bằng thao tác tay là một lời hứa chắc chắn sẽ bị phá vỡ. Infrastructure as Code không chỉ là về công cụ, nó là về việc tạo ra một quy trình vận hành minh bạch, an toàn và có khả năng mở rộng.

3 điều kỹ sư cần nhớ để thay đổi tư duy:

  1. Hạ tầng phải nằm trong Version Control: Nếu một cấu hình hạ tầng không tồn tại trong Git, nó không thực sự tồn tại (hoặc nó là một rủi ro tiềm tàng).
  2. Ưu tiên tư duy "Trạng thái mong muốn": Đừng dạy hệ thống làm thế nào, hãy mô tả bạn muốn hệ thống trông như thế nào.
  3. Hạ tầng là một "Công dân hạng nhất": Nó cần được Code Review, Unit Test (với Checkov, Terratest) và triển khai thông qua Pipeline chuyên nghiệp y hệt như Application Code.

9. OPEN LOOP & CHUYỂN TIẾP

Khi hạ tầng của bạn đã được định nghĩa hoàn toàn bằng code, chúng ta đã mở ra một cánh cửa mới đầy quyền năng. Chúng ta không còn phải lo lắng về việc tạo thêm 10 hay 100 server nữa. Nhưng một câu hỏi quan trọng khác xuất hiện:

"Làm thế nào để hệ thống này không chỉ nằm yên trong code, mà có thể tự động 'phình to' khi hàng triệu khách hàng ập đến trong đêm Sale, và tự động 'thu nhỏ' lại để tiết kiệm từng đồng xu cho doanh nghiệp khi mọi người đã đi ngủ?"

Khả năng "co giãn" tự động này không thể thành hiện thực nếu thiếu nền tảng IaC bền vững mà chúng ta vừa thảo luận.

Mời các bạn đón đọc tập tiếp theo: Episode 32 - Autoscaling: Hệ Thống Tự “Phình To – Thu Nhỏ” Theo Lưu Lượng.



🚀 Tiếp tục hành trình cùng TechCraft

Bài viết này là một phần trong hành trình khám phá Backend Engineering, System Design và Production Systems tại TechCraft.

Nếu bạn muốn học theo một lộ trình rõ ràng hơn, TechCraft đang xây dựng Dev Insider như nơi tập trung các series chuyên sâu hơn về:

  • Backend Internals
  • Database Internals
  • Transaction & Consistency
  • Distributed Systems
  • Production System Design
  • AI-Proof Engineer

🚀 Dev Insider
https://www.patreon.com/techcraft_official/posts/vi-sao-dev-ra-161163881?collection=2220113

📘 Facebook
https://www.facebook.com/techcraft.official

🎥 YouTube
https://www.youtube.com/@techcraft.official

🎵 TikTok
https://www.tiktok.com/@techcraft.official

Hiểu hệ thống. Không chỉ framework.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí