Kubernetes cho Frontend Developer · Phần 1 — Vì sao FE dev nên học K8s, bức tranh tổng thể và lộ trình 19 phần
Mở đầu series: FE dev học Kubernetes để làm gì và học tới đâu là đủ, hành trình từ npm run build tới URL production qua 9 chặng, từ điển thuật ngữ cấp tốc, cách học và lộ trình 19 phần.
Là frontend developer, vòng đời công việc của bạn thường dừng ở git push. Sau đó là một “vùng tối”: trang trắng trên production nhưng chạy tốt ở local, VITE_API_URL trỏ sai mà không biết vì sao, F5 ở route /users/123 thì ra 404 trong khi bấm link nội bộ thì chạy. Những câu hỏi đó không phải câu hỏi frontend. Chúng là câu hỏi hạ tầng, và trong đa số công ty hiện đại, hạ tầng đó chính là Kubernetes.
Series này viết cho React / Vue / Angular / Next.js developer chưa từng làm việc với server, Docker hay Linux chuyên sâu. Mọi khái niệm hạ tầng được giải thích lại từ đầu, kèm phép so sánh với thứ bạn đã quen: npm, webpack, package.json, localhost:3000. Phần 1 lo phần định vị: bạn đang học cái gì, vì sao, học tới đâu là đủ, và toàn cảnh hành trình của code từ npm run build tới URL production. Từ phần 2 trở đi ta mới gõ lệnh.
Thuật ngữ kỹ thuật giữ nguyên tiếng Anh (Pod, Deployment, Service, Ingress, probe, rollout, registry, reconciliation) vì đó là từ bạn sẽ gõ trong terminal, đọc trong manifest và nghe đồng nghiệp DevOps nói. Phần dịch là phần giải thích.
Lộ trình 19 phần
| Phần | Chủ đề | Nguồn gốc |
|---|---|---|
| 1 | Vì sao FE dev nên học K8s, bức tranh tổng thể, từ điển và lộ trình | Hướng dẫn + Bài 0.1–0.3 |
| 2 | Linux, terminal và mạng máy tính cho FE | Bài 1.1–1.2 |
| 3 | YAML trong 20 phút và container là gì | Bài 1.3–1.4 |
| 4 | Dockerfile chuẩn cho frontend, registry và Docker Compose | Bài 1.5–1.7 |
| 5 | K8s là gì, kiến trúc cluster, cluster local và kubectl | Bài 2.1–2.4 |
| 6 | Pod, ReplicaSet, Deployment, label và namespace | Bài 2.5–2.7 |
| 7 | Service và Ingress | Bài 2.8–2.9 |
| 8 | ConfigMap, Secret và health check probe | Bài 2.10–2.11 |
| 9 | Resources, QoS, storage và vòng đời Pod | Bài 2.12–2.14 |
| 10 | Biến môi trường build-time vs runtime và deploy React SPA từ A đến Z | Bài 3.1–3.2 |
| 11 | Deploy Next.js SSR, nhiều app trên một domain và micro-frontend | Bài 3.3–3.4 |
| 12 | Cache, nén, CDN đứng trước cluster và zero-downtime deploy | Bài 3.5–3.6 |
| 13 | Sổ tay debug: 12 lỗi thường gặp | Bài 3.7 |
| 14 | Chiến lược rollout và autoscaling | Bài 4.1–4.2 |
| 15 | Helm và Kustomize | Bài 4.3–4.4 |
| 16 | CI/CD với GitHub Actions và GitOps với ArgoCD | Bài 4.5–4.6 |
| 17 | HTTPS tự động với cert-manager và observability | Bài 4.7–4.8 |
| 18 | Bảo mật cơ bản, chi phí và khi nào không nên dùng K8s | Bài 4.9–4.10 |
| 19 | Thời khoá biểu 6 tuần, checklist, đồ án và cheat sheet | Phần 5 |
Cách đọc series này:
- Phần 1–4 là nền tảng bắt buộc, đọc tuần tự và đừng bỏ. 80% người học K8s thất bại không phải vì K8s khó, mà vì không hiểu container, port và DNS. Nếu bạn chưa từng viết Dockerfile, tuyệt đối đừng nhảy sang phần 5.
- Phần 5–9 là Kubernetes core, mỗi phần xây trên phần trước: kiến trúc → Pod và Deployment → Service và Ingress → ConfigMap và probe → resources và vòng đời Pod. Đọc theo thứ tự.
- Phần 10–13 là chặng deploy thực tế. Phần 10 (biến môi trường build-time vs runtime) là bài quan trọng nhất của cả series đối với FE dev; phần 13 (sổ tay debug) là bài bạn sẽ mở lại nhiều nhất.
- Phần 14–18 là nâng cao, nhảy cóc theo nhu cầu: cần đóng gói nhiều môi trường thì đọc 15, cần pipeline thì đọc 16, cần HTTPS thật thì đọc 17.
- Phần 19 là thời khoá biểu, checklist tự đánh giá và đồ án. Đọc lướt nó ngay từ đầu để biết đích đến trông thế nào.
Nếu bạn chỉ có 2 tuần: đọc phần 2–4 (bỏ mục Docker Compose), phần 5–8, phần 10 và phần 13. Bỏ qua chặng nâng cao, quay lại sau khi đã dùng K8s thực tế vài tuần.
Hướng dẫn sử dụng tài liệu
Cách học hiệu quả nhất
- Đọc, gõ, phá, sửa. Đừng copy/paste. Hãy gõ tay từng lệnh. Sau khi chạy được, cố tình làm sai (đổi tên image, xoá Service, bỏ một dòng trong nginx.conf) để xem lỗi trông như thế nào. Kinh nghiệm debug đến từ việc đã nhìn thấy lỗi đó một lần; lần thứ hai gặp lại trên production, bạn nhận ra nó trong 10 giây thay vì 2 giờ.
- Mỗi phần đều có mục Thực hành. Không làm thực hành thì coi như chưa học phần đó. Kiến thức K8s không nằm ở việc nhớ cú pháp YAML, mà ở phản xạ khi thấy
CrashLoopBackOfflà gõ ngaykubectl logs --previous. - Không nhảy cóc chặng nền tảng. Kubernetes chỉ là công cụ điều phối container. Không hiểu container thì không hiểu K8s, và mọi lỗi “lạ” về sau thực ra là lỗi về port, DNS hoặc filesystem của container.
- Chấp nhận không hiểu hết. Kubernetes có hơn 60 loại tài nguyên. Frontend dev thực tế chỉ dùng khoảng 10 loại: Namespace, Pod, Deployment, Service, Ingress, ConfigMap, Secret, HorizontalPodAutoscaler, PodDisruptionBudget và vài thứ quanh chúng. Series này tập trung vào đúng 10 loại đó.
Ký hiệu trong series
Nguồn gốc của series là một tài liệu 52 trang dùng năm loại ký hiệu. Trong bài viết, chúng trở thành các khối sau:
| Ký hiệu | Nghĩa |
|---|---|
| Ghi chú | Giải thích thêm, mẹo, liên hệ với kiến thức frontend bạn đã biết. |
| Thực hành (mục riêng) | Bắt buộc gõ tay. Đây là phần tạo ra kỹ năng thật. |
| Cạm bẫy | Lỗi mà gần như 100% người mới đều mắc phải. |
| Nguy hiểm | Có thể gây downtime hoặc lộ bảo mật trên production. |
| Kết quả mong đợi | Sau bước này bạn phải thấy đúng cái này; nếu không thì dừng lại debug, đừng đi tiếp. |
Ví dụ, đây là dạng bạn sẽ gặp:
Cạm bẫy: cú pháp
-p 8080:80là cổng-máy-thật : cổng-trong-container. Nhớ sai thứ tự là lỗi phổ biến nhất của người mới.
Cần chuẩn bị gì
- Máy tính có ít nhất 8GB RAM (16GB thì thoải mái), còn trống khoảng 20GB ổ cứng. Một cluster kind 3 node cộng Docker Desktop ăn khoảng 3–4GB RAM khi rảnh; nếu máy 8GB, hãy đóng bớt tab trình duyệt và tăng RAM cấp cho Docker Desktop trong Settings → Resources.
- macOS, Linux hoặc Windows kèm WSL2. Windows thuần rất khổ (đường dẫn, quyền file, script shell), hãy cài WSL2 và làm toàn bộ series bên trong Ubuntu của WSL.
- Đã cài Node.js và biết chạy
npm run build. Bạn sẽ dùng chính app của mình làm vật thí nghiệm, nên hãy chọn một app Vite hoặc Next.js nhỏ, build được sạch. - Một tài khoản GitHub. Nó dùng cho GitHub Container Registry (nơi cất image, phần 4) và GitHub Actions (CI/CD, phần 16).
- Tuỳ chọn: 5–10 USD để thuê VPS hoặc cluster thật ở tuần cuối. Không bắt buộc.
Ghi chú: toàn bộ phần 2 đến phần 18 học hoàn toàn miễn phí trên máy local bằng kind. Bạn không cần thuê cloud để học. Cluster thật chỉ khác ở chỗ có IP public và LoadBalancer do cloud cấp; mọi khái niệm còn lại giống hệt.
Vì sao FE dev nên học K8s và học tới đâu là đủ
Vấn đề thực tế bạn đang gặp
Hãy nhớ lại lần gần nhất bạn deploy xong và có người báo lỗi:
- “Trang trắng trên production, ở local chạy bình thường.” Bạn mở console thấy 404 cho
main-a1b2c3.js. Ai đó nói “chắc do cache”. Bạn không biết cache ở đâu, của ai, xoá thế nào. - “App gọi API staging trên production.” Bạn chắc chắn đã set
VITE_API_URLđúng trong ConfigMap. Nhưng bundle vẫn gọi staging. Hoá ra biến Vite được nhúng lúc build, và ConfigMap chỉ tác động tới tiến trình nginx. - “F5 ở
/users/123ra 404, bấm link nội bộ thì vào được.” Đây là lỗi cấu hình reverse proxy, không phải lỗi React Router. - “Probe đang fail nên Pod không nhận traffic.” Bạn gật đầu nhưng không hiểu probe là gì và vì sao nó liên quan tới trang của bạn.
Bốn tình huống này lặp lại ở gần như mọi team. Điểm chung: FE dev là người thấy triệu chứng đầu tiên, nhưng không có ngôn ngữ để mô tả và không có quyền để tự kiểm tra. Học K8s là học ngôn ngữ đó.
Học K8s mang lại gì cho một FE dev
| Khả năng | Ý nghĩa thực tế |
|---|---|
| Tự deploy app của mình | Không phải chờ DevOps rảnh. Tự tạo môi trường staging cho QA test, tự dựng preview cho một branch. |
| Tự debug lỗi production | Đọc log, vào trong container, kiểm tra biến môi trường mà không cần nhờ ai. |
| Hiểu kiến trúc hệ thống | Biết request đi từ trình duyệt qua những lớp nào tới code của mình, và mỗi lớp có thể hỏng ra sao. |
| Nói chuyện được với backend/DevOps | Hiểu “Service đó là ClusterIP” hay “probe đang fail” nghĩa là gì, và hỏi đúng câu hỏi. |
| Mở đường lên Senior / Fullstack | Đây là khác biệt rõ nhất giữa mid-level và senior FE trong JD tuyển dụng. |
Ranh giới: học tới đâu là đủ
Bạn không cần trở thành SRE. Hãy phân biệt rõ hai cột này và đừng cảm thấy có lỗi khi không biết cột bên phải:
| FE dev CẦN thành thạo | FE dev KHÔNG cần (để DevOps lo) |
|---|---|
| Pod, Deployment, Service, Ingress | etcd backup, cluster upgrade |
| ConfigMap, Secret | CNI plugin (Calico, Cilium) nội bộ |
| Probes, resources, HPA | Thiết kế network policy toàn cluster |
| Đọc log, exec vào Pod, debug | Vận hành StatefulSet cho database |
| Viết Dockerfile tối ưu | Tuning kernel, storage class, CSI driver |
| Helm/Kustomize ở mức sử dụng | Viết Operator, CRD, controller |
Ghi chú: series này dạy đúng cột bên trái, cộng thêm vừa đủ cột bên phải để bạn hiểu đồng nghiệp đang nói gì. Khi thấy một từ lạ trong cuộc họp (taint, CNI, CSI), bạn chỉ cần biết nó thuộc cột nào để quyết định có cần tìm hiểu thêm hay không.
Một cách kiểm tra đơn giản xem bạn đã “đủ” chưa: mở file Deployment mà team DevOps viết cho app của bạn. Nếu bạn đọc hiểu từng dòng, biết vì sao có readinessProbe, biết targetPort phải khớp cái gì, và tự trả lời được câu “vì sao cột READY là 0/1”, bạn đã ở mức đủ. Đó là đích của phần 5–9.
Bức tranh tổng thể: từ npm run build đến URL production
Trước khi đi vào chi tiết, hãy nắm toàn cảnh. Đây là hành trình của code frontend, chín chặng, từ file .tsx tới trình duyệt người dùng:
[1] Code của bạn src/App.tsx, package.json
|
v npm run build
[2] Static files dist/index.html, dist/assets/main-a1b2c3.js
|
v docker build
[3] Docker image my-app:v1.2.0 (nginx + dist bên trong)
|
v docker push
[4] Registry ghcr.io/cong-ty/my-app:v1.2.0
|
v kubectl apply -f deployment.yaml
[5] Kubernetes Deployment "Tôi muốn 3 bản sao của image này luôn chạy"
|
v K8s tự tạo
[6] Pod x3 3 container nginx đang chạy, mỗi cái 1 IP riêng
|
v Service gom lại
[7] Service 1 địa chỉ nội bộ ổn định: my-app-svc:80
|
v Ingress route
[8] Ingress app.congty.com -> my-app-svc:80
|
v
[9] Trình duyệt người dùng
Chặng 1–2 bạn đã làm hằng ngày. Chặng 3–4 là Docker (phần 3–4 của series). Chặng 5–8 là Kubernetes (phần 5–9). Mọi lỗi “vùng tối” ở đầu bài đều nằm ở một chặng cụ thể: cache index.html là chuyện của chặng 8 và CDN đứng trước nó; VITE_API_URL sai là chuyện của chặng 2 (giá trị bị đóng băng lúc build); 404 khi F5 là chuyện của nginx bên trong chặng 3.
Giải thích từng chặng bằng ngôn ngữ frontend
| Chặng | Ví von với thứ bạn đã biết |
|---|---|
| Image | Giống một file .zip chứa cả hệ điều hành mini + nginx + thư mục dist. Bất biến, có version. |
| Registry | Giống npm registry, nhưng chứa image thay vì package. docker push tương đương npm publish. |
| Container | Giống khi bạn npm start: biến file tĩnh thành tiến trình đang chạy. |
| Pod | Một “hộp” chứa 1 (hoặc vài) container, có IP riêng. Đơn vị mà K8s quản lý. |
| Deployment | Giống package.json khai báo phiên bản mong muốn. Bạn nói “tôi muốn 3 bản”, K8s lo phần còn lại. |
| Service | Giống một biến DNS nội bộ. Pod chết/sinh liên tục, IP đổi liên tục; Service cho bạn một tên cố định. |
| Ingress | Giống cấu hình server.proxy trong vite.config.ts nhưng ở tầng production: ánh xạ domain/path vào Service. |
Nếu bạn từng viết đoạn này trong vite.config.ts để tránh CORS lúc dev:
export default defineConfig({
server: {
proxy: {
'/api': 'http://localhost:3000',
},
},
});
thì bạn đã hiểu Ingress ở mức ý tưởng. Ingress làm đúng việc đó cho app.congty.com/api → backend-svc:3000 trên production, bằng YAML thay vì TypeScript. Phần 7 đi vào chi tiết.
Triết lý cốt lõi cần nhớ suốt series
Kubernetes hoạt động theo mô hình declarative (khai báo). Bạn mô tả trạng thái mong muốn (“3 bản sao của image v1.2.0”), K8s liên tục so sánh với thực tế và tự sửa cho khớp. Bạn không ra lệnh “hãy khởi động server”, đó là imperative, tư duy cũ.
Hãy nghĩ như React. Bạn không gọi document.createElement rồi appendChild; bạn khai báo UI mong muốn theo state, React tự diff và patch DOM. K8s cũng vậy: bạn khai báo spec, controller tự diff với status và patch cluster.
| React | Kubernetes |
|---|---|
state là nguồn sự thật | spec trong manifest là nguồn sự thật |
| Virtual DOM diff với DOM thật | Controller diff spec với status thật |
| Render lại khi state đổi | Reconcile lại khi spec đổi hoặc thực tế lệch |
| Bạn không đụng DOM trực tiếp | Bạn không docker run trực tiếp trên node |
setState rồi để React lo | kubectl apply rồi để controller lo |
Hệ quả thực tế của mô hình này, thứ bạn sẽ thấy tận mắt ở phần 5: xoá một Pod bằng tay, vài giây sau K8s tạo lại Pod mới, vì thực tế (2 Pod) lệch với khai báo (3 Pod). Bạn không làm gì cả. Đây là khác biệt cơ bản giữa K8s và docker run, và cũng là lý do kubectl edit trực tiếp trên production là ý tưởng tồi: lần kubectl apply sau từ Git sẽ âm thầm ghi đè thay đổi tay của bạn.
Từ điển thuật ngữ cấp tốc
Đọc lướt bảng này một lần, không cần nhớ. Bạn sẽ quay lại tra khi gặp từ lạ ở các phần sau.
| Thuật ngữ | Nghĩa ngắn gọn |
|---|---|
| Cluster | Toàn bộ hệ thống K8s: gồm nhiều máy chủ hoạt động như một. |
| Node | Một máy chủ (vật lý hoặc ảo) trong cluster. |
| Control Plane | ”Bộ não” điều phối cluster: nhận lệnh, lưu trạng thái, quyết định Pod chạy ở đâu. |
| Pod | Đơn vị chạy nhỏ nhất, bọc 1 hay nhiều container. |
| Workload | Tên gọi chung cho ứng dụng đang chạy (Deployment, Job, DaemonSet…). |
| Manifest | File YAML mô tả tài nguyên K8s. |
| kubectl | Công cụ dòng lệnh để nói chuyện với cluster. |
| Namespace | Thư mục logic chia tách tài nguyên (dev / staging / prod). |
| Label | Cặp key=value gắn lên tài nguyên để nhóm và chọn lọc. |
| Selector | Điều kiện lọc theo label. Cơ chế “kết nối” các tài nguyên với nhau. |
| Replica | Số bản sao của Pod. |
| Rollout | Quá trình cập nhật dần các Pod sang phiên bản mới. |
| Reconciliation | Vòng lặp K8s liên tục sửa thực tế cho khớp khai báo. |
| Registry | Kho chứa Docker image. |
| Helm Chart | Gói template hoá các manifest, có biến và version. |
| CRD | Custom Resource Definition: loại tài nguyên do bên thứ ba thêm vào (cert-manager, ArgoCD dùng cách này). |
Ba từ nữa bạn sẽ gặp ngay từ phần 2–4: image (sản phẩm đã build, bất biến, có tag), container (một phiên bản image đang chạy) và reverse proxy (phần mềm đứng trước server, nhận mọi request rồi chuyển tiếp cho đúng service). Phần 3 giải thích hai từ đầu, phần 2 giải thích từ cuối.
Thực hành
Chặng định vị không có lệnh K8s nào để gõ, nhưng có một bài tập đáng làm trước khi sang phần 2: lần theo chín chặng ở trên với chính app của bạn.
- Chạy
npm run buildtrong app của bạn. Mở thư mụcdist/(Vite) hoặc.next/(Next.js). Ghi lại: fileindex.htmlnằm ở đâu, file JS chính tên gì, phần hash trong tên file trông thế nào. - Mở
index.htmlvừa build bằng editor. Tìm dòng<script>trỏ tới bundle. Đây là điểm vào mà mọi chiến lược cache ở phần 12 xoay quanh. - Tìm xem app của bạn đang được deploy ở đâu. Hỏi đồng nghiệp DevOps xin file Deployment, hoặc tìm thư mục
k8s/,helm/,deploy/trong repo. Chưa cần hiểu, chỉ cần biết nó tồn tại. - Nếu có file đó, đếm xem có bao nhiêu khối bắt đầu bằng
kind:. Ghi lại tên cáckind. Bạn sẽ gặp lại từng cái trong phần 5–9. - Nếu công ty chưa dùng K8s: ghi lại cách app hiện được deploy (Vercel, S3, VPS chạy nginx). Phần 18 sẽ giúp bạn quyết định K8s có đáng cho trường hợp đó không.
Kết quả mong đợi: bạn có một ghi chú ngắn gồm tên file bundle có hash, vị trí
index.html, và danh sáchkindtrong manifest (hoặc tên nền tảng deploy hiện tại). Không cần hiểu gì thêm ở bước này.
Tóm tắt
- Vùng tối sau
git push(trang trắng, biến môi trường sai, 404 khi F5) là câu hỏi hạ tầng, và hạ tầng đó thường là Kubernetes. - FE dev cần thành thạo khoảng 10 loại tài nguyên: Pod, Deployment, Service, Ingress, ConfigMap, Secret, probe, resources, HPA, cùng Dockerfile và Helm/Kustomize ở mức sử dụng. Phần còn lại để DevOps lo.
- Hành trình code frontend có chín chặng: code → static files → image → registry → Deployment → Pod → Service → Ingress → trình duyệt. Mỗi lỗi quen thuộc nằm ở một chặng cụ thể.
- K8s là declarative: bạn khai báo
spec, controller tự reconcile thực tế cho khớp. Giống hệt cách React diff state với DOM. - Cách học duy nhất có tác dụng: gõ tay, cố tình làm hỏng, đọc lỗi, tự sửa. Mỗi phần đều có mục Thực hành và Kết quả mong đợi.
- Phần 2–4 là nền tảng bắt buộc (Linux, mạng, YAML, Docker). Đừng nhảy cóc: đa số người thất bại với K8s là vì thiếu nền này chứ không phải vì K8s khó.
- Toàn bộ series học miễn phí trên máy local bằng kind; máy 8GB RAM và WSL2 (nếu Windows) là đủ.
Đọc thêm
- Kubernetes Concepts — mục Overview và Kubernetes Objects là bản gốc của triết lý declarative ở trên.
- Deployment — tài nguyên bạn sẽ viết nhiều nhất.
- kind — công cụ dựng cluster local dùng xuyên suốt series.
- Nếu bạn muốn đi sâu hơn về Docker trước khi vào K8s, series Docker for Developers trên blog này đi chậm hơn và kỹ hơn phần 3–4 của series này.