Tài liệu này hướng dẫn tạo một cluster LKE đầu tiên cho ứng dụng web như Website AI: những lựa chọn trên form tạo cluster LKE, cách chia node pool theo vai trò, cách tính cỡ node theo request, và cách giữ an toàn file kubeconfig. Sau phần lý thuyết về pod, Service, ConfigMap, volume và Ingress, đây là lúc cần một cluster thật để chạy thử.

1. Cluster LKE gồm những gì

LKE (Linode Kubernetes Engine) là dịch vụ Kubernetes được quản lý của Linode. Như đã nói trong bài Kubernetes là gì: control plane, node và pod, một cluster có hai nửa. Với cluster LKE, trách nhiệm giữa hai nửa được chia rõ ràng:

PhầnAi vận hànhGồm những gì
Control planeLinodeAPI server, etcd, scheduler, controller manager, cùng các thành phần riêng của Linode như Cloud Controller Manager (tạo NodeBalancer) và CSI driver (tạo Block Storage)
Worker nodeBạn chọn, Linode dựngCác máy Linode chạy kubelet, container runtime, kube-proxy và CNI. Đây là nơi pod thật sự chạy
Tài nguyên đi kèmCluster tự tạo khi cầnNodeBalancer cho Service LoadBalancer, Block Storage volume cho PVC

Bạn không SSH được vào control plane, cũng không phải lo sao lưu etcd hay vá API server; mọi thao tác đều đi qua API và kubeconfig. Chi phí của cluster LKE nằm ở worker node, NodeBalancer và volume, nên mỗi lựa chọn bên dưới cũng là lựa chọn về tiền.

Worker node được nhóm thành node pool: các node cùng loại máy, tăng giảm số lượng hoặc thêm pool mới bất cứ lúc nào mà không phải tạo lại cluster. Mỗi node được gắn sẵn label lke.linode.com/pool-id cho biết nó thuộc pool nào.

2. Các lựa chọn khi tạo cluster LKE

Form tạo cluster LKE trên Cloud Manager rất ngắn, nhưng mỗi ô đều có hệ quả lâu dài:

  • Label: đặt tên nói rõ cluster phục vụ sản phẩm nào và chừa hậu tố số cho cluster sau, ví dụ app-prod-01. Nhìn tên là biết vai trò, giống cách đặt tên máy trên Cloud VPS.
  • Region: chọn region gần người dùng nhất để giảm độ trễ. Với khách hàng ở Việt Nam, Singapore (ap-south) thường là lựa chọn hợp lý. Region không đổi được sau khi tạo: muốn chuyển region là phải dựng cluster mới và di chuyển workload.
  • Phiên bản Kubernetes: LKE thường chỉ cung cấp vài nhánh minor gần nhất. Chọn phiên bản cũng là cam kết nâng cấp định kỳ, và trên LKE nâng cấp nghĩa là các node lần lượt bị thay bằng node mới, nên workload phải chịu được việc pod bị dời đi.
  • Control plane có HA hay không: LKE có tuỳ chọn control plane nhiều bản sao, tính phí thêm. Pod đang chạy không chết khi control plane chập chờn, chỉ việc deploy, scale và các controller bị ảnh hưởng.

Có một thứ bạn không phải chọn: CNI. LKE tự cài Calico ngay khi tạo cluster, các CRD của Calico xuất hiện gần như cùng lúc với namespace default. Calico lo mạng giữa các pod trên nhiều node và hỗ trợ NetworkPolicy nếu sau này cần khoanh vùng traffic.

Tài liệu chính thức về các tuỳ chọn này nằm ở trang Linode Kubernetes Engine.

3. Node pool: chia node theo vai trò

Một cluster LKE nhỏ có thể chỉ cần một pool, nhưng nên tách pool theo vai trò ngay từ đầu vì các nhóm workload hành xử rất khác nhau:

PoolChạy gìĐặc điểm
Pool hệ thốngIngress controller, cert-manager, monitoringÍt pod, ổn định, nhưng là cổng chung: chết là mọi website cùng chết
Pool websitePod ứng dụng của từng siteSố pod tăng theo số khách, tải lên xuống theo traffic từng site, deploy liên tục

Tách pool giúp một site bị bot cào hết CPU không kéo theo ingress controller. Nhưng scheduler vẫn tự do đặt pod lên bất kỳ node nào còn chỗ; muốn pod hệ thống chỉ chạy ở pool hệ thống, bạn phải khai báo nodeAffinity theo label lke.linode.com/pool-id (có bài riêng trong series).

4. Chọn kích thước node cho cluster LKE

Node của cluster LKE là các gói máy Linode thông thường. Ở nhóm Shared CPU, ba cỡ hay gặp là g6-standard-1 (1 vCPU, 2 GB RAM), g6-standard-2 (2 vCPU, 4 GB) và g6-standard-4 (4 vCPU, 8 GB). Khi chọn, hãy xét ba điều sau.

Allocatable nhỏ hơn con số trên bảng giá

Một node 4 GB không cho pod dùng đủ 4 GB. kubelet giữ lại một phần cho hệ điều hành và chính nó, phần còn lại gọi là allocatable. Trong phần allocatable đó, mỗi node còn phải chạy các DaemonSet hệ thống của LKE như calico-node, kube-proxy và CSI node driver. Xem con số thật bằng:

kubectl describe node <tên-node> | grep -A 6 Allocatable
kubectl describe node <tên-node> | grep -A 10 "Allocated resources"

Phần hao hụt này gần như cố định theo node, nên node càng nhỏ thì tỷ lệ bị "ăn mất" càng lớn.

Đếm pod theo request, không theo cảm giác

Scheduler xếp pod dựa trên requests, không dựa trên mức dùng thực tế. Giả sử container web đặt request 150m CPU và 300Mi RAM. Công thức ước lượng:

số pod tối đa theo RAM = (allocatable RAM − request của DaemonSet hệ thống) / request RAM mỗi pod
số pod tối đa theo CPU = (allocatable CPU − request của DaemonSet hệ thống) / request CPU mỗi pod
→ lấy số nhỏ hơn, rồi chừa khoảng trống cho lúc deploy (RollingUpdate tạo pod mới trước khi xoá pod cũ)

Với website PHP, RAM thường hết trước CPU, nên ưu tiên gói có tỷ lệ RAM trên CPU cao.

Ít node to hay nhiều node nhỏ

Nhiều node nhỏ thì một node chết chỉ kéo theo ít pod, nhưng hao hụt cho DaemonSet bị nhân lên. Ít node to tận dụng tài nguyên tốt hơn, nhưng mỗi sự cố node làm nhiều website bị dời đi cùng lúc. Với cluster LKE, đổi ý không tốn kém: thêm pool cỡ khác, dời workload sang, rồi xoá pool cũ.

5. Kubeconfig: chìa khoá vào cluster LKE

Khi cluster LKE sẵn sàng, Cloud Manager cho tải về một file kubeconfig. Đây là file YAML mà kubectl dùng để biết gọi API server nào và xưng danh bằng gì. Cấu trúc của nó (giá trị đã thay bằng <...>):

apiVersion: v1
kind: Config
clusters:
- name: lke<id>
  cluster:
    server: https://<api-server-endpoint>:443
    certificate-authority-data: <...>
users:
- name: lke<id>-admin
  user:
    token: <...>          # token quản trị: ai có nó là có toàn quyền
contexts:
- name: lke<id>-ctx
  context:
    cluster: lke<id>
    user: lke<id>-admin
    namespace: default
current-context: lke<id>-ctx

Dòng token là toàn bộ vấn đề: kubeconfig mặc định của cluster LKE mang quyền quản trị cao nhất, không có lớp xác thực thứ hai. File lọt ra ngoài nghĩa là cluster LKE lọt ra ngoài. Cách dùng an toàn hằng ngày:

# mỗi cluster một file, chỉ chủ sở hữu đọc được
chmod 600 ~/.kube/app-prod-01.yaml
export KUBECONFIG=~/.kube/app-prod-01.yaml

kubectl config get-contexts        # chắc chắn đang trỏ đúng cluster
kubectl get nodes -o wide          # các node của mọi node pool
kubectl get pods -n kube-system    # calico, coredns, csi-linode, kube-proxy...
kubectl get storageclass           # linode-block-storage và linode-block-storage-retain

Thói quen gõ kubectl config get-contexts trước một lệnh nguy hiểm trở nên cần thiết ngay khi có cluster LKE thứ hai. Kubernetes giải thích cơ chế gộp nhiều kubeconfig trong trang Organizing Cluster Access Using kubeconfig Files.

6. Quyền truy cập: ai được cầm chìa khoá

Với cluster LKE, nên đặt ra mấy nguyên tắc tương đương quản lý SSH key trên Cloud VPS:

  • Kubeconfig quản trị chỉ nằm trong tay người vận hành cluster: không gửi qua chat, không commit vào Git, không dán vào ticket. Kiểm tra .gitignore và .dockerignore để file không lọt vào Git hay image.
  • Lộ thì thu hồi ngay. Cloud Manager có thao tác reset kubeconfig: token cũ mất hiệu lực, mọi người phải tải file mới.
  • Dev và hệ thống CI không dùng kubeconfig quản trị. Hướng đúng là tạo ServiceAccount riêng, gắn Role và RoleBinding chỉ trong namespace cần thiết, rồi sinh kubeconfig từ token của ServiceAccount đó. Cơ chế phân quyền được mô tả trong tài liệu RBAC của Kubernetes.
  • Token Linode API là một chìa khoá khác. Token này tạo và xoá được cả cluster, node pool lẫn NodeBalancer. Chỉ cấp đúng phạm vi cần dùng và đặt thời hạn.

Ví dụ tối thiểu cho một ServiceAccount chỉ được deploy trong một namespace:

kubectl create namespace site-a
kubectl -n site-a create serviceaccount deployer
kubectl -n site-a create rolebinding deployer-edit \
  --clusterrole=edit --serviceaccount=site-a:deployer
kubectl -n site-a create token deployer --duration=24h

7. Lỗi thường gặp với cluster LKE mới

  • Gõ lệnh vào nhầm cluster: biến KUBECONFIG trong một tab terminal cũ vẫn trỏ cluster thử nghiệm. Đặt tên file, context rõ ràng và kiểm tra context trước mọi lệnh apply hay delete.
  • Unable to connect to the server sau khi reset kubeconfig: token cũ đã bị thu hồi. Tải lại file và cập nhật mọi nơi đang dùng file cũ.
  • Pod Pending dù node còn "trống": kubectl top cho thấy node đang rảnh, nhưng tổng requests đã chạm allocatable. Xem mục "Allocated resources" thay vì nhìn mức dùng thực tế.
  • Quên rằng node có thể bị thay bất cứ lúc nào: nâng cấp phiên bản hoặc recycle node sẽ tạo node mới với tên mới, IP mới. Không viết cấu hình nào phụ thuộc tên node hay IP node cụ thể. Một dòng comment hay nodeName trỏ tới node của cluster thử nghiệm cũ, sót lại trong manifest, là lỗi rất dễ mắc.

8. Checklist trước khi đưa workload lên cluster LKE

  1. Tên cluster nói rõ vai trò, region gần người dùng, phiên bản Kubernetes còn được hỗ trợ.
  2. Node pool tách theo vai trò (hệ thống, website), cỡ node tính từ allocatable và request.
  3. Kubeconfig quản trị có quyền 600, không nằm trong repo hay image, đã biết cách reset.
  4. CI và dev dùng ServiceAccount có quyền hẹp theo namespace.
  5. Token Linode API có phạm vi và thời hạn rõ ràng.
  6. Không manifest nào phụ thuộc tên node hay IP node.

Tạo một cluster LKE chỉ mất vài phút; phần tốn thời gian là quyết định workload nào chạy ở đâu, mỗi pod cần bao nhiêu tài nguyên, ai được quyền làm gì. Cách traffic đi vào cluster đã có ở bài Ingress và NodeBalancer, còn cách volume được cấp phát nằm ở bài PersistentVolume, PVC và StorageClass.

Bài tiếp theo

Manifest Kubernetes đầu tiên: namespace, Deployment và MySQL StatefulSet. Đọc từng file YAML của một ứng dụng Laravel trên Kubernetes, vì sao MySQL dùng StatefulSet thay vì Deployment, và những lỗi hay gặp ở phiên bản đầu.