Cài k3s Kubernetes Nhẹ Trên VPS 2026 — Cluster Riêng Trên Con VPS 4GB RAM, Không Cần Đến EKS

📅 26/06/2026 · ⏱ 16 phút đọc · 🏷 DevOps · Kubernetes · VPS

1. Tôi Đã Cố Chạy "Kubernetes Thật" Trên VPS 8GB RAM Và Thất Bại Thảm Hại

Đầu năm 2025, tôi quyết định "lên đời" từ Docker Compose lên Kubernetes cho project cá nhân. Tôi cài kubeadm theo đúng documentation của Kubernetes. 2 giờ sau khi cài xong control plane và mấy cái pod hệ thống (etcd, kube-apiserver, kube-scheduler, kube-controller-manager, CoreDNS, kube-proxy), tôi gõ kubectl top nodes. Kết quả: 5.2GB RAM đã bị ăn — trên tổng 8GB — chưa deploy ứng dụng nào. Control plane của Kubernetes gốc ngốn 2-4GB RAM một mình. Đau.

Tôi tắt cluster, quay lại Docker Compose thêm 6 tháng. Cho đến khi một thằng bạn bảo "mày thử k3s đi — Kubernetes mà nhẹ như Docker, gói trong 1 binary ~60MB". Tôi cài thử trên VPS 4GB RAM của TrumVPS. Toàn bộ control plane chạy hết ~500MB. Deploy thêm 5 ứng dụng (Nextcloud, Gitea, blog WordPress, bot Telegram, Uptime Kuma), tổng RAM dùng ~2.1GB. Còn dư 1.9GB. Từ hôm đó tôi không quay lại Docker Compose nữa.

Bài viết này là toàn bộ setup k3s production tôi đang dùng: cài đặt, Helm, Nginx Ingress, Longhorn storage, tự động SSL với cert-manager, và những cái bẫy mà không tutorial nào nói cho bạn biết.

2. Tại Sao k3s Mà Không Phải MicroK8s Hay K0s?

Khi nói đến "Kubernetes nhẹ cho VPS", có 3 ứng viên chính: k3s (Rancher/SUSE), MicroK8s (Canonical), và k0s (Mirantis). Cả ba đều đóng gói Kubernetes thành 1 binary. Nhưng chúng khác nhau ở triết lý thiết kế và trade-off vận hành.

Tiêu chík3s (Rancher)MicroK8s (Canonical)k0s (Mirantis)Kubernetes gốc (kubeadm)
Binary size~60MB~200MB (snap)~160MBNhiều binary riêng
RAM control plane~500MB~600-800MB~500-700MB~2-4GB
Database mặc địnhSQLite (embedded)Dqlite (embedded)etcd (có thể thay)etcd
CNI mặc địnhFlannelCalicoKhông (tự cài)Không (tự cài)
Ingress ControllerTraefik (built-in)Không (tự cài)Không (tự cài)Không (tự cài)
Helm tích hợpCó (HelmController)Có (addon)Có (addon)Không
Cài đặt1 lệnh curlsnap install1 lệnh curlkubeadm init + nhiều bước
Hỗ trợ ARMCó (RPi)Có (RPi)
Auto-upgradeCó (system-upgrade-controller)Có (snap refresh)Có (k0sctl)Thủ công

Lý do tôi chọn k3s:

⚠️ Bẫy #1 — SQLite không scale được multi-node: SQLite không hỗ trợ HA. Nếu bạn định có 3+ node control plane, phải cấu hình k3s với external database (etcd, PostgreSQL, hoặc MySQL) từ đầu. Đổi database sau khi đã có dữ liệu là cực kỳ đau — phải backup toàn bộ resource rồi restore. Tôi đã mất 1 buổi tối vì cái này.

3. Cài k3s Trên VPS Ubuntu 24.04 — 1 Dòng Lệnh

Yêu cầu tối thiểu: VPS 2 vCPU, 2GB RAM, 20GB SSD. Tôi khuyên 4GB RAM để thoải mái. Dùng VPS của TrumVPS (từ 80K/tháng) hoặc Netihot đều được — cả hai đều có KVM ảo hóa, không giới hạn IOPS.

# Trên VPS Ubuntu 24.04
curl -sfL https://get.k3s.io | sh -

# Output sẽ như này:
# [INFO]  Finding release for channel stable
# [INFO]  Using v1.31.2+k3s1 as release
# [INFO]  Downloading hash https://github.com/k3s-io/k3s/releases/...
# [INFO]  systemd: Starting k3s

# Kiểm tra node đã sẵn sàng
sudo k3s kubectl get nodes
# NAME   STATUS   ROLES                  AGE   VERSION
# vps1   Ready    control-plane,master   30s   v1.31.2+k3s1

Mất đúng 45 giây từ lúc chạy curl đến khi node Ready. So với 2 tiếng của kubeadm, đây là phép màu.

3.1. Lấy kubeconfig Để Quản Lý Từ Máy Cá Nhân

# Trên VPS
sudo cat /etc/rancher/k3s/k3s.yaml

# Copy nội dung ra máy local, sửa dòng server thành IP thật của VPS:
# server: https://123.456.789.0:6443

# Trên máy local
mkdir -p ~/.kube
# Paste nội dung đã sửa vào ~/.kube/config
kubectl get nodes  # Phải thấy node
⚠️ Bẫy #2 — Kubeconfig mặc định dùng 127.0.0.1: File /etc/rancher/k3s/k3s.yaml mặc định set server: https://127.0.0.1:6443. Nếu bạn copy file này ra máy local mà quên sửa IP, kubectl sẽ treo 30 giây rồi báo connection refused — không có error message nào nói là do IP sai. Luôn sửa thành IP public hoặc domain của VPS.

4. Cài Helm Và Deploy Ứng Dụng Đầu Tiên

k3s có Helm tích hợp, nhưng tôi vẫn thích cài Helm CLI riêng để quen tay hơn:

# Cài Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Thêm repo phổ biến
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add jetstack https://charts.jetstack.io
helm repo update

Deploy thử Nginx để kiểm tra:

# Tạo deployment + service Nginx
kubectl create deployment nginx-test --image=nginx:alpine --replicas=2
kubectl expose deployment nginx-test --port=80 --type=ClusterIP

# Kiểm tra
kubectl get pods -o wide
# NAME                          READY   STATUS    RESTARTS   AGE
# nginx-test-5cfd8f8d9c-abc12   1/1     Running   0          10s
# nginx-test-5cfd8f8d9c-def34   1/1     Running   0          10s

# Port-forward để test trên máy local
kubectl port-forward svc/nginx-test 8080:80
# Giờ mở http://localhost:8080 — thấy Nginx welcome page

5. Cấu Hình Ingress Và Tự Động HTTPS

k3s đi kèm Traefik làm Ingress Controller mặc định. Để expose ứng dụng ra internet với domain riêng, bạn cần:

# Tạo Ingress cho Nginx test
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
  rules:
  - host: nginx.yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-test
            port:
              number: 80
EOF

Để có HTTPS tự động, cài cert-manager:

# Cài cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.3/cert-manager.yaml

# Tạo ClusterIssuer cho Let's Encrypt
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your@email.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: traefik
EOF

# Thêm annotation vào Ingress để cert-manager tự xin cert
# metadata:
#   annotations:
#     cert-manager.io/cluster-issuer: letsencrypt-prod
#     traefik.ingress.kubernetes.io/router.entrypoints: websecure
#     traefik.ingress.kubernetes.io/router.tls: "true"
⚠️ Bẫy #3 — Traefik mặc định chỉ listen port 80: k3s cài Traefik chỉ expose port 80 (HTTP) mặc định. Port 443 (HTTPS) không tự động mở. Bạn cần sửa Service traefik trong namespace kube-system thêm port 443, hoặc dùng NodePort/HelmConfig khi cài k3s. Tôi đã mất 2 tiếng debug tại sao HTTPS không hoạt động dù cert-manager đã issued certificate thành công.

6. Storage — Longhorn Cho Persistent Volume

Kubernetes không có storage mặc định. Nếu bạn deploy database (PostgreSQL, MySQL) hoặc ứng dụng cần lưu file, bạn cần PersistentVolume. Trên VPS đơn, lựa chọn đơn giản nhất là hostPath — nhưng nó không hỗ trợ snapshot, backup, hoặc mở rộng online. Tôi dùng Longhorn — distributed block storage của Rancher, chạy tốt trên cả cluster 1 node.

# Cài Longhorn
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/deploy/longhorn.yaml

# Đợi tất cả pod ready (~2 phút)
kubectl -n longhorn-system get pods -w

# Set Longhorn làm StorageClass mặc định
kubectl patch storageclass longhorn -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

# Kiểm tra
kubectl get storageclass
# NAME                 PROVISIONER          RECLAIMPOLICY   VOLUMEBINDINGMODE
# longhorn (default)   driver.longhorn.io   Delete          Immediate

Longhorn dùng ~300-500MB RAM, nên nếu VPS 2GB thì hơi căng. Với VPS 4GB RAM thì thoải mái. Nếu bạn cần nhẹ hơn, dùng local-path-provisioner (có sẵn trong k3s, dùng hostPath động).

# Deploy PostgreSQL với Longhorn storage
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pvc
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: longhorn
  resources:
    requests:
      storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:16-alpine
        env:
        - name: POSTGRES_PASSWORD
          value: "your-secure-password"
        ports:
        - containerPort: 5432
        volumeMounts:
        - name: data
          mountPath: /var/lib/postgresql/data
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: postgres-pvc
EOF

7. Giám Sát: Prometheus + Grafana Stack

Cluster K8s mà không có monitoring là lái xe không có đồng hồ. Tôi dùng kube-prometheus-stack:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# Cài với config tối ưu cho VPS nhỏ
helm install monitoring prometheus-community/kube-prometheus-stack \
  --namespace monitoring --create-namespace \
  --set prometheus.prometheusSpec.resources.requests.memory=512Mi \
  --set prometheus.prometheusSpec.retention=7d \
  --set grafana.adminPassword=admin123 \
  --set alertmanager.enabled=false

Prometheus + Grafana sẽ dùng thêm ~1GB RAM. Nếu VPS 4GB RAM, tổng RAM sau khi cài đủ thứ: k3s ~500MB + Longhorn ~400MB + monitoring ~1GB + ứng dụng của bạn ~1GB = ~2.9GB. Vẫn còn dư ~1GB cho buffer.

8. So Sánh Chi Phí: k3s Trên VPS vs EKS/GKE/AKS

Giải phápControl planeNode 2vCPU 4GBTổng/thángGhi chú
k3s trên VPS TrumVPSMiễn phí (cùng node)~160K VND~160K VND1 node, tự quản
k3s trên VPS NetihotMiễn phí (cùng node)~120K VND~120K VND1 node, tự quản
AWS EKS$73/tháng (~1.8M VND)$60/tháng (t3.medium)~3.3M VNDManaged control plane
Google GKEMiễn phí (1 cluster)$50/tháng (e2-standard-2)~1.25M VNDAutopilot rẻ hơn
Azure AKSMiễn phí$55/tháng (B2s)~1.38M VNDManaged
DigitalOcean K8sMiễn phí$24/tháng (2vCPU 4GB)~600K VNDManaged, dễ dùng

k3s trên VPS Việt Nam rẻ hơn EKS 20 lần. Với cá nhân hoặc team nhỏ, managed Kubernetes là overkill. Bạn trả tiền cho thứ mình không cần: auto-scaling node, multi-AZ HA, managed etcd. Với project 1-3 node, k3s là lựa chọn hợp lý nhất.

9. k3s vs Docker Compose — Khi Nào Nên Dùng Cái Nào?

Tình huốngDocker Composek3s
1-3 ứng dụng đơn giản✅ Phù hợp❌ Overkill
5+ microservices⚠️ Khó quản lý✅ Sinh ra để làm việc này
Cần auto-restart khi crash✅ restart: always✅ Tự động (replica set)
Cần rolling update không downtime⚠️ Cần script riêng✅ Built-in (Deployment strategy)
Cần scale theo traffic❌ Thủ công✅ HPA (Horizontal Pod Autoscaler)
Cần secret management⚠️ .env file✅ Secrets (có thể tích hợp Vault)
Cần GitOps (ArgoCD/Flux)❌ Không hỗ trợ✅ Native
Học để đi xin việc⚠️ Cơ bản✅ K8s skill lương cao hơn 40-60%
RAM tối thiểu~50MB (Docker daemon)~500MB (control plane)
Độ phức tạp ban đầuThấpTrung bình

Quy tắc của tôi: nếu project có <3 services và không cần scale, Docker Compose. Nếu 3+ services hoặc muốn học Kubernetes để career, dùng k3s.

💡 Mẹo vận hành: Đừng cố chạy database production trong Kubernetes nếu bạn chỉ có 1 node. SQLite trong pod (với PVC) có thể bị corrupt khi node reboot đột ngột — tôi đã mất 3 ngày dữ liệu vì cái này. Với single-node cluster, database nên chạy ngoài K8s (trên host trực tiếp, hoặc dùng managed DB). Chỉ chạy DB trong K8s khi bạn có 3+ node và hiểu rõ StatefulSet + backup strategy.

10. Backup Cluster — Đừng Để Mất Hết Khi VPS Die

Backup Kubernetes không đơn giản như backup file. Bạn cần backup etcd/SQLite database (chứa toàn bộ resource definitions) + PersistentVolume data. Tôi dùng Velero:

# Cài Velero CLI
wget https://github.com/vmware-tanzu/velero/releases/download/v1.14.0/velero-v1.14.0-linux-amd64.tar.gz
tar xzf velero-v1.14.0-linux-amd64.tar.gz
sudo mv velero-v1.14.0-linux-amd64/velero /usr/local/bin/

# Cấu hình backup ra S3-compatible storage
velero install \
  --provider aws \
  --bucket k3s-backup \
  --secret-file ./credentials-velero \
  --backup-location-config region=ap-southeast-1,s3ForcePathStyle=true,s3Url=https://s3.example.com \
  --snapshot-location-config region=ap-southeast-1

# Backup hàng ngày
velero schedule create daily-backup --schedule="0 3 * * *" --ttl 168h

# Restore toàn bộ cluster (nếu VPS cũ die, tạo VPS mới)
velero restore create --from-backup daily-backup-20260626

Nếu bạn dùng Longhorn, nó có built-in backup ra S3/NFS — không cần Velero cho storage:

# Cấu hình Longhorn backup target
# Vào Longhorn UI (kubectl -n longhorn-system port-forward svc/longhorn-frontend 8080:80)
# Settings > Backup Target: s3://bucket@region/backup/
# Schedule recurring backup cho từng volume

🚀 Cần VPS Mạnh Để Chạy k3s Kubernetes?

TrumVPS có VPS KVM từ 80K/tháng, 2-8GB RAM, SSD NVMe — đủ sức chạy k3s cluster riêng cho cá nhân hoặc team nhỏ. Miễn phí backup weekly.

Thuê VPS TrumVPS Ngay →