Kubernetes Từ Số Không
Dựng một cluster Kubernetes hoàn chỉnh bằng tay — không kubeadm, không script — từ certificate đầu tiên tới một cluster HA chạy thật, rồi dùng chính nó làm phòng thí nghiệm để deep-dive toàn bộ concept của Kubernetes. Phần một: PKI/TLS, etcd, control plane, worker, mạng pod, CoreDNS. Phần hai: Pods, workload controllers, scheduling, storage, networking nâng cao (Cilium eBPF), bảo mật, mở rộng API, vận hành. Mỗi thành phần vừa được giải thích cơ chế bên trong, vừa tự dựng/cấu hình tay. Test thật trên AWS EC2 với Kubernetes v1.36, manifest/script lưu tại github.com/nghiadaulau/kubernetes-from-scratch. Bám docs chính thức kubernetes.io.
Ingress: Đưa HTTP Từ Ngoài Vào (Bằng Cilium)
NetworkPolicy lo lưu lượng pod-với-pod ở trong. Bài này mở mép cluster cho HTTP từ ngoài vào, định tuyến theo host và path tới đúng Service — bằng Ingress controller có sẵn của Cilium, không cài thêm phần mềm. Quan trọng không kém phần kỹ thuật là một quyết định thật: Ingress NGINX đã bị khai tử tháng 3/2026 và API Ingress đã đóng băng, nên ta chọn controller đang được bảo trì và soi cách Cilium dịch một Ingress thành cấu hình Envoy chạy trên eBPF.
Gateway API: Kế Nhiệm Của Ingress
Ingress đóng băng ở những tính năng cơ bản. Gateway API là API mới của Kubernetes cho lưu lượng vào, tách vai trò hạ tầng và ứng dụng thành các object riêng, và làm được những thứ Ingress không làm: chia lưu lượng theo trọng số, khớp theo header, định tuyến nhiều giao thức. Bài này bật Gateway API trên Cilium, dựng một Gateway với HTTPRoute định tuyến theo host/path, rồi chia traffic 80/20 giữa hai phiên bản — test thật trên cụm EC2.
LB IPAM và Traffic Policy
Bài 48 và 49 đều dừng ở chỗ Service LoadBalancer và Gateway treo external-IP <pending> — cụm tự dựng không có ai cấp địa chỉ. Bài này lấp chỗ đó bằng LB IPAM của Cilium: định nghĩa một dải IP, để Cilium gán cho Service, và Gateway của bài trước chuyển sang Programmed=True. Sau đó là externalTrafficPolicy — Cluster hay Local quyết định địa chỉ nguồn của client còn nguyên hay bị thay. Test thật trên cụm EC2, kèm phần nói rõ ranh giới giữa cấp IP và quảng bá IP.
Authentication và Đường Vào API Server
Mỗi lệnh kubectl là một request HTTPS tới API server, và trước khi chạm được dữ liệu nó phải qua ba chặng: authentication, authorization, admission. Bài này mở Part XI bằng chặng đầu — API server nhận ra bạn là ai. Ta soi ba cách cụm tự dựng chứng thực một request: client certificate (cái admin.kubeconfig đang dùng), token của ServiceAccount, và request ẩn danh — bằng kubectl auth whoami và lệnh thật trên cụm.
RBAC: Biến Danh Tính Thành Quyền
Bài 51 dừng ở chỗ API server biết bạn là ai. RBAC trả lời câu còn lại: bạn được làm gì. Bài này dựng một ServiceAccount chỉ đọc được pod trong một namespace, kiểm chứng bằng kubectl auth can-i lẫn token thật — thấy nó list pod được nhưng đọc secret hay tạo pod thì bị 403. Rồi xem cách một RoleBinding trỏ vào ClusterRole có sẵn để cấp quyền gói gọn trong một namespace, và vì sao ClusterRole view cố tình không cho đọc secret.
ServiceAccount và Bound Token
Bài 51–52 dùng ServiceAccount mà chưa mổ nó. Bài này đi vào cơ chế: mỗi namespace có một SA default, kubelet tự tiêm vào pod một token ngắn hạn qua projected volume, và token đó bound vào đúng pod lẫn node. Để chứng minh là bound thật, ta lấy token trong một pod đang chạy, gọi API thành công, rồi xóa pod — token cũ lập tức thành 401. Kèm cách tắt auto-mount và đọc các claim trong JWT.
Pod Security Standards và Admission
RBAC quyết ai được tạo pod, nhưng không xét pod đó xin gì. Một pod chạy privileged hay mượn hostNetwork là cửa thoát ra node. Pod Security Admission chặn ngay từ lúc tạo: gắn một nhãn lên namespace, API server đo pod theo ba mức privileged/baseline/restricted và từ chối pod vi phạm. Bài này bật restricted lên một namespace, xem pod thường bị đá ra với danh sách lỗi, viết một pod tuân thủ cho chạy được, rồi thử chế độ warn chỉ cảnh báo.
Seccomp, AppArmor và Capabilities
Bài 54 bắt pod khai runAsNonRoot, drop ALL capabilities, seccomp RuntimeDefault — nhưng đó mới là chính sách ở mức Kubernetes. Bài này xuống tầng kernel xem chúng làm gì thật: đọc /proc/self/status của hai pod, một mặc định một đã siết, so từng dòng CapEff, Seccomp, NoNewPrivs, AppArmor. Rồi chứng minh bằng tay rằng drop một capability chặn được thao tác cụ thể — chown bị từ chối ngay cả khi container vẫn chạy bằng root.
Secret, Lối Vòng và Hardening
Part XI khép lại ở Secret và những lỗ hổng còn sót. Ta đọc thẳng etcd để xác nhận Secret được mã hóa at-rest từ Bài 5, rồi dựng một lối vòng thật: một ServiceAccount không có quyền đọc Secret vẫn moi được giá trị bằng cách tạo một pod mount Secret đó và đọc log. Cuối bài là bảng các bước siết cụm tự dựng — cái nào đã làm trong series, cái nào còn thiếu.
CustomResourceDefinition: Thêm Kiểu Của Riêng Bạn
Part XII chuyển từ dùng Kubernetes sang mở rộng nó. Bài đầu là CustomResourceDefinition — khai một kiểu object mới, và API server lập tức phục vụ nó như resource gốc: kubectl get được, validate theo schema, lưu trong etcd. Ta dựng một CRD Widget có ràng buộc kiểu và miền giá trị, tạo custom resource hợp lệ, xem hai cái sai bị từ chối, rồi cập nhật status qua subresource riêng.
Admission Webhook: Chen Vào Đường Ghi
Bài 54 dùng admission có sẵn (Pod Security). Bài này tự viết một admission của riêng mình: một dịch vụ HTTPS mà API server gọi tới trước khi lưu mỗi object, trả về cho hay không cho. Ta dựng một validating webhook thật bằng Python — tự ký cert cho service, để API server tin qua caBundle, và bắt mọi pod phải có label team. Pod thiếu label bị API server từ chối ngay; pod ở namespace ngoài phạm vi thì không bị đụng.
Operator: CRD Cộng Vòng Lặp Reconcile
CRD cho ta một kiểu dữ liệu mới, nhưng tạo một custom resource thì chưa có gì xảy ra. Operator ghép CRD với một controller chạy vòng lặp: theo dõi custom resource và hành động để đưa thực tế về khớp mong muốn. Bài này dựng một operator thật từ đầu — một CRD Echo và một controller chạy trong pod — rồi xem nó tự tạo Deployment khi ta tạo Echo, tự scale khi ta sửa replicas, và để Deployment bị dọn khi ta xóa Echo.