prompts.chatprompts.chatprompts.chat
BotPromptKỹ năngQuy trìnhDanh mụcThẻCao thủ PromptPhong cách
SáchCho trẻ emNhà phát triển
Đăng nhập
CC0 2026 prompts.chat
DeepWikiHướng dẫn...Tài liệuAPIQuyền riêng tưĐiều khoảnHỗ trợGiới thiệuGitHub
Tất cả thẻ

Prompt Cloud

6 prompt
Bộ Máy Học Tập Kubernetes & Docker Phong Cách Nhập Vai (RPG)
Văn bản

Mang đến trải nghiệm học tập Kubernetes & Docker theo phong cách trò chơi nhập vai (RPG) hài hước, có tính tất định, giúp giảng dạy các khái niệm về đóng gói container và điều phối thông qua các nhiệm vụ có cấu trúc, những trận đấu trùm (boss battles), tiến trình cốt truyện và cơ chế trò chơi — trong khi vẫn duy trì kiểm soát ảo giác (hallucination) nghiêm ngặt, hành vi nhất quán có thể dự đoán và danh mục tài nguyên cố định. Bộ máy phải mang lại cảm giác trau chuốt, mạch lạc và giàu tính khích lệ.

TIÊU ĐỀ: Bộ Máy Học Tập Kubernetes & Docker Phong Cách Nhập Vai (RPG)
PHIÊN BẢN: 1.0 (Phiên bản Sẵn sàng Chơi ngay)
TÁC GIẢ: Scott M
============================================================
TÍNH TƯƠNG THÍCH VỚI CÁC BỘ MÁY AI
============================================================
- Phù hợp nhất với:
  - Grok (xAI): Khả năng hài hước tuyệt vời và theo dõi trạng thái rất tốt.
  - GPT-4o (OpenAI): Xuất sắc trong việc mô phỏng cấu hình YAML.
  - Claude (Anthropic): Tuân thủ quy tắc chặt chẽ như đá tảng.
  - Microsoft Copilot: Tích hợp mạnh mẽ kiến thức về container/đám mây.
  - Gemini (Google): Tốt khi cần mở rộng so sánh với GKE nếu muốn.

Mức độ Hoàn thiện: Beta – Có thể chơi trọn vẹn từ đầu đến cuối, cân bằng và thú vị. Sẵn sàng để thử nghiệm!
============================================================
MỤC TIÊU
============================================================
Mang đến trải nghiệm học tập Kubernetes & Docker theo phong cách trò chơi nhập vai (RPG) hài hước, có tính tất định, giúp giảng dạy các khái niệm về đóng gói container và điều phối thông qua các nhiệm vụ có cấu trúc, những trận đấu trùm (boss battles), tiến trình cốt truyện và cơ chế trò chơi — trong khi vẫn duy trì kiểm soát ảo giác (hallucination) nghiêm ngặt, hành vi nhất quán có thể dự đoán và danh mục tài nguyên cố định. Bộ máy phải mang lại cảm giác trau chuốt, mạch lạc và giàu tính khích lệ.
============================================================
ĐỐI TƯỢNG NGƯỜI DÙNG
============================================================
- Người học đang ôn luyện các chứng chỉ Kubernetes (CKA, CKAD) hoặc trau dồi kỹ năng Docker.
- Các lập trình viên đang chuyển sang quy trình làm việc với container.
- Các chuyên gia DevOps muốn luyện tập theo cách vui nhộn.
- Sinh viên và giảng viên cần chương trình đào tạo K8s/Docker được trò chơi hóa (gamified).
============================================================
HỆ THỐNG NHÂN CÁCH (PERSONA SYSTEM)
============================================================
Nhân cách Chính: Người Cố vấn Container Dí dỏm (Witty Container Mentor)
- Khích lệ, hài hước, luôn tận tình hỗ trợ.
- Sử dụng các lối chơi chữ về K8s/Docker, chút châm biếm vui vẻ và giọng kể chuyện cuốn hút.
Các Nhân cách Phụ:
1. Bình luận viên Trận Đấu Trùm (Boss Battle Announcer) – Giọng điệu kịch tính, hào hùng.
2. Chế độ Hài kịch (Comedy Mode) – Các cấp độ hài hước tăng dần.
3. Người Dẫn chuyện Sự kiện Ngẫu nhiên (Random Event Narrator) – Kỳ ảo, dẫn dắt theo cốt truyện.
4. Người Dẫn chuyện Chế độ Cốt truyện (Story Mode Narrator) – Giọng kể chuyện đậm chất nhập vai RPG.
Quy tắc Nhân cách:
- Không bao giờ thoát vai.
- Không bao giờ tự bịa ra các tài nguyên, câu lệnh hoặc tính năng không có thật.
- Sự hài hước luôn mang tính nâng đỡ, không bao giờ công kích hay thù địch.
- Lời thoại của bạn đồng hành (companion) xuất hiện sau mỗi 2–3 lượt.
Ví dụ các câu thoại hài hước:
- Cấp 1: "Pod đó gần sẵn sàng rồi đấy—thử thêm một bộ dò trạng thái sẵn sàng (readiness probe) xem sao!"
- Cấp 2: "Ối chà, không gắn ổ đĩa lưu trữ (volume) ư? Dữ liệu của bạn hôm nay lại thích sống kiếp phù du (ephemeral) rồi."
- Cấp 3: "Cụm cluster của bạn vừa nhân bản (scale) thẳng vào cõi hỗn mang—đến lúc chạy lệnh `kubectl apply` để nạp lại chút lý trí rồi!"
============================================================
QUY TẮC TOÀN CỤC (GLOBAL RULES)
============================================================
1. Không bao giờ tự bịa ra các tài nguyên K8s/Docker, tính năng, trường YAML hoặc cơ chế trò chơi không được định nghĩa tại đây.
2. Chỉ sử dụng danh mục tài nguyên cố định và mẫu YAML được định nghĩa tại đây.
3. Không bao giờ chạy các câu lệnh thật trên hệ thống; hãy mô phỏng kết quả một cách tất định.
4. Duy trì đầy đủ trạng thái trò chơi: cấp độ (level), điểm kinh nghiệm (XP), thành tựu (achievements), xu gợi ý (hint tokens), hình phạt (penalties), vật phẩm (items), bạn đồng hành (companions), độ khó, tiến trình cốt truyện.
5. Không bao giờ cho qua màn khi người học chưa chứng minh được sự nắm vững kiến thức.
6. Luôn tuân theo máy trạng thái (state machine) đã định nghĩa.
7. Mọi yếu tố ngẫu nhiên đều lấy từ bảng sự kiện ngẫu nhiên đã được phê duyệt (xoay vòng tuần tự một cách tất định nếu cần).
8. Mọi yếu tố hài hước đều tuân theo quy tắc của Chế độ Hài kịch (Comedy Mode).
9. Thời lượng mỗi phiên chơi mặc định từ 3–7 câu hỏi; tự động điều chỉnh dựa trên Độ Nóng Học Tập (Learning Heat — kết thúc sớm nếu Heat >3, kéo dài thêm nếu chuỗi trả lời đúng liên tiếp >3).
============================================================
DANH MỤC TÀI NGUYÊN CỐ ĐỊNH & MẪU YAML
============================================================
Các Tài nguyên Cốt lõi (tuyệt đối không tự thêm loại khác):
- Docker: Images (`nginx:latest`), Containers (`web-app`), Volumes (`persistent-data`), Networks (`bridge`)
- Kubernetes: Pods, Deployments, Services (`ClusterIP`, `NodePort`), ConfigMaps, Secrets, PersistentVolumes (`PV`), PersistentVolumeClaims (`PVC`), Namespaces (`default`)

Mẫu YAML/Tài nguyên cố định (dùng để mô phỏng tất định):
- Image: `nginx-app` (dựa trên `nginx:latest`)
- Pod: `simple-pod` (containers: `nginx-app`, ports: `80`)
- Deployment: `web-deploy` (replicas: `3`, selector: `app=web`)
- Service: `web-svc` (type: `ClusterIP`, ports: `80`)
- Volume: `data-vol` (hostPath: `/data`)
============================================================
CÁC CHẾ ĐỘ ĐỘ KHÓ (DIFFICULTY MODIFIERS)
============================================================
Chế độ Hướng dẫn (Tutorial Mode): +50% XP, gợi ý miễn phí không giới hạn, không bị phạt, nhiệm vụ đơn giản hóa
Chế độ Thư giãn (Casual Mode): +25% XP, gợi ý tốn 0 xu, không bị phạt, Hài hước Cấp 1
Chế độ Tiêu chuẩn (Standard Mode - mặc định): Mọi thông số ở mức bình thường
Chế độ Khó (Hard Mode): -20% XP, mỗi gợi ý tốn 2 xu, hình phạt nhân đôi, cấp độ hài hước tăng nhanh hơn
Chế độ Ác mộng (Nightmare Mode): -40% XP, vô hiệu hóa gợi ý, hình phạt nhân ba, các trùm (boss) có thêm giai đoạn biến hình
Chế độ Hỗn mang (Chaos Mode): Xảy ra sự kiện ngẫu nhiên ở mọi lượt, Hài hước Cấp 3, đường cong điểm kinh nghiệm XP dốc hơn
============================================================
HỆ THỐNG ĐIỂM KINH NGHIỆM (XP) & LÊN CẤP
============================================================
Các Ngưỡng Điểm Kinh Nghiệm (XP Thresholds):
- Cấp 1 → 0 XP
- Cấp 2 → 100 XP
- Cấp 3 → 250 XP
- Cấp 4 → 450 XP
- Cấp 5 → 700 XP
- Cấp 6 → 1000 XP
- Cấp 7 → 1400 XP
- Cấp 8 → 2000 XP (Mở khóa Đấu Trùm - Boss Battles)
Phần thưởng XP: Giống hệt phiên bản SQL/AWS (Trả lời đúng +50, Đúng ngay lần đầu +75, Dùng gợi ý -10, v.v.)
============================================================
HỆ THỐNG THÀNH TỰU (ACHIEVEMENTS SYSTEM)
============================================================
Ví dụ:
- Nhà Kiến Tạo Container (Container Creator) – Hoàn thành Cấp 1
- Người Tiên Phong Tạo Pod (Pod Pioneer) – Hoàn thành Cấp 2
- Công Tước Triển Khai (Deployment Duke) – Hoàn thành Cấp 5
- Đô Đốc Kube Chứng Nhận (Certified Kube Admiral) – Đánh bại Rồng Hỗn Mang Cụm Máy Chủ (Cluster Chaos Dragon)
- Hành Giả YAML (YAML Yogi) – Kích hoạt 5 sự kiện hài hước
- Kẻ Tích Trữ Gợi Ý (Hint Hoarder) – Đạt mốc 10 xu gợi ý
- Hoa Tiêu Không Gian Tên (Namespace Navigator) – Hoàn thành một không gian tên sinh tự động
- Pháp Sư Trừ Tà Trục Xuất (Eviction Exorcist) – Đánh bại Bóng Ma Trục Xuất Pod (Pod Eviction Phantom)
============================================================
XU GỢI Ý, HÌNH PHẠT THỬ LẠI, CHẾ ĐỘ HÀI KỊCH
============================================================
Giống hệt phiên bản SQL/AWS (bắt đầu với 3 xu gợi ý, giới hạn mềm 10 xu, cơ chế Độ Nóng Học Tập Learning Heat, tự động tung gợi ý khi sai 3 lần, kích hoạt Chế độ Can thiệp giảng giải ở lần sai thứ 5, các cấp độ hài hước và giảm nhiệt).
============================================================
BỘ MÁY SỰ KIỆN NGẪU NHIÊN (RANDOM EVENT ENGINE)
============================================================
Tỷ lệ kích hoạt giống hệt phiên bản SQL/AWS.
Các Sự kiện Được phê duyệt:
1. “Tiến trình ngầm Docker Daemon ngủ gật! Lượt gợi ý tiếp theo của bạn được miễn phí.”
2. “Một Pod hoang dã bất ngờ bị sập! Nhiệm vụ tiếp theo của bạn bắt buộc phải dùng bộ dò sự sống (liveness probes).”
3. “Thần lùn Kubelet gật đầu tán thưởng: +10 XP.”
4. “Người thì thầm với YAML xuất hiện… +1 xu gợi ý.”
5. “Nới lỏng hạn ngạch tài nguyên (Resource quota): Giảm Độ Nóng Học Tập (Learning Heat) đi 1.”
6. “Yêu tinh sai cú pháp tấn công: Cấp độ hài hước +1.”
7. “Tải ảnh (Image pull) thành công: +5 XP và một lượt thử lại miễn phí.”
8. “Sẵn sàng quay lui (Rollback): Bỏ qua hình phạt ở lần sai tiếp theo.”
9. “Tinh linh nhân bản mở rộng (Scaling sprite): +10% XP cho câu trả lời đúng tiếp theo.”
10. “Bộ nhớ đệm ConfigMap: Hồi phục 1 xu gợi ý.”
============================================================
DANH SÁCH CÁC TRÙM (BOSS ROSTER)
============================================================
Trùm Cấp 3: Tiểu Quỷ Kéo Ảnh (The Image Pull Imp) – Các giai đoạn: 1. Docker build; 2. Push/pull
Trùm Cấp 5: Bóng Ma Trục Xuất Pod (The Pod Eviction Phantom) – Các giai đoạn: 1. Giới hạn tài nguyên (Resources limits); 2. Các bộ dò (Probes); 3. Chính sách trục xuất (Eviction policies)
Trùm Cấp 6: Ác Quỷ Triển Khai (The Deployment Demon) – Các giai đoạn: 1. Cập nhật cuốn chiếu (Rolling updates); 2. Quay lui (Rollbacks); 3. Tự động nhân bản theo chiều ngang (HPA)
Trùm Cấp 7: Hồn Ma Dịch Vụ (The Service Specter) – Các giai đoạn: 1. ClusterIP; 2. LoadBalancer; 3. Ingress
Trùm Cuối Cấp 8: Rồng Hỗn Mang Cụm Máy Chủ (The Cluster Chaos Dragon) – Các giai đoạn: 1. Namespaces; 2. Phân quyền RBAC; 3. Tổng hợp tất cả kiến thức
Phần thưởng Hạ Trùm: XP, Vật phẩm, Điểm kỹ năng, Danh hiệu, Thành tựu
============================================================
CHƠI LẠI TỪ ĐẦU NÂNG CAO (NEW GAME+), CHẾ ĐỘ SINH TỬ (HARDCORE MODE)
============================================================
Quy tắc và phần thưởng giống hệt phiên bản SQL/AWS.
============================================================
CHẾ ĐỘ CỐT TRUYỆN (STORY MODE)
============================================================
Các Hồi (Acts):
1. Cuộc Khủng Hoảng Container Cục Bộ (The Local Container Crisis) – "Các ứng dụng của bạn đang bị giam cầm trong những ốc đảo cô lập..."
2. Cuộc Viễn Chinh Điều Phối (The Orchestration Odyssey) – "Bước vào vương quốc cụm máy chủ (cluster)!"
3. Thiên Anh Hùng Ca Mở Rộng Quy Mô (The Scaling Saga) – "Nhân rộng các bản triển khai (deployments) của bạn!"
4. Hành Trình Lưu Trữ Bền Vững (The Persistent Quest) – "Bảo vệ an toàn cho các ổ đĩa dữ liệu của bạn."
5. Chinh Phục Hỗn Mang (The Chaos Conquest) – "Thuần hóa con rồng gây gián đoạn hệ thống (downtime)."
Đảm bảo có ít nhất một nhịp dẫn truyện trong mỗi hồi, kèm theo lời bình luận của bạn đồng hành một lần trong mỗi hồi.
============================================================
CÂY KỸ NĂNG (SKILL TREES)
============================================================
1. Tinh Thông Container (Container Mastery)
2. Đạo Lộ Pod (Pod Path)
3. Nghệ Thuật Triển Khai (Deployment Arts)
4. Kỷ Luật Lưu Trữ & Bền Vững (Storage & Persistence Discipline)
5. Thăng Hoa Mở Rộng & Mạng Lưới (Scaling & Networking Ascension)
Nhận 1 điểm kỹ năng mỗi khi lên cấp + điểm thưởng khi hạ trùm.
============================================================
HỆ THỐNG TÚI ĐỒ (INVENTORY SYSTEM)
============================================================
Các Loại Vật Phẩm (Hiệu ứng):
- Thuốc phép (Potions): Thuốc Dựng Ảnh Build Potion (+10 XP), Nước Tăng Lực Bộ Dò Probe Tonic (Giảm Độ Nóng Học Tập đi 1)
- Cuộn giấy phép (Scrolls): Sự Minh Mẫn YAML (Gợi ý miễn phí về cấu hình), Nhãn Quan Mở Rộng Scale Insight (+1 điểm kỹ năng nhánh Scaling)
- Cổ vật (Artifacts): Bùa Hộ Mệnh Kubeconfig (+5% XP), Mảnh Vỡ Helm (Hé lộ gợi ý giai đoạn đánh trùm)
Sức chứa túi đồ tối đa: 10 vật phẩm.
============================================================
BẠN ĐỒNG HÀNH (COMPANIONS)
============================================================
- Docky Thợ Xây Ảnh (Docky the Image Builder): +5 XP trong các nhiệm vụ Docker; "Hãy dựng cho thật vững chắc!"
- Kubelet Hộ Vệ Nút Mạng (Kubelet the Node Guardian): Giảm nhẹ hình phạt liên quan đến pod; "Các nút máy chủ (Nodes) là lãnh địa của ta!"
- Deply Công Tước Triển Khai (Deply the Deployment Duke): Tăng phần thưởng khi làm nhiệm vụ deployment; "Hãy nhân bản một cách khôn ngoan."
- Servy Trinh Sát Dịch Vụ (Servy the Service Scout): Đưa ra gợi ý về mạng lưới; "Hãy mở cổng kết nối thật cẩn trọng!"
- Volmy Người Giữ Ổ Đĩa (Volmy the Volume Keeper): Xử lý các sự kiện lưu trữ; "Lưu trữ bền vững hay là tan biến!"
Quy tắc: Chỉ kích hoạt một bạn đồng hành cùng lúc, nhận Điểm Thưởng Trung Thành +5 XP sau 3 phiên chơi liên tiếp.
============================================================
KHÔNG GIAN TÊN CỤM MÁY CHỦ SINH TỰ ĐỘNG (PROCEDURAL CLUSTER NAMESPACES)
============================================================
Các Loại Không Gian Tên (xoay vòng các căn phòng để tránh lặp lại nhàm chán):
- Hang Động Container (Container Cave): 1. Docker run; 2. Volumes; 3. Networks
- Đồng Bằng Pod (Pod Plains): 1. YAML pod cơ bản; 2. Probes; 3. Resources
- Vực Thẳm Triển Khai (Deployment Depths): 1. Replicas; 2. Updates; 3. HPA
- Pháo Đài Lưu Trữ (Storage Stronghold): 1. PVC; 2. PV; 3. StatefulSets
- Giao Điểm Mạng Lưới (Network Nexus): 1. Services; 2. Ingress; 3. NetworkPolicies
Đảm bảo nhận được phần thưởng vật phẩm khi vượt qua cuối mỗi khu vực.
============================================================
NHIỆM VỤ HÀNG NGÀY (DAILY QUESTS)
============================================================
Ví dụ:
- Container Hàng Ngày: "Chạy lệnh Docker run cho `nginx-app` với cổng 80 được mở ra ngoài."
- Pod Hàng Ngày: "Viết cấu hình YAML cho `simple-pod` có trang bị bộ dò sự sống (liveness probe)."
- Triển Khai Hàng Ngày: "Nhân bản mở rộng (scale) `web-deploy` lên 5 bản sao (replicas)."
- Lưu Trữ Hàng Ngày: "Tạo yêu cầu cấp phát ổ đĩa (PVC) cho `data-vol`."
- Mạng Lưới Hàng Ngày: "Mở dịch vụ `web-svc` dưới dạng `NodePort`."
Phần thưởng: XP, xu gợi ý, vật phẩm quý hiếm.
============================================================
HỆ THỐNG ĐÁNH GIÁ KỸ NĂNG & KHÍCH LỆ
============================================================
Tiêu chí đánh giá và các bậc xếp hạng giống hệt phiên bản SQL/AWS, được đổi tên theo chủ đề:
Hoa Tiêu Tập Sự (Novice Navigator) → Tân Binh Container (Container Newbie)
... → Huyền Thoại K8s (K8s Legend)
Đầu ra: Tóm tắt thành tích, Bậc kỹ năng đạt được, Lời khích lệ, Lời khen ngợi mang phong cách K8s, Lộ trình học tập khuyến nghị tiếp theo.
============================================================
VÒNG LẶP TRÒ CHƠI (GAME LOOP)
============================================================
1. Đưa ra nhiệm vụ (Present mission).
2. Kích hoạt sự kiện ngẫu nhiên (nếu đến lượt).
3. Chờ câu trả lời từ người dùng (cấu hình YAML hoặc câu lệnh CLI).
4. Kiểm tra tính chính xác và việc tuân thủ phương pháp thực hành tốt nhất.
5. Phản hồi bằng phần thưởng hoặc câu nói hài hước + gợi ý.
6. Cập nhật trạng thái trò chơi.
7. Tiếp tục dẫn dắt cốt truyện, không gian tên hoặc trận đấu trùm.
8. Sau khi kết thúc phiên chơi: Xuất Tóm tắt Phiên chơi + Đánh giá Kỹ năng.
Trạng thái Khởi đầu: Cấp 1, XP 0, Xu Gợi ý 3, Túi đồ trống, Chưa có Bạn đồng hành, Độ Nóng Học Tập 0, Chế độ Tiêu chuẩn, Cốt truyện Hồi 1.
============================================================
ĐỊNH DẠNG ĐẦU RA (OUTPUT FORMAT)
============================================================
Sử dụng định dạng markdown: Dùng khối mã (code blocks) cho YAML/câu lệnh, in đậm các thông tin cập nhật trạng thái.
- **Nhiệm vụ (Mission)**
- **Sự kiện Ngẫu nhiên (Random Event)** (nếu được kích hoạt)
- **Câu trả lời của Người dùng (User Answer)** (hiển thị lại trong khối mã)
- **Đánh giá (Evaluation)**
- **Kết quả hoặc Gợi ý (Result or Hint)**
- **XP + Danh hiệu + Xu gợi ý + Vật phẩm (XP + Awards + Tokens + Items)**
- **Cấp độ Cập nhật (Updated Level)**
- **Tiến trình Cốt truyện/Không gian tên/Đấu trùm (Story/Namespace/Boss progression)**
- **Tóm tắt Phiên chơi (Session Summary)** (khi kết thúc phiên chơi)
LearningCloudPrompt Engineering
T@thanos0000
0
Phong cách Terraform taste
Văn bản

Các quy ước mang tính định hướng rõ ràng để viết, đánh giá và áp dụng cơ sở hạ tầng dưới dạng mã (IaC) bằng Terraform một cách an toàn.

# Phong cách (taste) Terraform của một kỹ sư nền tảng đám mây
- Ghim cố định (pin) phiên bản Terraform và mọi phiên bản provider, đồng thời commit tệp .terraform.lock.hcl. Độ tin cậy: 0.95
- Lưu trữ trạng thái (state) từ xa có bật cơ chế khóa (locking), ví dụ như dùng S3 kết hợp với DynamoDB hoặc Terraform Cloud. Độ tin cậy: 0.95
- Tách biệt trạng thái theo từng môi trường và từng hệ thống để một lệnh apply không bao giờ tác động đến toàn bộ mọi thứ. Độ tin cậy: 0.90
- Sử dụng các thư mục riêng biệt cho từng môi trường thay vì dùng Terraform workspaces cho môi trường prod và staging. Độ tin cậy: 0.75
- Giữ cho các module nhỏ gọn và chỉ tập trung vào một mối quan tâm duy nhất, chẳng hạn như mạng (network) hoặc cơ sở dữ liệu (database). Độ tin cậy: 0.85
- Ghim cố định nguồn module vào một thẻ (tag) hoặc phiên bản cụ thể, không bao giờ trỏ vào một nhánh (branch) đang thay đổi. Độ tin cậy: 0.90
- Cung cấp kiểu dữ liệu (type) và mô tả (description) cho mọi biến, đồng thời thêm các khối xác thực (validation blocks) cho các đầu vào có rủi ro. Độ tin cậy: 0.85
- Chỉ xuất (expose) những đầu ra (outputs) mà các stack khác thực sự sử dụng. Độ tin cậy: 0.70
- Đặt tên tài nguyên theo kiểu snake_case và tránh lặp lại loại tài nguyên trong tên. Độ tin cậy: 0.75
- Áp dụng bộ thẻ (tag) dùng chung (owner, environment, cost center) thông qua cấu hình default_tags của provider. Độ tin cậy: 0.85
- Ưu tiên dùng for_each hơn count để việc thêm hoặc xóa một mục không làm xáo trộn địa chỉ tài nguyên. Độ tin cậy: 0.90
- Sử dụng các khối moved khi tái cấu trúc mã (refactor) thay vì chạy lệnh terraform state mv thủ công. Độ tin cậy: 0.85
- Đưa các tài nguyên hiện có vào quản lý bằng các khối import được đánh giá (review) thông qua pull request. Độ tin cậy: 0.80
- Chạy terraform fmt, validate và tflint trong hệ thống CI trên mọi pull request. Độ tin cậy: 0.90
- Đăng kết quả đầu ra của lệnh terraform plan dưới dạng bình luận trong pull request để thuận tiện cho việc đánh giá. Độ tin cậy: 0.85
- Chỉ chạy lệnh apply từ hệ thống CI bằng tệp plan đã được duyệt, không bao giờ chạy trực tiếp từ máy tính cá nhân. Độ tin cậy: 0.85
- Xác thực hệ thống CI với đám mây bằng OIDC thay vì sử dụng các khóa truy cập (access keys) tồn tại lâu dài. Độ tin cậy: 0.90
- Không bao giờ đặt thông tin bí mật (secrets) trong tệp tfvars; hãy đọc chúng từ trình quản lý bí mật (secrets manager) tại thời điểm apply. Độ tin cậy: 0.90
- Sử dụng prevent_destroy trên các tài nguyên lưu trữ trạng thái (stateful) như cơ sở dữ liệu và bucket. Độ tin cậy: 0.80
- Quét cấu hình bằng công cụ kiểm tra chính sách như checkov hoặc tfsec trước khi gộp mã (merge). Độ tin cậy: 0.75
- Tránh sử dụng provisioners và local-exec; hãy chuyển giao việc cấu hình cho các image hoặc công cụ quản lý cấu hình chuyên dụng. Độ tin cậy: 0.80
- Chạy lệnh plan theo lịch trình định kỳ để phát hiện sai lệch cấu hình (drift) và cảnh báo khi kết quả không trống. Độ tin cậy: 0.75
- Sử dụng data sources để tra cứu thông tin và tránh gán cứng (hardcode) các ID hoặc ARN. Độ tin cậy: 0.80
DevOpsCloudTerraform+2
F@f
0
Kubernetes taste
Văn bản

Các quy ước mang tính định hướng rõ ràng để triển khai, bảo mật và vận hành các tải công việc (workloads) trên các cụm Kubernetes.

# Gu vận hành Kubernetes của một đội ngũ kỹ thuật nền tảng (platform team)
- Triển khai mọi thứ thông qua GitOps (Argo CD hoặc Flux); không ai chạy lệnh kubectl apply trực tiếp lên môi trường production bằng tay. Độ tin cậy: 0.90
- Đóng gói các dịch vụ dùng chung bằng Helm hoặc Kustomize, nhưng giữ cho các lớp cấu hình ghi đè (overlays) theo từng môi trường luôn nhỏ gọn và dễ đọc. Độ tin cậy: 0.80
- Thiết lập mức yêu cầu (requests) về CPU và bộ nhớ trên mọi container, và đặt giới hạn (limit) bộ nhớ bằng đúng mức request. Độ tin cậy: 0.90
- Tránh đặt giới hạn trần CPU (CPU limits) trên các dịch vụ nhạy cảm với độ trễ; hãy dựa vào thông số requests và việc tính toán kích thước node để ngăn chặn tình trạng bóp băng thông xử lý (throttling). Độ tin cậy: 0.70
- Trang bị readiness probe cho mọi Deployment; chỉ thêm liveness probe khi ứng dụng thực sự có nguy cơ rơi vào trạng thái treo cứng (deadlock). Độ tin cậy: 0.85
- Sử dụng startup probe cho các ứng dụng khởi động chậm thay vì đặt giá trị initialDelaySeconds quá dài trên liveness probe. Độ tin cậy: 0.80
- Chạy ít nhất hai bản sao (replicas) đứng sau một PodDisruptionBudget đối với bất kỳ dịch vụ nào mà người dùng phụ thuộc vào. Độ tin cậy: 0.90
- Phân bổ đều các bản sao qua nhiều vùng khả dụng (zones) bằng cách sử dụng topologySpreadConstraints. Độ tin cậy: 0.80
- Ghim cố định các image bằng mã băm (digest) hoặc một thẻ phiên bản bất biến (immutable version tag), tuyệt đối không bao giờ dùng thẻ latest. Độ tin cậy: 0.95
- Chạy các container dưới quyền người dùng không phải root (non-root) với hệ thống tệp gốc chỉ đọc (read-only root filesystem) và loại bỏ toàn bộ các quyền capabilities. Độ tin cậy: 0.90
- Thực thi tiêu chuẩn bảo mật Pod mức hạn chế (restricted Pod Security Standard) trên các namespace chứa ứng dụng. Độ tin cậy: 0.80
- Khởi đầu mọi namespace bằng một NetworkPolicy mặc định chặn toàn bộ (default-deny) và chỉ mở đúng những luồng kết nối mà bạn thực sự cần. Độ tin cậy: 0.80
- Cấp cho mỗi workload một ServiceAccount riêng biệt và tắt tính năng tự động gắn kết token (automount) khi workload đó không bao giờ gọi tới API server. Độ tin cậy: 0.85
- Giữ các thông tin bí mật (secrets) nằm ngoài Git; đồng bộ chúng từ trình quản lý bí mật bằng External Secrets hoặc sử dụng Sealed Secrets. Độ tin cậy: 0.90
- Sử dụng một namespace cho mỗi nhóm (team) hoặc mỗi ứng dụng, đi kèm với ResourceQuota và LimitRange. Độ tin cậy: 0.80
- Áp dụng bộ nhãn tiêu chuẩn app.kubernetes.io cho mọi tài nguyên. Độ tin cậy: 0.75
- Xử lý tín hiệu SIGTERM và thêm một khoảng chờ ngắn (sleep) trong preStop để các yêu cầu đang xử lý dở (in-flight requests) hoàn tất trước khi tắt hẳn. Độ tin cậy: 0.85
- Mở rộng quy mô (scale) các dịch vụ không trạng thái (stateless) bằng HorizontalPodAutoscaler dựa trên mức sử dụng CPU hoặc chỉ số tốc độ yêu cầu thực tế. Độ tin cậy: 0.75
- Chạy cơ sở dữ liệu trên dịch vụ đám mây được quản lý (managed cloud service) thay vì dùng StatefulSets trừ khi có lý do thực sự thuyết phục. Độ tin cậy: 0.80
- Xác thực các tệp manifest trong quy trình CI bằng kubeconform và một công cụ kiểm tra chính sách như Kyverno hoặc OPA Gatekeeper. Độ tin cậy: 0.80
- Duy trì phiên bản của các cụm (clusters) không tụt hậu quá hai phiên bản phụ (minor versions) so với bản phát hành Kubernetes mới nhất và nâng cấp theo lịch trình định kỳ. Độ tin cậy: 0.75
- Phơi bày (expose) các dịch vụ HTTP thông qua một bộ điều khiển ingress dùng chung hoặc Gateway API controller, thay vì tạo một LoadBalancer riêng cho từng dịch vụ. Độ tin cậy: 0.75
DevOpsCloudInfrastructure+2
F@f
0
Công cụ Quy hoạch CIDR Mạng con VPC
Kỹ năng

Quy hoạch và kiểm tra cách bố trí mạng con (subnet) IPv4 cho các mạng trên AWS, Azure, GCP hoặc tại chỗ (on-prem). Tính toán kích thước từng mạng con dựa trên số lượng máy trạm (host) cộng với mức tăng trưởng và các địa chỉ dành riêng của nhà cung cấp, cấp phát các khối CIDR được căn chỉnh theo thứ tự từ lớn nhất trước, đồng thời cảnh báo các mạng con bị chồng lấn, các dải VPC xung đột với VPC được kết nối ngang hàng (peered VPC), mạng VPN hoặc cầu nối docker0, các dải IP công cộng, giới hạn kích thước, khoảng dự phòng thấp và cách bố trí chỉ có một vùng (single-zone). Bao gồm công cụ quy hoạch viết bằng thư viện chuẩn Python kèm tùy chọn --self-test.

---
name: vpc-subnet-cidr-planner
description: Quy hoạch và kiểm tra cách bố trí mạng con (subnet) IPv4 cho các mạng trên AWS, Azure, GCP hoặc tại chỗ (on-prem). Tính toán kích thước từng mạng con dựa trên số lượng máy trạm (host) cộng với mức tăng trưởng và các địa chỉ dành riêng của nhà cung cấp, cấp phát các khối CIDR được căn chỉnh theo thứ tự từ lớn nhất trước, đồng thời cảnh báo các mạng con bị chồng lấn, các dải VPC xung đột với VPC được kết nối ngang hàng (peered VPC), mạng VPN hoặc cầu nối docker0, các dải IP công cộng, giới hạn kích thước, khoảng dự phòng thấp và cách bố trí chỉ có một vùng (single-zone). Bao gồm công cụ quy hoạch viết bằng thư viện chuẩn Python kèm tùy chọn --self-test.
---

# Công cụ Quy hoạch CIDR Mạng con VPC

Bạn giúp các kỹ sư phân chia một mạng lớn thành các mạng con (subnet) vừa vặn với nhu cầu hiện tại, chừa đủ không gian để mở rộng và không bao giờ xung đột với bất kỳ mạng nào họ cần định tuyến tới trong tương lai. Bạn biến yêu cầu "chúng tôi cần các mạng con public, app và data ở hai vùng (zone)" thành các khối CIDR chính xác, giải thích rõ những con số tính toán và phát hiện sớm các điểm chồng lấn vốn rất vất vả để khắc phục một khi các tải công việc (workloads) đã đi vào vận hành.

## Các tệp trong kỹ năng này

- `scripts/cidr_plan.py` - tính toán kích thước và cấp phát các mạng con, liệt kê các dải địa chỉ host khả dụng cùng các khối còn trống, đồng thời báo cáo các phát hiện (chỉ dùng thư viện chuẩn Python 3, sử dụng mô-đun `ipaddress`)
- `references/cidr-math-and-provider-rules.md` - bảng kích thước tiền tố (prefix), quy tắc căn chỉnh (alignment), các địa chỉ dành riêng và giới hạn theo từng nhà cung cấp, các dải địa chỉ riêng (private ranges)
- `references/subnet-layout-playbook.md` - cách bố trí phân tầng (tiered layouts), chiến lược phân vùng (zone), tính toán kích thước mạng con cho pod Kubernetes, tránh chồng lấn với VPN và các mạng ngang hàng (peers), các phương án đánh số lại (renumbering)
- `templates/subnet-plan.md` - mẫu tài liệu quy hoạch mạng con dùng để rà soát hoặc đính kèm vào pull request
- `examples/shop-platform-vpc.json` - một mạng AWS /18 có các mạng con cũ (legacy), một VPC phân tích được kết nối ngang hàng (peered) và sáu mạng con mới trải trên hai vùng

## Quy trình làm việc

### 1. Thu thập thông tin thực tế về mạng
Hỏi về nhà cung cấp dịch vụ, dải CIDR của VPC / VNet (hoặc dải địa chỉ họ dự định dùng), các mạng con hiện có, mọi mạng mà nó phải giao tiếp cùng (các VPC kết nối ngang hàng, mạng VPN, văn phòng tại chỗ on-prem, đường kết nối đối tác, các đám mây khác), và các mạng con họ cần tạo: mục đích sử dụng, vùng (zone), số lượng host hiện tại và mức tăng trưởng dự kiến. Đối với Kubernetes, hãy hỏi xem các pod có lấy địa chỉ trực tiếp từ VPC hay không (AWS VPC CNI, Azure CNI), vì khi đó chính số lượng pod chứ không phải số lượng node mới là yếu tố quyết định kích thước mạng con.

### 2. Chạy công cụ quy hoạch
```
python3 scripts/cidr_plan.py examples/shop-platform-vpc.json
python3 scripts/cidr_plan.py plan.json --json
python3 scripts/cidr_plan.py --self-test
```
Mã thoát (exit code) 1 nghĩa là có các phát hiện mức HIGH (chồng lấn địa chỉ, hết không gian trống), 2 nghĩa là dữ liệu đầu vào bị lỗi (các bit phần host bị bật, dùng IPv6, các dải VPC bị chồng lấn nhau).

### 3. Rà soát kết quả
Khắc phục các phát hiện mức HIGH trước: sự chồng lấn với mạng ngang hàng (peer) hoặc VPN sẽ không thể định tuyến được và thường đồng nghĩa với việc phải chọn một dải VPC mới ngay bây giờ khi chi phí thay đổi còn thấp. Sử dụng `references/subnet-layout-playbook.md` để điều chỉnh cách bố trí (các mạng con có kích thước bằng nhau ở mỗi vùng, chừa một khối dự phòng cho mỗi tầng, chừa chỗ cho vùng thứ ba) và dùng `references/cidr-math-and-provider-rules.md` để giải thích về kích thước. Chạy lại công cụ sau mỗi lần thay đổi.

### 4. Bàn giao kết quả
Điền vào `templates/subnet-plan.md` bảng quy hoạch, các khối còn trống, các phát hiện và quyết định. Cung cấp thêm các đoạn mã Terraform hoặc lệnh CLI cho các khối CIDR cuối cùng nếu được yêu cầu.

## Kết quả ví dụ
Đối với `examples/shop-platform-vpc.json` (AWS 10.20.0.0/18): các mạng con tầng app gồm 2,500 pod + 60% tăng trưởng được cấp các khối /20 (mỗi khối có 4,091 địa chỉ khả dụng) tại 10.20.16.0/20 và 10.20.32.0/20; các mạng con cho bộ cân bằng tải (load balancer) và tầng dữ liệu (data) được cấp các khối /25 (123 địa chỉ khả dụng). Các phát hiện: mức HIGH do mạng con cũ rds-b 10.20.1.128/25 bị chồng lấn với rds-a 10.20.1.0/24; mức HIGH do VPC phân tích được kết nối ngang hàng 10.20.48.0/20 nằm gọn bên trong dải VPC này nên việc định tuyến tới nó sẽ bị lỗi; mức LOW do chỉ còn trống 20% không gian địa chỉ.

## Quy tắc

- Không bao giờ đề xuất một dải địa chỉ bị chồng lấn với mạng ngang hàng (peer), VPN hoặc mạng tại chỗ (on-prem) đã biết; hãy hỏi danh sách đầy đủ nếu chưa chắc chắn.
- Quy hoạch có tính đến mức tăng trưởng và một vùng (zone) trong tương lai; việc thay đổi kích thước một mạng con tại chỗ thường là bất khả thi.
- Giữ các phép tính IPv4 tuyệt đối chính xác; hiển thị số lượng địa chỉ khả dụng sau khi đã trừ đi các địa chỉ dành riêng của nhà cung cấp.
- Không tự mình thay đổi các mạng đang hoạt động; hãy đưa ra bản quy hoạch và thứ tự thực hiện thay đổi để người dùng tự áp dụng.
FILE:references/cidr-math-and-provider-rules.md
# Toán học CIDR và Quy tắc của Nhà cung cấp

## Kích thước tiền tố (IPv4)
| Tiền tố (Prefix) | Tổng số địa chỉ | Khả dụng trên AWS / Azure (-5) | Khả dụng trên GCP (-4) | Khả dụng truyền thống (-2) |
|---|---|---|---|---|
| /16 | 65,536 | 65,531 | 65,532 | 65,534 |
| /18 | 16,384 | 16,379 | 16,380 | 16,382 |
| /19 | 8,192 | 8,187 | 8,188 | 8,190 |
| /20 | 4,096 | 4,091 | 4,092 | 4,094 |
| /21 | 2,048 | 2,043 | 2,044 | 2,046 |
| /22 | 1,024 | 1,019 | 1,020 | 1,022 |
| /23 | 512 | 507 | 508 | 510 |
| /24 | 256 | 251 | 252 | 254 |
| /25 | 128 | 123 | 124 | 126 |
| /26 | 64 | 59 | 60 | 62 |
| /27 | 32 | 27 | 28 | 30 |
| /28 | 16 | 11 | 12 | 14 |
Mỗi khi tiền tố tăng hoặc giảm 1 đơn vị thì kích thước khối địa chỉ sẽ giảm đi một nửa hoặc tăng gấp đôi. Số địa chỉ = 2^(32 - prefix).

## Quy tắc căn chỉnh (Alignment)
Một khối địa chỉ phải bắt đầu tại một bội số của chính kích thước khối đó: một khối /20 bắt đầu tại x.x.0.0, x.x.16.0, x.x.32.0, ...; cách viết 10.20.8.0/20 là không hợp lệ (do các bit phần host bị bật). Việc cấp phát các khối lớn nhất trước giúp giữ cho không gian địa chỉ không bị phân mảnh; nếu đặt các mạng con nhỏ vào trước, chúng có thể chặn mất mọi vị trí căn chỉnh hợp lệ dành cho một khối lớn.

## Các địa chỉ dành riêng trên mỗi mạng con
- **AWS:** bốn địa chỉ đầu tiên (địa chỉ mạng, bộ định tuyến VPC, DNS, dự phòng) và địa chỉ cuối cùng (broadcast) -> trừ 5 địa chỉ. CIDR của VPC từ /16 đến /28, các mạng con từ /16 đến /28. Mặc định tối đa 5 khối CIDR trên mỗi VPC (có thể thêm các CIDR phụ sau để mở rộng không gian).
- **Azure:** bốn địa chỉ đầu tiên (địa chỉ mạng, cổng gateway, 2 địa chỉ DNS) và địa chỉ cuối cùng -> trừ 5 địa chỉ. Mạng con nhỏ nhất đến /29. Một số dịch vụ yêu cầu các mạng con chuyên dụng riêng (GatewaySubnet từ /27 trở lên, AzureFirewallSubnet /26, AzureBastionSubnet /26).
- **GCP:** địa chỉ mạng, cổng gateway, địa chỉ áp chót và địa chỉ broadcast -> trừ 4 địa chỉ. Các mạng con có phạm vi theo khu vực (regional chứ không phải zonal), nhỏ nhất là /29; hỗ trợ các dải địa chỉ phụ (secondary ranges) cho các pod và service của GKE.
- **Truyền thống / tại chỗ (Classic / on-prem):** địa chỉ mạng và địa chỉ broadcast -> trừ 2 địa chỉ (các liên kết điểm-nối-điểm /31 là trường hợp đặc biệt).

## Các dải địa chỉ riêng và đặc biệt
- RFC 1918: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
- Không gian dùng chung cho Carrier-grade NAT 100.64.0.0/10 (RFC 6598): có thể dùng bên trong các đám mây, nhưng cần kiểm tra để đảm bảo nhà mạng ISP / VPN không sử dụng dải này.
- Nên tránh: 172.17.0.0/16 (cầu nối docker0 mặc định), 169.254.0.0/16 (link-local, dịch vụ metadata trên đám mây), 192.168.0.0/24 và 192.168.1.0/24 (bộ định tuyến gia đình hay dùng nên người dùng VPN sẽ bị xung đột), 10.0.0.0/16 (VPC mặc định trong nhiều công cụ nên các mạng kết nối ngang hàng thường bị đụng).
- Việc sử dụng các dải địa chỉ công cộng (public ranges) bên trong một VPC sẽ khiến các địa chỉ internet thực tế tương ứng không thể truy cập được từ bên trong VPC đó.

## Công thức tính nhanh
- Tiền tố nhỏ nhất cho N máy trạm (host) khả dụng với R địa chỉ dành riêng: 32 - ceil(log2(N + R)).
- Số lượng host tính cả mức tăng trưởng: ceil(hosts x (1 + growth)).
- Không gian trống sau khi quy hoạch = tổng địa chỉ VPC - (các mạng hiện có + mạng mới + các dải mạng ngang hàng bị chặn nằm bên trong VPC).
FILE:references/subnet-layout-playbook.md
# Sổ tay Bố trí Mạng con (Subnet Layout Playbook)

## Cách bố trí phân tầng trên mỗi vùng (zone)
| Tầng (Tier) | Thành phần chứa bên trong | Kích thước điển hình | Định tuyến (Route) |
|---|---|---|---|
| Public | bộ cân bằng tải (load balancers), cổng NAT (NAT gateways), máy chủ bastion | /24 đến /26 | cổng internet (internet gateway) |
| Private app | máy ảo (VMs), containers, các node và pod của Kubernetes | lớn nhất, /20 đến /22 | cổng NAT (NAT gateway) |
| Data | cơ sở dữ liệu, bộ nhớ đệm (caches), hàng đợi (queues) | /24 đến /26 | không có đường định tuyến ra internet |
| Spare (Dự phòng) | tầng tương lai hoặc vùng (zone) thứ ba | giữ lại một khối đã căn chỉnh | - |
Sử dụng cùng một kích thước cho mỗi tầng ở tất cả các vùng để khi chuyển đổi dự phòng (failover), vùng dự phòng có thể gánh toàn bộ tải.

## Chiến lược phân vùng (Zone strategy)
- Sử dụng ít nhất hai vùng (zones) cho bất kỳ hệ thống môi trường thực tế (production) nào; dùng ba vùng nếu khu vực (region) và ngân sách cho phép.
- Giữ chỗ trước các khối địa chỉ cho vùng thứ ba ngay từ bây giờ dù chưa dùng tới; việc này giúp cấu trúc bố trí luôn đối xứng.
- Các mạng con trên GCP có phạm vi theo khu vực (regional), vì vậy hãy quy hoạch theo từng khu vực thay vì theo từng vùng (zone).

## Tính toán kích thước cho Kubernetes
- Với AWS VPC CNI hoặc Azure CNI, mỗi pod sẽ lấy một địa chỉ IP từ VPC: hãy tính kích thước mạng con tầng app theo số lượng pod ở mức đỉnh (số node x số pod tối đa trên mỗi node), cộng thêm mức tăng đột biến trong quá trình cập nhật cuốn chiếu (rolling updates, thường là +25%) và khi thay thế node.
- Cơ chế ủy quyền tiền tố (Prefix delegation trên AWS) hoặc mạng phủ (overlay networking như Calico, Cilium, kubenet, Azure CNI Overlay) sẽ chuyển các pod sang một dải địa chỉ riêng biệt; khi đó chỉ cần tính kích thước mạng con theo số lượng node và giữ cho dải CIDR của pod không bị trùng với bất kỳ mạng ngang hàng nào.
- Giữ cho dải CIDR của service (ví dụ 172.20.0.0/16) cũng tách biệt hoàn toàn khỏi VPC và các mạng ngang hàng.

## Tránh chồng lấn địa chỉ
- Thu thập mọi mạng mà bạn sẽ cần định tuyến tới: các VPC và tài khoản khác, máy khách VPN, văn phòng, đối tác, các đám mây khác và cả những dải mạng đang được sử dụng bởi các công ty được mua lại/sáp nhập.
- Duy trì một bảng quy hoạch IP tập trung (bảng tính hoặc hệ thống IPAM) và cấp cho mỗi môi trường một khối riêng biệt, ví dụ: 10.20.0.0/16 cho prod, 10.21.0.0/16 cho staging, 10.22.0.0/16 cho dev.
- Không chọn các dải 10.0.0.0/16, 172.17.0.0/16 hoặc từ 192.168.0.0/24 đến 192.168.1.0/24 cho bất kỳ hệ thống nào mà người dùng VPN sẽ kết nối vào.

## Khi đã xảy ra chồng lấn
1. Ưu tiên đánh số lại (renumbering) phía mạng nhỏ hơn hoặc mới hơn ngay lập tức (tạo VPC mới hoặc thêm một dải CIDR phụ, di chuyển hệ thống sang, rồi xóa mạng cũ).
2. Nếu không thể đánh số lại, hãy sử dụng NAT (private NAT gateway, hoặc NAT trên thiết bị VPN) và chỉ định tuyến các dải địa chỉ đã được biên dịch (translated ranges).
3. Các mạng con chồng lấn bên trong cùng một VPC không thể tạo được trên AWS / Azure / GCP; nếu thấy xuất hiện trong tài liệu thì thường là do lỗi gõ nhầm, vì vậy hãy kiểm tra lại các giá trị thực tế.

## Danh sách kiểm tra rà soát (Review checklist)
- [ ] Dải VPC là địa chỉ riêng (private) và duy nhất trên tất cả các mạng ngang hàng (peers) cùng mạng VPN
- [ ] Mọi mạng con đều được căn chỉnh đúng, nằm trong VPC và không bị chồng lấn nhau
- [ ] Kích thước đã tính gộp cả các địa chỉ dành riêng và mức tăng trưởng dự kiến
- [ ] Các tầng cùng loại có kích thước bằng nhau ở mỗi vùng; có giữ lại khối dự phòng
- [ ] Còn trống ít nhất 25% không gian địa chỉ của VPC
FILE:templates/subnet-plan.md
# Bản Quy hoạch Mạng con - <tên mạng>

**Nhà cung cấp / khu vực:** <aws eu-west-1>  **VPC CIDR:** <10.x.0.0/16>  **Đơn vị sở hữu:** <nhóm>  **Ngày:** <ngày>
**Các mạng ngang hàng (Peers) / VPN đã kiểm tra:** <danh sách các dải địa chỉ>

## Các mạng con (Subnets)
| Mạng con | Tầng (Tier) | Vùng (Zone) | Số host hiện tại | Mức tăng trưởng | CIDR | Số IP khả dụng | Bảng định tuyến (Route table) |
|---|---|---|---|---|---|---|---|
| | | | | | | | |

## Các mạng con hiện có được giữ lại
| Tên | CIDR | Ghi chú |
|---|---|---|
| | | |

## Không gian trống
- Đã sử dụng hoặc bị chặn: <n> trên tổng số <total> (còn trống <x>%)
- Các khối dự phòng được giữ chỗ cho: <vùng thứ ba / tầng tương lai>

## Các phát hiện và quyết định
| Mức độ nghiêm trọng | Phát hiện | Quyết định |
|---|---|---|
| | | |

## Thứ tự triển khai (Rollout order)
1. <tạo CIDR phụ / tạo VPC mới>
2. <tạo các mạng con và bảng định tuyến>
3. <di chuyển các tải công việc (workloads), xóa các mạng con cũ>
FILE:examples/shop-platform-vpc.json
{
  "name": "shop platform, eu-west-1 production VPC",
  "provider": "aws",
  "vpc_cidrs": ["10.20.0.0/18"],
  "existing": [
    {"name": "legacy bastion", "cidr": "10.20.0.0/26"},
    {"name": "legacy rds-a", "cidr": "10.20.1.0/24"},
    {"name": "legacy rds-b", "cidr": "10.20.1.128/25"}
  ],
  "peers": [
    {"name": "office VPN (Istanbul)", "cidr": "192.168.10.0/24"},
    {"name": "analytics VPC (peered)", "cidr": "10.20.48.0/20"}
  ],
  "requests": [
    {"name": "public-a (load balancers)", "hosts": 40, "zone": "eu-west-1a", "growth": 0.5},
    {"name": "public-b (load balancers)", "hosts": 40, "zone": "eu-west-1b", "growth": 0.5},
    {"name": "app-a (EKS pods)", "hosts": 2500, "zone": "eu-west-1a", "growth": 0.6},
    {"name": "app-b (EKS pods)", "hosts": 2500, "zone": "eu-west-1b", "growth": 0.6},
    {"name": "data-a (databases, cache)", "hosts": 60, "zone": "eu-west-1a"},
    {"name": "data-b (databases, cache)", "hosts": 60, "zone": "eu-west-1b"}
  ]
}
FILE:scripts/cidr_plan.py
#!/usr/bin/env python3
"""VPC subnet CIDR planner and checker (Python 3 standard library only).

Input: a network plan JSON file:
  {"name": "prod-eu", "provider": "aws", "vpc_cidrs": ["10.40.0.0/16"],
   "existing": [{"name": "legacy-db", "cidr": "10.40.8.0/24"}],
   "peers": [{"name": "office vpn", "cidr": "192.168.0.0/22"}],
   "requests": [{"name": "app-a", "hosts": 900, "zone": "eu-west-1a", "growth": 0.5}]}
  provider: aws | azure | gcp | generic. Reserved addresses per subnet: aws 5, azure 5,
  gcp 4, generic 2 (network + broadcast). Subnet size limits: aws /16../28,
  azure /8../29, gcp /8../29, generic /8../30.
  requests: hosts needed now; growth = extra fraction to reserve (default 0.3);
  optional "prefix" forces a size. Allocation is largest-first, aligned, lowest free address,
  never overlapping existing subnets or peer networks that sit inside the VPC.

Checks (severity):
  HIGH   OVERLAP_EXISTING   two existing subnets overlap
  HIGH   OUTSIDE_VPC        existing subnet not inside any VPC CIDR
  HIGH   PEER_OVERLAP       VPC CIDR overlaps a peered / VPN / on-prem network (routing breaks)
  HIGH   NO_SPACE           a request does not fit in the remaining space
  MEDIUM DOCKER_DEFAULT     VPC overlaps 172.17.0.0/16 (default docker0 bridge)
  MEDIUM PUBLIC_RANGE       VPC CIDR is not private (RFC 1918 / 100.64.0.0/10)
  MEDIUM PREFIX_LIMIT       requested or VPC prefix outside the provider limits
  LOW    LOW_HEADROOM       less than 25% of the VPC left free after the plan
  LOW    SINGLE_ZONE        all requests in one zone (no zone redundancy)
Usage:
  python3 cidr_plan.py plan.json
  python3 cidr_plan.py plan.json --json
  python3 cidr_plan.py --self-test
Exit code: 0 no HIGH findings, 1 HIGH findings, 2 bad input.
"""
import argparse
import ipaddress as ip
import json
import math
import sys

RESERVED = {"aws": 5, "azure": 5, "gcp": 4, "generic": 2}
HEAD_RESERVED = {"aws": 4, "azure": 4, "gcp": 2, "generic": 1}  # rest are at the end of the block
LIMITS = {"aws": (16, 28), "azure": (8, 29), "gcp": (8, 29), "generic": (8, 30)}
PRIVATE = [ip.ip_network(c) for c in ("10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/10")]
DOCKER = ip.ip_network("172.17.0.0/16")


class PlanError(ValueError):
    pass


def net(cidr, what="cidr"):
    try:
        n = ip.ip_network(str(cidr).strip(), strict=True)
    except ValueError as e:
        raise PlanError(f"bad {what} {cidr!r}: {e}")
    if n.version != 4:
        raise PlanError(f"only IPv4 is supported: {cidr!r}")
    return n


def usable(prefix, provider):
    return max(0, 2 ** (32 - prefix) - RESERVED[provider])


def prefix_for(hosts, provider, growth):
    need = math.ceil(hosts * (1 + growth))
    lo, hi = LIMITS[provider]
    for p in range(hi, lo - 1, -1):
        if usable(p, provider) >= need:
            return p
    return None


def find_slot(vpcs, taken, prefix):
    for v in vpcs:
        if prefix < v.prefixlen:
            continue
        for cand in v.subnets(new_prefix=prefix):
            if not any(cand.overlaps(t) for t in taken):
                return cand
    return None


def plan(cfg):
    provider = str(cfg.get("provider", "generic")).lower()
    if provider not in RESERVED:
        raise PlanError(f"unknown provider {provider!r} (aws, azure, gcp, generic)")
    vpcs = [net(c, "vpc_cidr") for c in cfg.get("vpc_cidrs") or []]
    if not vpcs:
        raise PlanError("vpc_cidrs is empty")
    lo, hi = LIMITS[provider]
    findings = []

    def f(sev, code, where, msg):
        findings.append({"severity": sev, "code": code, "where": where, "message": msg})

    for v in vpcs:
        if not any(v.subnet_of(p) for p in PRIVATE):
            f("MEDIUM", "PUBLIC_RANGE", str(v), "not an RFC 1918 or 100.64.0.0/10 range; it may clash with real internet addresses")
        if v.overlaps(DOCKER):
            f("MEDIUM", "DOCKER_DEFAULT", str(v), "overlaps 172.17.0.0/16, the default docker0 bridge; containers on hosts in this VPC may lose routes")
        if provider == "aws" and not (16 <= v.prefixlen <= 28):
            f("MEDIUM", "PREFIX_LIMIT", str(v), "AWS VPC CIDR blocks must be /16 to /28")
    for i, a in enumerate(vpcs):
        for b in vpcs[i + 1:]:
            if a.overlaps(b):
                raise PlanError(f"vpc_cidrs overlap each other: {a} and {b}")

    existing = []
    for e in cfg.get("existing") or []:
        n = net(e.get("cidr"), "existing cidr")
        name = e.get("name") or str(n)
        if not any(n.subnet_of(v) for v in vpcs):
            f("HIGH", "OUTSIDE_VPC", name, f"{n} is not inside {', '.join(map(str, vpcs))}")
        for other_name, o in existing:
            if n.overlaps(o):
                f("HIGH", "OVERLAP_EXISTING", name, f"{n} overlaps {other_name} {o}")
        existing.append((name, n))

    taken = [n for _, n in existing]
    for p in cfg.get("peers") or []:
        n = net(p.get("cidr"), "peer cidr")
        name = p.get("name") or str(n)
        for v in vpcs:
            if v.overlaps(n):
                f("HIGH", "PEER_OVERLAP", name, f"{n} overlaps VPC {v}; traffic to the overlapping range cannot be routed both ways (renumber one side or use NAT)")
                taken.append(n)

    reqs = []
    for r in cfg.get("requests") or []:
        name = r.get("name") or "subnet"
        hosts = r.get("hosts", 0)
        if not isinstance(hosts, int) or isinstance(hosts, bool) or hosts < 1:
            raise PlanError(f"request {name!r}: hosts must be a positive integer")
        growth = r.get("growth", 0.3)
        if not isinstance(growth, (int, float)) or growth < 0:
            raise PlanError(f"request {name!r}: growth must be >= 0")
        if "prefix" in r:
            pfx = r["prefix"]
            if not isinstance(pfx, int) or not 8 <= pfx <= 30:
                raise PlanError(f"request {name!r}: prefix must be an integer 8..30")
            if not lo <= pfx <= hi:
                f("MEDIUM", "PREFIX_LIMIT", name, f"/{pfx} is outside {provider} subnet limits /{lo}../{hi}")
        else:
            pfx = prefix_for(hosts, provider, growth)
        reqs.append({"name": name, "hosts": hosts, "growth": growth, "zone": r.get("zone", ""), "prefix": pfx})

    allocs = []
    order = sorted(range(len(reqs)), key=lambda i: (reqs[i]["prefix"] if reqs[i]["prefix"] is not None else -1, i))
    for i in order:
        r = reqs[i]
        slot = find_slot(vpcs, taken, r["prefix"]) if r["prefix"] is not None else None
        if slot is None:
            f("HIGH", "NO_SPACE", r["name"], f"needs {r['hosts']} hosts (+{round(r['growth'] * 100)}% growth) and no free aligned block is left")
            allocs.append(dict(r, cidr=None, usable=0))
            continue
        taken.append(slot)
        u = usable(slot.prefixlen, provider)
        tail = RESERVED[provider] - HEAD_RESERVED[provider]
        allocs.append(dict(r, cidr=str(slot), usable=u,
                           first=str(slot[HEAD_RESERVED[provider]]) if u else "-",
                           last=str(slot[-1 - tail]) if u else "-"))
        if u < r["hosts"]:
            f("HIGH", "NO_SPACE", r["name"], f"/{slot.prefixlen} gives only {u} usable addresses for {r['hosts']} hosts")
    allocs.sort(key=lambda a: (a["cidr"] is None, ip.ip_network(a["cidr"]) if a["cidr"] else 0))

    total = sum(v.num_addresses for v in vpcs)
    used = 0
    inside = [t for t in taken if any(t.subnet_of(v) for v in vpcs)]
    for t in ip.collapse_addresses(inside):
        used += t.num_addresses
    free = total - used
    free_blocks = []
    for v in vpcs:
        rest = [v]
        for t in ip.collapse_addresses([x for x in inside if x.subnet_of(v)]):
            nxt = []
            for b in rest:
                if t.subnet_of(b):
                    nxt.extend(b.address_exclude(t))
                elif not b.subnet_of(t):
                    nxt.append(b)
            rest = nxt
        free_blocks.extend(sorted(rest))
    if total and free / total < 0.25:
        f("LOW", "LOW_HEADROOM", "plan", f"only {free / total:.0%} of the VPC address space is left free")
    zones = {r["zone"] for r in reqs if r["zone"]}
    if len(reqs) > 1 and len(zones) == 1:
        f("LOW", "SINGLE_ZONE", "plan", f"all requests are in {zones.pop()}; spread subnets over at least two zones")
    rank = {"HIGH": 0, "MEDIUM": 1, "LOW": 2}
    findings.sort(key=lambda x: rank[x["severity"]])
    return {"name": cfg.get("name", "network plan"), "provider": provider, "vpcs": [str(v) for v in vpcs],
            "existing": [{"name": n, "cidr": str(c)} for n, c in existing],
            "allocations": allocs, "total": total, "used": used, "free": free,
            "free_blocks": [str(b) for b in free_blocks], "findings": findings}


def report(res):
    out = [f"# Subnet plan: {res['name']}", "",
           f"Provider: {res['provider']} (reserves {RESERVED[res['provider']]} addresses per subnet)  VPC: {', '.join(res['vpcs'])}", "",
           "| Subnet | Zone | Hosts now | Growth | CIDR | Usable | First host | Last host |", "|---|---|---|---|---|---|---|---|"]
    for a in res["allocations"]:
        out.append(f"| {a['name']} | {a['zone'] or '-'} | {a['hosts']} | {round(a['growth'] * 100)}% | {a['cidr'] or 'NOT PLACED'} | "
                   f"{a['usable']} | {a.get('first', '-')} | {a.get('last', '-')} |")
    if res["existing"]:
        out += ["", "Existing subnets kept: " + ", ".join(f"{e['name']} {e['cidr']}" for e in res["existing"])]
    pct = res["free"] / res["total"] if res["total"] else 0
    out += ["", f"Address space: {res['used']} of {res['total']} used or blocked, {res['free']} free ({pct:.0%})",
            "Largest free blocks: " + (", ".join(sorted(res["free_blocks"], key=lambda c: ip.ip_network(c).prefixlen)[:6]) or "none"),
            "", "## Findings"]
    if not res["findings"]:
        out.append("- none")
    for x in res["findings"]:
        out.append(f"- **{x['severity']} {x['code']}** ({x['where']}): {x['message']}")
    return "\n".join(out) + "\n"


def self_test():
    cases = []

    def ok(name, cond):
        cases.append(bool(cond))
        print(("PASS " if cond else "FAIL ") + name)

    ok("aws /24 usable 251", usable(24, "aws") == 251)
    ok("generic /24 usable 254", usable(24, "generic") == 254)
    ok("gcp /29 usable 4", usable(29, "gcp") == 4)
    ok("900 hosts +50% on aws -> /21", prefix_for(900, "aws", 0.5) == 21)
    ok("250 hosts no growth aws -> /24", prefix_for(250, "aws", 0) == 24)
    ok("252 hosts no growth aws -> /23", prefix_for(252, "aws", 0) == 23)
    ok("too big for aws -> None", prefix_for(70000, "aws", 0) is None)
    base = {"provider": "aws", "vpc_cidrs": ["10.0.0.0/16"]}
    r = plan(dict(base, requests=[{"name": "a", "hosts": 200, "zone": "z1"}, {"name": "b", "hosts": 1000, "zone": "z2"}]))
    cid = {a["name"]: a["cidr"] for a in r["allocations"]}
    ok("largest first gets lowest block", cid == {"b": "10.0.0.0/21", "a": "10.0.8.0/23"})
    ok("clean plan has no findings", r["findings"] == [])
    aa = [a for a in r["allocations"] if a["name"] == "a"][0]
    ok("first/last host skip aws reserved", (aa["first"], aa["last"]) == ("10.0.8.4", "10.0.9.254"))
    g = plan({"provider": "gcp", "vpc_cidrs": ["10.0.0.0/16"], "requests": [{"name": "a", "hosts": 100, "growth": 0}]})["allocations"][0]
    ok("gcp reserves 2 head + 2 tail", (g["cidr"], g["first"], g["last"]) == ("10.0.0.0/25", "10.0.0.2", "10.0.0.125"))
    r = plan(dict(base, existing=[{"name": "old", "cidr": "10.0.0.0/22"}], requests=[{"name": "a", "hosts": 1000}]))
    ok("allocation avoids existing", r["allocations"][0]["cidr"] == "10.0.8.0/21")
    r = plan(dict(base, existing=[{"name": "x", "cidr": "10.0.0.0/24"}, {"name": "y", "cidr": "10.0.0.128/25"}]))
    ok("overlap existing flagged", any(x["code"] == "OVERLAP_EXISTING" for x in r["findings"]))
    r = plan(dict(base, existing=[{"name": "x", "cidr": "10.1.0.0/24"}]))
    ok("outside vpc flagged", any(x["code"] == "OUTSIDE_VPC" for x in r["findings"]))
    r = plan(dict(base, peers=[{"name": "vpn", "cidr": "10.0.4.0/22"}], requests=[{"name": "a", "hosts": 900, "growth": 0}]))
    ok("peer overlap flagged", any(x["code"] == "PEER_OVERLAP" for x in r["findings"]))
    ok("allocation avoids peer range", r["allocations"][0]["cidr"] == "10.0.0.0/22")
    r = plan({"provider": "aws", "vpc_cidrs": ["10.0.0.0/24"], "requests": [{"name": "a", "hosts": 200}]})
    ok("no space flagged", any(x["code"] == "NO_SPACE" for x in r["findings"]))
    r = plan({"provider": "generic", "vpc_cidrs": ["172.16.0.0/12"]})
    ok("docker default flagged", any(x["code"] == "DOCKER_DEFAULT" for x in r["findings"]))
    r = plan({"provider": "generic", "vpc_cidrs": ["8.8.0.0/16"]})
    ok("public range flagged", any(x["code"] == "PUBLIC_RANGE" for x in r["findings"]))
    r = plan({"provider": "aws", "vpc_cidrs": ["10.0.0.0/8"]})
    ok("aws vpc /8 flagged", any(x["code"] == "PREFIX_LIMIT" for x in r["findings"]))
    r = plan({"provider": "aws", "vpc_cidrs": ["10.0.0.0/22"], "requests": [{"name": "a", "hosts": 400, "zone": "z1"}, {"name": "b", "hosts": 300, "zone": "z1"}]})
    ok("low headroom flagged", any(x["code"] == "LOW_HEADROOM" for x in r["findings"]))
    ok("single zone flagged", any(x["code"] == "SINGLE_ZONE" for x in r["findings"]))
    r = plan(dict(base, requests=[{"name": "a", "hosts": 10, "prefix": 30}]))
    ok("forced /30 on aws flagged", any(x["code"] == "PREFIX_LIMIT" for x in r["findings"]))
    r = plan(dict(base, requests=[{"name": "a", "hosts": 1000}]))
    ok("free blocks cover rest", sum(ip.ip_network(b).num_addresses for b in r["free_blocks"]) == 65536 - 2048)
    for bad, label in ((dict(base, vpc_cidrs=[]), "empty vpc"), (dict(base, vpc_cidrs=["10.0.0.1/16"]), "host bits set"),
                       (dict(base, provider="oracle"), "unknown provider"), (dict(base, requests=[{"hosts": 0}]), "zero hosts"),
                       (dict(base, vpc_cidrs=["10.0.0.0/16", "10.0.128.0/17"]), "overlapping vpcs"),
                       (dict(base, vpc_cidrs=["fd00::/48"]), "ipv6")):
        try:
            plan(bad)
            ok(label + " rejected", False)
        except PlanError:
            ok(label + " rejected", True)
    print(f"{sum(cases)}/{len(cases)} passed")
    return 0 if all(cases) else 1


def main(argv=None):
    ap = argparse.ArgumentParser(description="Plan and check VPC subnet CIDR blocks.")
    ap.add_argument("file", nargs="?", help="network plan JSON")
    ap.add_argument("--json", action="store_true", help="print machine-readable JSON")
    ap.add_argument("--self-test", action="store_true")
    a = ap.parse_args(argv)
    if a.self_test:
        return self_test()
    if not a.file:
        ap.error("give a plan JSON file or --self-test")
    try:
        cfg = json.load(open(a.file, encoding="utf-8"))
        res = plan(cfg)
    except (OSError, json.JSONDecodeError, PlanError) as e:
        print(f"error: {e}", file=sys.stderr)
        return 2
    print(json.dumps(res, indent=2) if a.json else report(res), end="" if not a.json else "\n")
    return 1 if any(x["severity"] == "HIGH" for x in res["findings"]) else 0


if __name__ == "__main__":
    sys.exit(main())
PythonDevOpsCloud+2
F@f
0
Công cụ Tối ưu hóa Định mức Tài nguyên Kubernetes (Rightsizer)
Kỹ năng

Tối ưu hóa đúng định mức (rightsize) các thông số requests và limits cho CPU và bộ nhớ trong Kubernetes dựa trên mức sử dụng thực tế (p50, p95 và max trên từng container). Đề xuất mức requests tại ngưỡng p95 cộng thêm khoảng dự phòng (headroom), giới hạn bộ nhớ (memory limits) cao hơn mức đỉnh và loại bỏ giới hạn CPU (CPU limits), đồng thời ước tính số lõi (cores), dung lượng GiB và chi phí tiết kiệm được. Cảnh báo các lỗi OOM kill, mức dùng bộ nhớ vượt quá request, hiện tượng bóp băng thông CPU (CPU throttling), thiếu thông số requests hoặc memory limits, cấp phát dư thừa (overprovisioning) và khoảng thời gian thu thập dữ liệu quá ngắn. Bao gồm một công cụ tính toán bằng thư viện chuẩn Python có hỗ trợ cờ --self-test.

---
name: kubernetes-resource-requests-rightsizer
description: Tối ưu hóa đúng định mức (rightsize) các thông số requests và limits cho CPU và bộ nhớ trong Kubernetes dựa trên mức sử dụng thực tế (p50, p95 và max trên từng container). Đề xuất mức requests tại ngưỡng p95 cộng thêm khoảng dự phòng (headroom), giới hạn bộ nhớ (memory limits) cao hơn mức đỉnh và loại bỏ giới hạn CPU (CPU limits), đồng thời ước tính số lõi (cores), dung lượng GiB và chi phí tiết kiệm được. Cảnh báo các lỗi OOM kill, mức dùng bộ nhớ vượt quá request, hiện tượng bóp băng thông CPU (CPU throttling), thiếu thông số requests hoặc memory limits, cấp phát dư thừa (overprovisioning) và khoảng thời gian thu thập dữ liệu quá ngắn. Bao gồm một công cụ tính toán bằng thư viện chuẩn Python có hỗ trợ cờ --self-test.
---

# Công cụ Tối ưu hóa Định mức Tài nguyên Kubernetes (Rightsizer)

Bạn giúp các kỹ sư nền tảng (platform engineers), kỹ sư SRE và nhà phát triển thiết lập thông số requests và limits cho các container Kubernetes dựa trên bằng chứng số liệu thực tế thay vì phỏng đoán. Từ các phân vị mức sử dụng (usage percentiles) được xuất ra từ Prometheus, Datadog hoặc trình đề xuất VPA, bạn đề xuất thông số requests và limits mới cho từng container, giải thích các rủi ro nguy hiểm trước tiên (lỗi OOM kill, nghẽn CPU do throttling, nguy cơ bị trục xuất pod - eviction), ước tính lượng tài nguyên mà cụm (cluster) tiết kiệm được, và lập kế hoạch triển khai an toàn.

## Các tệp trong kỹ năng này

- `scripts/rightsize.py` - đọc tệp CSV chứa các thiết lập hiện tại và phân vị mức sử dụng của từng container, sau đó in ra thông số requests và limits được khuyến nghị, các phát hiện rủi ro và lượng tài nguyên requests được giải phóng (chỉ dùng thư viện chuẩn của Python 3)
- `references/sizing-method.md` - vai trò của requests và limits, quy tắc tính toán định mức, các chỉ số cần thu thập (kèm câu truy vấn PromQL), và cách đọc số liệu của các container đang bị bóp CPU (throttled) hoặc bị OOM kill
- `references/rollout-and-guardrails.md` - thứ tự áp dụng thay đổi, quy trình triển khai (rollout) và hoàn tác (rollback) an toàn, LimitRange, ResourceQuota, VPA, cảnh báo (alerts), và những trường hợp không nên cắt giảm tài nguyên
- `templates/rightsizing-plan.md` - mẫu kế hoạch tối ưu hóa định mức tài nguyên để chia sẻ với nhóm hoặc đính kèm vào phiếu yêu cầu thay đổi (change ticket)
- `examples/shop-cluster-usage.csv` - sáu container của một hệ thống cửa hàng trực tuyến: một API được cấp phát quá dư thừa, container sidecar đi kèm của nó, một dịch vụ tìm kiếm vừa bị OOM kill vừa bị bóp CPU, một worker không đặt giới hạn bộ nhớ, Redis và một trình đẩy log (log shipper) không khai báo requests

## Quy trình làm việc

### 1. Thu thập số liệu sử dụng
Hãy yêu cầu dữ liệu thống kê theo từng container trong ít nhất 7 ngày (tốt nhất là 14-28 ngày): số lượng bản sao (replicas), thông số requests và limits hiện tại, phân vị p50/p95/max của CPU tính bằng millicores, phân vị p50/p95/max của bộ nhớ làm việc (memory working set) tính bằng MiB, tỷ lệ phần trăm bị bóp CPU (throttled percentage) và số lần bị OOM kill. Tệp `references/sizing-method.md` có sẵn câu truy vấn PromQL cho từng chỉ số này. Hãy hỏi thêm về nhiệm vụ của từng workload, đặc điểm biến thiên lưu lượng truy cập (đỉnh điểm hàng tuần, đợt khuyến mãi, tác vụ chạy theo lô batch jobs) và liệu có đang dùng HPA để tự động co giãn cho nó hay không.

### 2. Chạy công cụ tối ưu hóa định mức
```
python3 scripts/rightsize.py examples/shop-cluster-usage.csv --core-month 24 --gib-month 3.2
python3 scripts/rightsize.py usage.csv --headroom 25 --keep-cpu-limits --json
python3 scripts/rightsize.py --self-test
```
Thông số đơn giá là tùy chọn và được tính trên mỗi lõi (core) hoặc mỗi GiB được yêu cầu (requested) mỗi tháng. Mã thoát (exit code) bằng 1 nghĩa là có phát hiện rủi ro mức CRITICAL hoặc HIGH, bằng 2 nghĩa là dữ liệu đầu vào không hợp lệ.

### 3. Giải thích và lập kế hoạch
Bắt đầu với các container có mức cảnh báo CRITICAL và HIGH: nêu rõ vấn đề gì đang xảy ra hiện nay, bằng chứng số liệu cụ thể và thay đổi cần áp dụng. Đối với các container đang bị bóp CPU hoặc bị OOM kill, hãy lưu ý rằng các con số sử dụng hiện tại đã bị chạm trần giới hạn và cần lên kế hoạch đo đạc lại lần thứ hai sau khi khắc phục. Tiếp theo, liệt kê các khoản tiết kiệm lớn nhất (số lượng replicas sẽ nhân bội mức tiết kiệm này lên). Kiểm tra các trường hợp ngoại lệ trong `references/rollout-and-guardrails.md` mà việc cắt giảm tài nguyên là không an toàn, đồng thời nhắc nhở việc tinh chỉnh lại ngưỡng HPA khi thay đổi thông số requests.

### 4. Bàn giao kết quả
Điền vào mẫu `templates/rightsizing-plan.md` với bảng tổng hợp, bản vá YAML (YAML patch) cho từng workload, thứ tự triển khai, các chỉ số cần theo dõi và ngày hẹn đo đạc lại.

## Ví dụ kết quả
Đối với tệp `examples/shop-cluster-usage.csv`: container shop/catalog-search/app ở mức CRITICAL (bị OOM kill 3 lần tại ngưỡng giới hạn 1536Mi, mức bộ nhớ p95 là 1180Mi vượt quá mức request 1024Mi, bị bóp CPU 31% tại ngưỡng giới hạn 500m) và được đề xuất mức requests mới là 570m / 1360Mi, giới hạn bộ nhớ 1872Mi và gỡ bỏ hoàn toàn giới hạn CPU; ops/log-shipper hoàn toàn không có thông số requests nào (mức HIGH, chạy 8 replicas); shop/image-resizer cần bổ sung giới hạn bộ nhớ và tăng thêm bộ nhớ; shop/checkout-api/app giảm từ 1000m / 2048Mi xuống còn 485m / 912Mi trên 6 replicas. Tổng cộng giải phóng được 1.76 cores và 4.06 GiB tài nguyên requests, tương đương tiết kiệm khoảng 55 mỗi tháng nếu tính theo đơn giá 24 trên mỗi core và 3.2 trên mỗi GiB.

## Quy tắc

- Luôn khắc phục các rủi ro về độ tin cậy trước khi tối ưu tiết kiệm chi phí, và tuyệt đối không bao giờ khuyến nghị gỡ bỏ giới hạn bộ nhớ (memory limit).
- Luôn nêu rõ mỗi con số đề xuất được tính từ phân vị nào, khoảng thời gian dữ liệu bao lâu và tỷ lệ dự phòng (headroom) là bao nhiêu, đồng thời lưu ý rằng các đợt tăng vọt hiếm gặp nằm ngoài khoảng thời gian thu thập dữ liệu sẽ chưa được tính tới.
- Coi mức sử dụng của các container đang bị bóp CPU (throttled) hoặc bị OOM kill chỉ là mức sàn tối thiểu (floor), chứ chưa phải nhu cầu thực tế của chúng.
- Cung cấp các thay đổi dưới dạng bản vá tệp manifest hoặc Helm values để đội ngũ kỹ thuật xem xét; không tự ý chạy các lệnh `kubectl` trực tiếp lên cụm đang hoạt động.
- Báo cáo mức tiết kiệm dưới dạng "tài nguyên requests được giải phóng" cho tới khi các máy chủ nút (nodes) thực sự được thu hồi giảm bớt.
FILE:references/sizing-method.md
# Phương pháp Tính toán Định mức (Sizing Method)

## Vai trò của requests và limits
- **CPU request:** lượng tài nguyên mà bộ lập lịch (scheduler) đặt chỗ trước trên một node và là tỷ trọng chia sẻ CPU của container đó khi node rơi vào trạng thái bận. Đặt quá thấp: pod bị xếp vào các node chật chội và chạy chậm đi khi tải cao. Đặt quá cao: các node trông có vẻ đã đầy trên sổ sách trong khi thực tế lại đang nhàn rỗi, khiến bạn phải trả tiền cho những lõi CPU bỏ không.
- **CPU limit:** mức trần cứng được thực thi bởi hạn ngạch CFS (CFS quota) theo từng chu kỳ 100 ms. Một container chạm tới ngưỡng này sẽ bị bóp băng thông (throttled), ngay cả khi node đó đang dư thừa CPU nhàn rỗi. Các dịch vụ nhạy cảm với độ trễ (API, proxy, ứng dụng JVM và chương trình Go sử dụng nhiều luồng) sẽ chịu ảnh hưởng nặng nề nhất.
- **Memory request:** lượng bộ nhớ mà bộ lập lịch đặt chỗ trước. Các pod sử dụng nhiều bộ nhớ hơn mức request của chúng sẽ là đối tượng đầu tiên bị trục xuất (evicted) khi một node cạn kiệt bộ nhớ.
- **Memory limit:** mức trần cứng; vượt quá ngưỡng này đồng nghĩa với việc bị OOM kill ngay lập tức (mã thoát 137, lý do `OOMKilled`). Bộ nhớ không thể bị làm chậm (throttled) như CPU.
- **Các hạng QoS (QoS classes):** Guaranteed (requests = limits cho mọi container trong pod), Burstable (có thiết lập một số thông số requests), BestEffort (không thiết lập gì cả, sẽ bị trục xuất đầu tiên khi thiếu tài nguyên).

## Các quy tắc được sử dụng bởi `scripts/rightsize.py`
| Thông số | Quy tắc tính | Lý do |
|---|---|---|
| CPU request | p95 x (1 + headroom), làm tròn lên theo bậc 5m, tối thiểu 10m | đáp ứng tốt các giai đoạn bận rộn thông thường; phần nhu cầu đột biến còn lại sẽ tận dụng nguồn CPU nhàn rỗi dùng chung |
| CPU limit | gỡ bỏ (hoặc nếu dùng cờ `--keep-cpu-limits`: max(max x 1.2, 2 x request)) | giới hạn CPU gây nghẽn các đợt xử lý đột biến ngay cả trên các node đang rảnh |
| Memory request | p95 x (1 + headroom), làm tròn lên theo bậc 16Mi, tối thiểu 32Mi | giữ cho pod nằm ngoài danh sách ưu tiên bị trục xuất (eviction) |
| Memory limit | max(max x 1.25, request), làm tròn lên theo bậc 16Mi | tạo khoảng trống cho các đỉnh tải; không bao giờ được gỡ bỏ vì một lỗi rò rỉ bộ nhớ (memory leak) không được phép đánh sập cả node |

Tỷ lệ dự phòng (headroom) mặc định là 15%. Hãy nâng lên mức 25-30% đối với các lưu lượng có tính chất tăng vọt đột ngột (spiky traffic), các tác vụ chạy theo lô (batch jobs) hoặc khi khoảng thời gian thu thập dữ liệu quá ngắn.

## Các chỉ số cần thu thập
Trên từng container, trong khoảng thời gian ít nhất 7 ngày (tốt nhất là 14-28 ngày để bắt được các đỉnh tải hàng tuần và cuối tháng):
- CPU tính bằng millicores: giá trị p50, p95 và max của `rate(container_cpu_usage_seconds_total[5m]) * 1000`
- Bộ nhớ tính bằng MiB: giá trị p50, p95 và max của `container_memory_working_set_bytes / 2^20` (working set chính là chỉ số mà trình OOM killer và cơ chế trục xuất eviction theo dõi, chứ không phải RSS hay cache)
- Tỷ lệ bóp CPU (Throttling): `container_cpu_cfs_throttled_periods_total / container_cpu_cfs_periods_total * 100`
- Số lần OOM kill: `kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}` hoặc số lần khởi động lại (restarts) với mã thoát 137
- Thiết lập hiện tại: dùng lệnh `kubectl get deploy -o jsonpath` hoặc chỉ số `kube_pod_container_resource_requests` / `_limits`

## Cách đọc kết quả
- **Các container bị bóp CPU (Throttled containers)** sẽ báo cáo mức sử dụng bị chặn đứng tại ngưỡng limit, do đó chỉ số p95 thu được thấp hơn nhu cầu thực tế. Hãy nâng cao hoặc gỡ bỏ giới hạn CPU trước, đo đạc lại trong vài ngày, rồi mới tính toán định mức chuẩn.
- **Các lỗi OOM kill** có nghĩa là mức đỉnh thực sự vẫn chưa xác định được (vì container đã bị giết ngay khi chạm ngưỡng limit). Hãy tăng giới hạn bộ nhớ lên thêm 50% hoặc nhiều hơn, tìm nguyên nhân rò rỉ bộ nhớ hoặc truy vấn nặng gây tốn RAM, sau đó đo đạc lại.
- **Ứng dụng JVM, Node.js và Go** đọc kích thước vùng nhớ heap từ cấu hình khởi chạy: hãy thay đổi các cờ `-Xmx`, `--max-old-space-size` hoặc `GOMEMLIMIT` đồng bộ với giới hạn bộ nhớ của container (giữ vùng nhớ heap ở mức khoảng 70-75% so với memory limit).
- **Các container phụ trợ (Sidecars)** (như istio-proxy, trình đẩy log) cần được tính toán định mức riêng biệt; thông số của chúng sẽ được nhân lên theo từng bản sao (replica) của ứng dụng.
- **HPA dựa trên CPU** thực hiện co giãn dựa trên tỷ lệ giữa mức sử dụng thực tế chia cho thông số request. Việc hạ thấp thông số request sẽ khiến HPA kích hoạt nhân bản (scale out) sớm hơn, vì vậy bạn có thể cần hạ mục tiêu `averageUtilization` hoặc số lượng bản sao sẽ thay đổi. Hãy tối ưu hóa định mức tài nguyên trước, sau đó tinh chỉnh lại HPA.

## Giới hạn của phương pháp này
- Các chỉ số phân vị trong một khung thời gian sẽ bỏ sót các sự kiện hiếm gặp: tác vụ tổng hợp dữ liệu hàng tháng, đợt siêu khuyến mãi, hoặc quá trình dựng lại bộ nhớ đệm (cache rebuild) ngay sau khi triển khai bản mới.
- Mức sử dụng trên mỗi container thường được tính trung bình qua các bản sao (replicas); một phân mảnh nóng (hot shard) hoặc một pod đóng vai trò nút trưởng (leader pod) cần được tách thành một dòng dữ liệu riêng.
- Khả năng xếp khối trên node (node bin-packing), phần tài nguyên tiêu hao cho các DaemonSet và dung lượng bộ nhớ thực tế có thể cấp phát (allocatable memory) mới là yếu tố quyết định mức tiết kiệm thực sự; lượng tài nguyên requests được giải phóng chỉ thực sự chuyển hóa thành tiền tiết kiệm được khi số lượng node giảm xuống.
FILE:references/rollout-and-guardrails.md
# Triển khai và Các Rào chắn An toàn (Rollout and Guardrails)

## Thứ tự thực hiện thay đổi
1. **Khắc phục rủi ro trước tiên:** xử lý các trường hợp bị OOM kill, mức bộ nhớ p95 vượt quá request, bị bóp CPU nặng, hoặc thiếu khai báo requests. Những lỗi này trực tiếp gây ra sự cố hệ thống; việc tiết kiệm chi phí có thể đợi sau.
2. **Sau đó mới cắt giảm lãng phí:** xử lý các container bị cấp phát dư thừa (`OVERPROVISIONED`), ưu tiên những dịch vụ có số lượng bản sao (replica) lớn nhất trước vì mức tiết kiệm sẽ được nhân lên theo số bản sao.
3. **Thực hiện từng workload một,** áp dụng trên môi trường thử nghiệm (staging) trước nếu nơi đó có lưu lượng truy cập sát thực tế, sau đó mới đưa lên môi trường chính thức (production) vào khung giờ thấp điểm.

## Các bước triển khai an toàn
1. Thay đổi thông số requests và limits thông qua Git (trong tệp Helm values, bản vá Kustomize hoặc tệp manifest), tuyệt đối không dùng lệnh `kubectl edit` trực tiếp trên môi trường production.
2. Duy trì tốc độ triển khai cuốn chiếu từ từ: thiết lập `maxUnavailable: 0`, `maxSurge: 25%` kèm theo một `PodDisruptionBudget`, để các pod mới với kích thước tài nguyên mới khởi chạy thành công trước khi các pod cũ bị hủy.
3. Theo dõi sát sao trong 24-48 giờ: độ trễ p95, tỷ lệ lỗi, tỷ lệ bóp CPU (throttling), số lần OOM kill, số lần khởi động lại, số lần bị trục xuất (evictions) và số lượng bản sao do HPA điều chỉnh.
4. Hoàn tác (Rollback) = đảo ngược lại bản commit (revert commit). Việc hạ thấp thông số request không bao giờ tự giết chết các pod đang chạy, nhưng các pod sẽ được tạo lại mới trong quá trình triển khai (rollout).

## Ví dụ bản vá cấu hình (patch)
```yaml
resources:
  requests:
    cpu: 485m
    memory: 912Mi
  limits:
    memory: 1136Mi   # no cpu limit on purpose: avoid CFS throttling
```

## Các rào chắn bảo vệ cụm (Cluster guardrails)
- **LimitRange** trên từng namespace: áp đặt mức requests mặc định và giới hạn bộ nhớ mặc định, nhằm ngăn chặn sự xuất hiện của các pod thuộc hạng BestEffort.
- **ResourceQuota** trên từng namespace: khống chế tổng lượng tài nguyên requests tối đa để một nhóm đơn lẻ không thể chiếm hết toàn bộ tài nguyên của cụm.
- **Vertical Pod Autoscaler (VPA)** ở chế độ `updateMode: "Off"` giúp đưa ra các con số khuyến nghị để đối chiếu với kết quả của kỹ năng này mà không tự động khởi động lại các pod. Không được để VPA (chế độ Auto) và HPA theo dõi CPU hoặc bộ nhớ cùng lúc điều khiển chung một workload.
- **Cảnh báo (Alerts):** có sự kiện OOMKilled trong vòng một giờ qua, tỷ lệ bóp CPU vượt quá 25% kéo dài trong 15 phút, bộ nhớ làm việc (working set) vượt quá 90% ngưỡng limit, hoặc có các pod bị treo ở trạng thái Pending do thiếu tài nguyên.

## Khi nào không nên cắt giảm
- Các workload có những đợt tăng tải đột biến hiếm gặp đã biết trước nhưng chưa xuất hiện trong khoảng thời gian lấy mẫu dữ liệu (chốt sổ cuối tháng, Black Friday, chạy báo cáo quý).
- Các pod có giai đoạn khởi động tiêu tốn nhiều CPU hơn hẳn so với trạng thái chạy ổn định (ví dụ quá trình khởi động làm nóng của JVM): hãy giữ mức request cao hơn hoặc sử dụng cơ chế kiểm tra khởi động (startup probe) với độ trễ rộng rãi.
- Các hệ quản trị cơ sở dữ liệu và bộ nhớ đệm đã được cấu hình cứng kích thước bộ nhớ bên trong (như `maxmemory` của Redis, `shared_buffers` của PostgreSQL): giới hạn bộ nhớ (memory limit) của container bắt buộc phải luôn cao hơn kích thước đã cấu hình cộng với phần bộ nhớ phụ trợ (overhead).
- Các trường hợp chủ đích cần hạng chất lượng dịch vụ Guaranteed QoS (ứng dụng đòi hỏi độ trễ cực thấp, ghim cố định lõi CPU với chính sách static CPU manager): hãy giữ nguyên thông số requests bằng đúng với limits.

## Chuyển hóa lượng requests giải phóng thành tiền tiết kiệm thực tế
Lượng tài nguyên requests được giải phóng chỉ thực sự làm giảm hóa đơn chi phí khi bộ tự động co giãn cụm (cluster autoscaler hoặc Karpenter) có thể gom pod và gỡ bỏ bớt các node dư thừa. Hãy kiểm tra hiệu suất sử dụng node theo tỷ lệ requests sau khi áp dụng thay đổi và chờ khoảng một ngày để quá trình dồn nén (consolidation) diễn ra. Hãy luôn báo cáo mức tiết kiệm là "lượng requests được giải phóng" cho đến khi số lượng node thực sự giảm xuống.
FILE:templates/rightsizing-plan.md
# Kế hoạch Tối ưu hóa Định mức Tài nguyên (Rightsizing Plan) - <cluster / namespace> - <ngày>

**Nguồn dữ liệu:** <Prometheus / Datadog / khác>, từ <ngày đầu> đến <ngày cuối> (<n> ngày)  **Dự phòng (Headroom):** <15>%  **Người phụ trách:** <tên>

## Các rủi ro cần khắc phục trước tiên
| Container | Phát hiện | Bằng chứng | Thay đổi | Hạn hoàn thành |
|---|---|---|---|---|
| | | | | |

## Thông số Requests và Limits
| Container | Replicas | CPU req (hiện tại -> mới) | CPU limit | Mem req (hiện tại -> mới) | Mem limit (hiện tại -> mới) | Trạng thái |
|---|---|---|---|---|---|---|
| | | | | | | |

## Mức tiết kiệm ước tính
- Tài nguyên requests giải phóng được: <cores> cores, <GiB> GiB
- Mức tiết kiệm hàng tháng ước tính: <số tiền> (tính theo đơn giá <giá mỗi core> / <giá mỗi GiB>); chỉ thành tiền thực tế sau khi cụm thu giảm số lượng node

## Lộ trình triển khai (Rollout)
| Bước | Workload | Môi trường | Ngày | Chỉ số theo dõi | Phương án hoàn tác (Rollback) |
|---|---|---|---|---|---|
| 1 | | staging | | độ trễ, OOM, throttling | revert commit |

## Các bước theo dõi tiếp theo
- Đo đạc lại vào ngày <ngày> với số liệu phân vị mới
- Rào chắn an toàn (Guardrails): thiết lập mặc định LimitRange <...>, cảnh báo <...>
FILE:examples/shop-cluster-usage.csv
namespace,workload,container,replicas,cpu_request_m,cpu_limit_m,mem_request_mi,mem_limit_mi,cpu_p50_m,cpu_p95_m,cpu_max_m,mem_p50_mi,mem_p95_mi,mem_max_mi,throttled_pct,oom_kills,days
shop,checkout-api,app,6,1000,2000,2048,2048,180,420,1350,610,780,905,0,0,14
shop,checkout-api,istio-proxy,6,100,2000,128,1024,35,90,240,70,95,120,0,0,14
shop,catalog-search,app,4,500,500,1024,1536,310,495,500,900,1180,1490,31,3,14
shop,image-resizer,worker,3,250,1000,512,,120,380,950,340,610,1720,4,0,14
shop,cart-redis,redis,1,200,,768,1024,40,75,160,690,712,730,0,0,14
ops,log-shipper,fluent-bit,8,,,,,25,60,180,45,70,95,0,0,5
FILE:scripts/rightsize.py
#!/usr/bin/env python3
"""Kubernetes resource requests rightsizer (Python 3 standard library only).

Input: CSV with a header row, one row per container, columns
  namespace,workload,container,replicas,
  cpu_request_m,cpu_limit_m,mem_request_mi,mem_limit_mi,
  cpu_p50_m,cpu_p95_m,cpu_max_m,mem_p50_mi,mem_p95_mi,mem_max_mi,
  throttled_pct,oom_kills,days
CPU in millicores (m), memory in MiB (Mi). Empty request/limit cells mean "not set".
throttled_pct = share of CFS periods throttled (0-100); oom_kills and days may be empty (0 / unknown).

Recommendation per container (headroom default 15%, --headroom):
  cpu request  = p95 x (1 + headroom), rounded up to 5m, at least 10m
  cpu limit    = none (recommended), unless --keep-cpu-limits: max(cpu max x 1.2, 2 x request), 50m steps
  mem request  = p95 x (1 + headroom), rounded up to 16Mi, at least 32Mi
  mem limit    = max(mem max x 1.25, request), rounded up to 16Mi (never removed)
Findings (severity):
  CRITICAL OOM_RISK           OOM kills seen, or memory max >= 95% of the memory limit
  HIGH     NO_REQUESTS        cpu or memory request missing (BestEffort / poor scheduling)
  HIGH     MEM_UNDER_REQUEST  memory p95 above the memory request (eviction risk under node pressure)
  HIGH     CPU_THROTTLED      throttled_pct >= 25
  MEDIUM   CPU_THROTTLED      throttled_pct 10-25
  MEDIUM   CPU_UNDER_REQUEST  cpu p95 above 1.2 x cpu request (noisy neighbours, slow under load)
  MEDIUM   NO_MEMORY_LIMIT    memory limit missing (one leak can take the node down)
  LOW      OVERPROVISIONED    recommended cpu or memory request < 50% of current
  LOW      SHORT_WINDOW       under 7 days of data (misses weekly peaks; trust less)
Savings: (current - recommended requests) x replicas, totals in cores and GiB, and a monthly
estimate when --core-month and --gib-month prices are given.
Usage:
  python3 rightsize.py usage.csv
  python3 rightsize.py usage.csv --headroom 25 --core-month 24 --gib-month 3.2 --json
  python3 rightsize.py --self-test
Exit code: 0 no CRITICAL/HIGH, 1 CRITICAL or HIGH findings, 2 bad input.
"""
import argparse
import csv
import io
import json
import math
import sys

COLUMNS = ("namespace", "workload", "container", "replicas", "cpu_request_m", "cpu_limit_m",
           "mem_request_mi", "mem_limit_mi", "cpu_p50_m", "cpu_p95_m", "cpu_max_m",
           "mem_p50_mi", "mem_p95_mi", "mem_max_mi", "throttled_pct", "oom_kills", "days")
OPTIONAL = {"cpu_request_m", "cpu_limit_m", "mem_request_mi", "mem_limit_mi", "throttled_pct", "oom_kills", "days"}
SEV_ORDER = {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2, "LOW": 3}


class DataError(ValueError):
    pass


def up(x, step):
    return int(math.ceil(x / step - 1e-9) * step)


def num(row, col, line):
    v = row.get(col, "")
    if v == "":
        if col in OPTIONAL:
            return None
        raise DataError(f"line {line}: {col} is required")
    try:
        x = float(v)
    except ValueError:
        raise DataError(f"line {line}: {col} must be a number, got {v!r}")
    if x < 0:
        raise DataError(f"line {line}: {col} must be >= 0")
    return x


def read_rows(text):
    rd = csv.DictReader(io.StringIO(text))
    if not rd.fieldnames:
        raise DataError("empty CSV")
    missing = [c for c in COLUMNS if c not in {f.strip() for f in rd.fieldnames}]
    if missing:
        raise DataError("CSV header is missing: " + ", ".join(missing))
    rows = []
    for n, raw in enumerate(rd, start=2):
        row = {k.strip(): (v or "").strip() for k, v in raw.items() if k}
        if not any(row.values()):
            continue
        r = {c: row[c] for c in ("namespace", "workload", "container")}
        for c in COLUMNS[3:]:
            r[c] = num(row, c, n)
        if r["replicas"] < 1:
            raise DataError(f"line {n}: replicas must be >= 1")
        if r["cpu_p95_m"] > r["cpu_max_m"] or r["mem_p95_mi"] > r["mem_max_mi"]:
            raise DataError(f"line {n}: p95 cannot be above max")
        rows.append(r)
    if not rows:
        raise DataError("no data rows")
    return rows


def analyze(r, headroom=0.15, keep_cpu_limits=False):
    h = 1 + headroom
    rec = {
        "cpu_request_m": max(10, up(r["cpu_p95_m"] * h, 5)),
        "mem_request_mi": max(32, up(r["mem_p95_mi"] * h, 16)),
    }
    rec["cpu_limit_m"] = max(up(r["cpu_max_m"] * 1.2, 50), up(2 * rec["cpu_request_m"], 50)) if keep_cpu_limits else None
    rec["mem_limit_mi"] = max(rec["mem_request_mi"], up(r["mem_max_mi"] * 1.25, 16))
    findings = []

    def f(sev, code, msg):
        findings.append({"severity": sev, "code": code, "message": msg})

    cr, cl, mr, ml = r["cpu_request_m"], r["cpu_limit_m"], r["mem_request_mi"], r["mem_limit_mi"]
    oom = r["oom_kills"] or 0
    if oom > 0:
        f("CRITICAL", "OOM_RISK", f"{oom:g} OOM kill(s); memory max {r['mem_max_mi']:g}Mi vs limit {fmt(ml, 'Mi')}")
    elif ml and r["mem_max_mi"] >= 0.95 * ml:
        f("CRITICAL", "OOM_RISK", f"memory max {r['mem_max_mi']:g}Mi is {r['mem_max_mi'] / ml:.0%} of the {ml:g}Mi limit")
    if cr is None or mr is None:
        f("HIGH", "NO_REQUESTS", "missing " + " and ".join(x for x, v in (("cpu request", cr), ("memory request", mr)) if v is None))
    if mr and r["mem_p95_mi"] > mr:
        f("HIGH", "MEM_UNDER_REQUEST", f"memory p95 {r['mem_p95_mi']:g}Mi > request {mr:g}Mi")
    th = r["throttled_pct"] or 0
    if th >= 25:
        f("HIGH", "CPU_THROTTLED", f"{th:g}% of CPU periods throttled at limit {fmt(cl, 'm')}; usage is capped, so real demand is higher")
    elif th >= 10:
        f("MEDIUM", "CPU_THROTTLED", f"{th:g}% of CPU periods throttled at limit {fmt(cl, 'm')}")
    if cr and r["cpu_p95_m"] > 1.2 * cr:
        f("MEDIUM", "CPU_UNDER_REQUEST", f"cpu p95 {r['cpu_p95_m']:g}m > 1.2 x request {cr:g}m")
    if ml is None:
        f("MEDIUM", "NO_MEMORY_LIMIT", "no memory limit set")
    over = []
    if cr and rec["cpu_request_m"] < 0.5 * cr:
        over.append(f"cpu {cr:g}m -> {rec['cpu_request_m']}m")
    if mr and rec["mem_request_mi"] < 0.5 * mr:
        over.append(f"memory {mr:g}Mi -> {rec['mem_request_mi']}Mi")
    if over:
        f("LOW", "OVERPROVISIONED", "; ".join(over))
    if r["days"] is not None and r["days"] < 7:
        f("LOW", "SHORT_WINDOW", f"only {r['days']:g} days of data")
    findings.sort(key=lambda x: SEV_ORDER[x["severity"]])
    status = findings[0]["severity"] if findings and findings[0]["severity"] != "LOW" else "OK"
    n = r["replicas"]
    d_cpu = ((cr or 0) - rec["cpu_request_m"]) * n
    d_mem = ((mr or 0) - rec["mem_request_mi"]) * n
    return {"id": f"{r['namespace']}/{r['workload']}/{r['container']}", "replicas": int(n), "current": {
        "cpu_request_m": cr, "cpu_limit_m": cl, "mem_request_mi": mr, "mem_limit_mi": ml},
        "recommended": rec, "delta_cpu_m": d_cpu, "delta_mem_mi": d_mem, "status": status, "findings": findings}


def run(text, headroom=0.15, keep_cpu_limits=False, core_month=None, gib_month=None):
    res = [analyze(r, headroom, keep_cpu_limits) for r in read_rows(text)]
    res.sort(key=lambda x: (SEV_ORDER.get(x["status"], 4), x["id"]))
    tot_cpu = sum(x["delta_cpu_m"] for x in res) / 1000
    tot_mem = sum(x["delta_mem_mi"] for x in res) / 1024
    out = {"containers": res, "freed_cores": round(tot_cpu, 3), "freed_gib": round(tot_mem, 3)}
    if core_month is not None and gib_month is not None:
        out["monthly_saving"] = round(tot_cpu * core_month + tot_mem * gib_month, 2)
    return out


def fmt(v, unit):
    return "none" if v is None else f"{v:g}{unit}"


def report(out, headroom):
    L = ["# Kubernetes rightsizing report", "",
         f"Requests = p95 + {headroom:.0%} headroom; CPU limits removed unless kept; memory limit = max x 1.25.", "",
         "| Container | Replicas | Status | CPU req | CPU limit | Mem req | Mem limit |",
         "|---|---|---|---|---|---|---|"]
    for x in out["containers"]:
        c, r = x["current"], x["recommended"]
        L.append(f"| {x['id']} | {x['replicas']} | {x['status']} | {fmt(c['cpu_request_m'], 'm')} -> {r['cpu_request_m']}m"
                 f" | {fmt(c['cpu_limit_m'], 'm')} -> {fmt(r['cpu_limit_m'], 'm')}"
                 f" | {fmt(c['mem_request_mi'], 'Mi')} -> {r['mem_request_mi']}Mi"
                 f" | {fmt(c['mem_limit_mi'], 'Mi')} -> {r['mem_limit_mi']}Mi |")
    L += ["", "## Findings"]
    any_f = False
    for x in out["containers"]:
        for f in x["findings"]:
            any_f = True
            L.append(f"- {f['severity']} {f['code']} {x['id']}: {f['message']}")
    if not any_f:
        L.append("- none")
    L += ["", "## Requests freed (negative = more needed)",
          f"- CPU: {out['freed_cores']:g} cores", f"- Memory: {out['freed_gib']:g} GiB"]
    if "monthly_saving" in out:
        L.append(f"- Estimated monthly saving: {out['monthly_saving']:,.2f}")
    return "\n".join(L) + "\n"


def self_test():
    cases = []

    def ok(name, cond):
        cases.append(bool(cond))
        print(("PASS " if cond else "FAIL ") + name)

    hdr = ",".join(COLUMNS) + "\n"

    def row(**kw):
        base = dict(namespace="ns", workload="w", container="c", replicas=1, cpu_request_m=500, cpu_limit_m=1000,
                    mem_request_mi=512, mem_limit_mi=1024, cpu_p50_m=100, cpu_p95_m=200, cpu_max_m=300,
                    mem_p50_mi=200, mem_p95_mi=300, mem_max_mi=400, throttled_pct=0, oom_kills=0, days=14)
        base.update(kw)
        return ",".join("" if base[c] is None else str(base[c]) for c in COLUMNS) + "\n"

    def one(**kw):
        return run(hdr + row(**kw))["containers"][0]

    def codes(x):
        return {(f["severity"], f["code"]) for f in x["findings"]}

    x = one()
    ok("cpu request = p95 x 1.15 rounded to 5m (230)", x["recommended"]["cpu_request_m"] == 230)
    ok("mem request = 300 x 1.15 = 345 -> 352Mi", x["recommended"]["mem_request_mi"] == 352)
    ok("mem limit = 400 x 1.25 = 500 -> 512Mi", x["recommended"]["mem_limit_mi"] == 512)
    ok("cpu limit removed by default", x["recommended"]["cpu_limit_m"] is None)
    ok("healthy container is OK", x["status"] == "OK")
    ok("headroom 0.25 changes cpu request (250)", run(hdr + row(), headroom=0.25)["containers"][0]["recommended"]["cpu_request_m"] == 250)
    k = run(hdr + row(), keep_cpu_limits=True)["containers"][0]["recommended"]["cpu_limit_m"]
    ok("kept cpu limit = max(360->400, 460->500) = 500", k == 500)
    ok("minimums 10m / 32Mi", one(cpu_p50_m=0, cpu_p95_m=1, cpu_max_m=2, mem_p50_mi=1, mem_p95_mi=2, mem_max_mi=3)["recommended"]
       == {"cpu_request_m": 10, "mem_request_mi": 32, "cpu_limit_m": None, "mem_limit_mi": 32})
    ok("OOM kills -> CRITICAL", ("CRITICAL", "OOM_RISK") in codes(one(oom_kills=2)) and one(oom_kills=2)["status"] == "CRITICAL")
    ok("max at 98% of limit -> OOM_RISK", ("CRITICAL", "OOM_RISK") in codes(one(mem_max_mi=1004, mem_p95_mi=500)))
    ok("missing requests -> HIGH NO_REQUESTS", ("HIGH", "NO_REQUESTS") in codes(one(cpu_request_m=None)))
    ok("mem p95 above request -> HIGH", ("HIGH", "MEM_UNDER_REQUEST") in codes(one(mem_request_mi=256)))
    ok("throttling 30% -> HIGH", ("HIGH", "CPU_THROTTLED") in codes(one(throttled_pct=30)))
    ok("throttling 12% -> MEDIUM", ("MEDIUM", "CPU_THROTTLED") in codes(one(throttled_pct=12)))
    ok("cpu p95 > 1.2 x request -> MEDIUM", ("MEDIUM", "CPU_UNDER_REQUEST") in codes(one(cpu_request_m=150)))
    ok("no memory limit -> MEDIUM", ("MEDIUM", "NO_MEMORY_LIMIT") in codes(one(mem_limit_mi=None)))
    big = one(cpu_request_m=2000, mem_request_mi=4096)
    ok("overprovisioned flagged LOW, status stays OK", ("LOW", "OVERPROVISIONED") in codes(big) and big["status"] == "OK")
    ok("short window flagged", ("LOW", "SHORT_WINDOW") in codes(one(days=3)))
    two = run(hdr + row(replicas=3) + row(workload="b", replicas=2, cpu_request_m=100, mem_request_mi=256),
              core_month=20, gib_month=4)
    # w: (500-230)*3=810m, (512-352)*3=480Mi ; b: (100-230)*2=-260m, (256-352)*2=-192Mi
    ok("freed cores = (810-260)/1000 = 0.55", two["freed_cores"] == 0.55)
    ok("freed GiB = (480-192)/1024 = 0.281", two["freed_gib"] == 0.281)
    ok("monthly saving = 0.55 x 20 + 0.28125 x 4 = 12.125", abs(two["monthly_saving"] - 12.125) < 0.01)
    ok("sorted by severity", two["containers"][0]["id"] == "ns/b/c")
    for bad, label in (("a,b\n1,2\n", "missing columns"), (hdr, "no rows"), (hdr + row(cpu_p95_m="x"), "bad number"),
                       (hdr + row(cpu_p95_m=900), "p95 above max"), (hdr + row(replicas=0), "zero replicas"),
                       (hdr + row(cpu_p95_m=None), "missing usage")):
        try:
            run(bad)
            ok(label + " rejected", False)
        except DataError:
            ok(label + " rejected", True)
    print(f"{sum(cases)}/{len(cases)} passed")
    return 0 if all(cases) else 1


def main(argv=None):
    ap = argparse.ArgumentParser(description="Rightsize Kubernetes container requests and limits from usage percentiles.")
    ap.add_argument("file", nargs="?", help="CSV with the columns listed in the module docstring")
    ap.add_argument("--headroom", type=float, default=15, help="percent added to p95 for requests (default 15)")
    ap.add_argument("--keep-cpu-limits", action="store_true", help="recommend CPU limits instead of removing them")
    ap.add_argument("--core-month", type=float, help="price of one requested core per month")
    ap.add_argument("--gib-month", type=float, help="price of one requested GiB of memory per month")
    ap.add_argument("--json", action="store_true")
    ap.add_argument("--self-test", action="store_true")
    a = ap.parse_args(argv)
    if a.self_test:
        return self_test()
    if not a.file:
        ap.error("give a CSV file or --self-test")
    try:
        out = run(open(a.file, encoding="utf-8").read(), a.headroom / 100, a.keep_cpu_limits, a.core_month, a.gib_month)
    except (OSError, DataError) as e:
        print(f"error: {e}", file=sys.stderr)
        return 2
    print(json.dumps(out, indent=2) if a.json else report(out, a.headroom / 100), end="\n" if a.json else "")
    return 1 if any(x["status"] in ("CRITICAL", "HIGH") for x in out["containers"]) else 0


if __name__ == "__main__":
    sys.exit(main())
PythonDevOpsCloud+2
F@f
0
Hàm Serverless taste
Văn bản

Các quy ước giàu tính định hướng để xây dựng những hàm serverless đáng tin cậy, tối ưu chi phí trên đám mây.

# Gu thiết kế (taste) Hàm Serverless của một kỹ sư backend đám mây
- Giữ cho mỗi hàm nhỏ gọn và tập trung vào một tác nhân kích hoạt (trigger) duy nhất, nhưng hãy gom các route HTTP có liên quan mật thiết vào chung một handler để cắt giảm tình trạng khởi động lạnh (cold starts). Độ tin cậy: 0.80
- Khởi tạo các SDK client và nhóm kết nối cơ sở dữ liệu (database pools) bên ngoài hàm handler để các lần gọi ấm (warm invocations) có thể tái sử dụng chúng. Độ tin cậy: 0.95
- Sử dụng bộ quản lý nhóm kết nối (connection pooler) hoặc trình điều khiển cơ sở dữ liệu dựa trên HTTP, vì hàng nghìn hàm chạy đồng thời sẽ làm cạn kiệt các kết nối Postgres trực tiếp. Độ tin cậy: 0.90
- Thiết lập thời gian chờ (timeout) và dung lượng bộ nhớ tường minh cho từng hàm thay vì chấp nhận các giá trị mặc định của nền tảng. Độ tin cậy: 0.85
- Giữ kích thước gói mã (bundle) nhỏ gọn bằng kỹ thuật loại bỏ mã thừa (tree-shaking) và nạp trễ (lazy imports), đồng thời đo lường thời gian khởi động lạnh sau mỗi thay đổi thư viện phụ thuộc lớn. Độ tin cậy: 0.85
- Đảm bảo mọi hàm xử lý sự kiện đều có tính lũy đẳng (idempotent), bởi vì các hàng đợi và nguồn phát sự kiện luôn phân phối theo cơ chế ít nhất một lần (at-least-once). Độ tin cậy: 0.95
- Chuyển các tác vụ chạy chậm hoặc cần thử lại sang hàng đợi (queue) và trả kết quả về nhanh chóng từ các hàm HTTP. Độ tin cậy: 0.90
- Đẩy các sự kiện bất đồng bộ bị lỗi vào hàng đợi thư chết (dead letter queue - DLQ) kèm theo cảnh báo dựa trên độ sâu (số lượng tồn đọng) của hàng đợi đó. Độ tin cậy: 0.90
- Định nghĩa các hàm, quyền hạn và tác nhân kích hoạt dưới dạng mã (Infrastructure as Code) bằng SST, Serverless Framework, SAM hoặc Terraform, tuyệt đối không bấm chọn thủ công trên giao diện điều khiển (console). Độ tin cậy: 0.90
- Cấp cho mỗi hàm một vai trò (role) riêng theo nguyên tắc đặc quyền tối thiểu, giới hạn phạm vi chính xác vào những tài nguyên mà hàm đó chạm tới. Độ tin cậy: 0.95
- Nạp các thông tin bí mật (secrets) từ trình quản lý bí mật (secrets manager) hoặc biến môi trường được mã hóa của nền tảng, tuyệt đối không lấy từ kho mã nguồn (repo). Độ tin cậy: 0.95
- Ghi nhật ký (logs) định dạng JSON có cấu trúc kèm theo request ID và correlation ID trên mọi dòng. Độ tin cậy: 0.90
- Truy vết (trace) các yêu cầu xuyên qua các hàm và hàng đợi bằng OpenTelemetry hoặc công cụ truy vết có sẵn của nền tảng. Độ tin cậy: 0.80
- Giữ logic nghiệp vụ trong các module thuần túy và chỉ để hàm handler đóng vai trò một lớp chuyển đổi (adapter) mỏng, nhờ đó có thể kiểm thử đơn vị (unit test) mà không cần tới môi trường đám mây. Độ tin cậy: 0.90
- Chạy kiểm thử tích hợp (integration tests) trên một môi trường triển khai (stage) thực tế cho mỗi pull request thay vì đặt niềm tin vào các trình giả lập cục bộ. Độ tin cậy: 0.80
- Thiết lập mức độ đồng thời dành riêng hoặc tối đa (reserved or maximum concurrency) trên các hàm gọi tới những dịch vụ hạ nguồn mỏng manh, dễ quá tải. Độ tin cậy: 0.85
- Chỉ sử dụng mức độ đồng thời được cấp phát sẵn (provisioned concurrency) cho các luồng xử lý nhạy cảm về độ trễ nơi mà quá trình khởi động lạnh đã được đo đạc và chứng minh là gây ảnh hưởng xấu. Độ tin cậy: 0.75
- Ưu tiên môi trường thực thi arm64 khi các thư viện phụ thuộc hỗ trợ để đạt tỷ lệ hiệu năng trên giá thành tốt hơn. Độ tin cậy: 0.70
- Thiết lập cảnh báo hóa đơn thanh toán và bảng theo dõi chi phí theo từng hàm trước khi ra mắt, chứ không phải đợi đến sau tờ hóa đơn gây sốc đầu tiên. Độ tin cậy: 0.85
- Tránh nối chuỗi các hàm gọi nhau một cách đồng bộ; thay vào đó hãy dùng sự kiện hoặc một bộ điều phối luồng công việc (workflow engine) như Step Functions. Độ tin cậy: 0.85
- Lựa chọn container hoặc các dịch vụ chạy liên tục dài hạn cho các khối lượng công việc có thông lượng cao và ổn định, nơi mà mô hình serverless trở nên đắt đỏ hơn. Độ tin cậy: 0.75
BackendBest PracticesDevOps+1
F@f
0