Cloud, Containers

Hướng dẫn từng bước cài đặt & cấu hình Kubernetes trên Ubuntu 24.04 và triển khai ứng dụng

Giới thiệu
Kubernetes (#K8s) là nền tảng mã nguồn mở hàng đầu để quản lý và điều phối các ứng dụng containers. Trong bài viết này, chúng ta sẽ thực hiện từng bước thiết lập một Kubernetes cluster trên Ubuntu 24.04 LTS và triển khai một ứng dụng mẫu. Hướng dẫn này phù hợp cho người mới làm quen với Kubernetes cũng như những bạn đã có kiến thức cơ bản về Linux, Docker và Ingress. Bài viết này mình viết theo phong cách rất thân thiện , giúp bạn dễ dàng nắm bắt các khái niệm và các lệnh K8s một cách tốt nhất.

Trước khi bắt đầu, hãy đảm bảo bạn có:

  • 2 máy chủ Ubuntu 24.04 (một máy làm Master – node điều phối quản trị chính, và ít nhất một máy làm Worker – node để tải công việc ).

  • Quyền truy cập sudo trên các máy chủ.

  • Kết nối internet để cài đặt các gói cần thiết.

  • Kiến thức nền tảng về dòng lệnh Linux và Docker (sẽ hữu ích nhưng không bắt buộc).

Chúng ta sẽ lần lượt thực hiện:

  1. Cài đặt và cấu hình môi trường Kubernetes trên Ubuntu 24.04.

  2. Khởi tạo (init) cụm Kubernetes trên node Master.

  3. Join node Worker vào cụm Kubernetes.

  4. Gán vai trò cho node Worker và tạo Namespace mới.

  5. Triển khai một ứng dụng mẫu trên cụm (ví dụ: Nginx).

  6. Mở rộng (scale) ứng dụng Nginx lên hai bản sao (replica), đồng thời kiểm tra tính năng tự động khôi phục.

  7. Cấu hình truy cập ứng dụng thông qua Service loại ClusterIP và Ingress bằng domain nội bộ (tránh sử dụng NodePort trực tiếp).

Vậy chúng ta hãy cùng bắt đầu hành trình khám phá Kubernetes nào!

Bước 1: Cài đặt môi trường Kubernetes trên Ubuntu 24.04

Trong bước đầu tiên, chúng ta sẽ chuẩn bị môi trường cho cả node Master và node Worker, vậy bạn hãy thực hiện bước này trên tất cả các nodes. Việc cài đặt bao gồm cập nhật hệ thống, tắt các tính năng không cần thiết, cài đặt container runtime (ở đây dùng containerd) và các thành phần Kubernetes (kubeadm, kubelet, kubectl).

1. Cập nhật hệ thống Linux và cài đặt các gói phụ thuộc (trên tất cả các node):

  • Cập nhật danh sách gói và nâng cấp hệ thống:

    sudo apt update && sudo apt upgrade -y

  • Cài đặt các tiện ích cần thiết: các công cụ hỗ trợ cài đặt qua HTTPS và quản lý kho:

    sudo apt install -y apt-transport-https ca-certificates curl gnupg2 software-properties-common

  • Đặt hostname duy nhất cho mỗi node (để dễ quản lý trong cluster):
    Ví dụ, đặt tên master cho máy Master và worker1 cho máy Worker:

    sudo hostnamectl set-hostname master # Thực hiện trên máy Master
    sudo hostnamectl set-hostname worker1 # Thực hiện trên máy Worker

2. Tắt swap và điều chỉnh kernel (trên tất cả các nodes):
Kubernetes yêu cầu tắt swap trên các nodes để đảm bảo hiệu xuất và sự ổn định. Đồng thời, chúng ta thiết lập một số thông số kernel để Kubernetes hoạt động đúng.

  • Tạm thời tắt swap ngay lập tức:

    sudo swapoff -a    
  • Tắt swap vĩnh viễn: chỉnh sửa file cấu hình /etc/fstab và thêm dấu # ở đầu dòng kích hoạt swap (hoặc xóa dòng đó). Việc này ngăn không cho swap tự bật lại sau mỗi lần khởi động.

  • Nếu bạn muốn tự động thêm dấu # vào đầu dòng cho việc tắt swap vĩnh viễn /swap.img trong file /etc/fstab, thì có thể dùng lệnh sed:

    sudo sed -i '/\/swap.img/s/^/#/' /etc/fstab

    Giải thích nhanh:

    • -i : Chỉnh sửa trực tiếp file.

    • /\/swap.img/ : Tìm dòng có chứa chuỗi ký tự /swap.img.

    • s/^/#/ : Thay thế ký tự ở đầu dòng bằng # ( có nghĩa là thêm # vào đầu dòng).

  • Tải các module kernel cần thiết và cấu hình thông số networking:

    # Bật các module cho khả năng overlay và networking trong container
    sudo modprobe overlay
    sudo modprobe br_netfilter
    # Thiết lập các thông số sysctl cho Kubernetes
    sudo tee /etc/sysctl.d/kubernetes.conf <<EOF
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    net.ipv4.ip_forward = 1
    EOF
    # Áp dụng cấu hình sysctl ngay
    sudo sysctl --system

    Giải thích: Các thiết lập trên cho phép iptables xử lý traffic qua cầu network bridge và bật tính năng chuyển tiếp IP. Điều này rất quan trọng để các pods trong Kubernetes có thể giao tiếp qua hệ thống mạng.

3. Cài đặt container runtime (trên tất cả các nodes):
Kubernetes sử dụng container runtime để chạy các containers. Ở đây, chúng ta chọn containerd – runtime nhẹ và được Kubernetes hỗ trợ trực tiếp (Docker hiện nay cũng sử dụng containerd dưới nền).

  • Thêm kho lưu trữ (repository) Docker và key xác thực: Containerd có thể cài từ repo Docker official.

    sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
  • Lệnh tiếp theo:
    echo \
    "deb [arch=amd64 signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu jammy stable" | \
    sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

  • Cài đặt containerd:

    sudo apt update
    sudo apt install -y containerd.io
  • Cấu hình containerd để sử dụng systemdlàm cgroup driver (giúp tương thích tốt với kubelet và hệ thống):

    # Tạo file cấu hình mặc định
    sudo mkdir -p /etc/containerd
    sudo containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
    # Sửa config để dùng systemd làm cgroup driver
    sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
  • Khởi động và bật containerd chạy cùng hệ thống:

    sudo systemctl restart containerd
    sudo systemctl enable containerd

Lưu ý: Nếu bạn quen dùng Docker, có thể cài Docker thay cho containerd. Tuy nhiên, kể từ Kubernetes 1.24, dockershim (cầu nối trực tiếp tới Docker) đã bị loại bỏ; Docker muốn dùng với Kubernetes cũng thông qua containerd. Vì vậy, sử dụng containerd trực tiếp sẽ đơn giản và phù hợp hơn với hướng dẫn này.

4. Thêm kho lưu trữ và cài đặt các gói Kubernetes (trên tất cả các node):
Các gói kubeadm, kubelet, kubectl không có sẵn trong Ubuntu theo mặc định, ta cần thêm nguồn từ Kubernetes:

  • Thêm kho apt Kubernetes và khóa GPG:

    sudo mkdir -p /etc/apt/keyrings
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes.gpg
    echo "deb [signed-by=/etc/apt/keyrings/kubernetes.gpg] https://pkgs.k8s.io/core:/stable:/v1.34/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

    (Lệnh trên giả định ta dùng phiên bản stable v1.34 cho năm 2025; bạn có thể điều chỉnh phiên bản tùy thời điểm hiện tại nếu cần).

  • Cài đặt kubeadm, kubelet, kubectl:

    sudo apt update
    sudo apt install -y kubelet kubeadm kubectl
    sudo apt-mark hold kubelet kubeadm kubectl # giữ cố định phiên bản, tránh nâng cấp ngoài ý muốn
  • Kiểm tra phiên bản cài đặt (tùy chọn):

    kubeadm version
    kubectl version --client
    kubelet --version

    Các lệnh trên sẽ hiển thị phiên bản của kubeadm, kubectl (client) và kubelet, xác nhận rằng chúng đã được cài thành công.

Bạn đã cài đặt xong môi trường Kubernetes trên cả Master và Worker nodes. Great job! Bây giờ chúng ta sẵn sàng khởi tạo cụm Kubernetes.

Bước 2: Khởi tạo Kubernetes Cluster trên node Master

Trong bước này, chúng ta sẽ sử dụng kubeadm để khởi tạo (initialize) cụm Kubernetes trên máy Master. Node Master (còn gọi là Control Plane) chịu trách nhiệm quản lý toàn cụm – gồm API server, bộ lập lịch, controller-manager, v.v.

Thực hiện khởi tạo cụm trên node Master:

  • Trên máy Master, chạy lệnh kubeadm initđể thiết lập control plane. Ở đây, chúng ta sẽ chỉ định CIDR mạng Pod10.244.0.0/16 để tương thích với plugin mạng Flannel (step này sẽ làm sau). Chạy lệnh như sau:

    sudo kubeadm init --pod-network-cidr=10.244.0.0/16

    Giải thích: Tham số --pod-network-cidr=10.244.0.0/16 khai báo dải mạng Pod cho cluster. Flannel CNI mặc định dùng 10.244.0.0/16, nên ta đặt cho khớp; điều này là bắt buộc để Flannel hoạt động đúng. Nếu bạn dùng CNI khác (ví dụ Calico), có thể dải mặc định khác, nhưng trong hướng dẫn này ta chọn Flannel cho đơn giản.

    Chạy lệnh trên, kubeadm sẽ tiến hành một loạt bước:

    • Kiểm tra preflight (cấu hình kernel, CPU, swap…).

    • Tạo các chứng chỉ cần thiết, khởi tạo cluster etcd, API server, Controller Manager, Scheduler dưới dạng pods tĩnh (static pods) trên Master.

    • Đánh dấu node hiện tại là control-plane (gán label node-role.kubernetes.io/control-plane và taint NoSchedule)

    • Sinh ra file cấu hình kubeconfig cho admin (/etc/kubernetes/admin.conf).

    • Cuối cùng, khởi chạy các add-on cơ bản: CoreDNS (DNS nội bộ) và kube-proxy (đã cài sẵn dưới dạng DaemonSet).

    Quá trình này có thể mất vài phút, tùy tốc độ của server và mạng (kubeadm sẽ kéo các image Kubernetes cần thiết). Khi hoàn thành, bạn sẽ thấy thông báo Your Kubernetes control-plane has initialized successfully!.

    Quan trọng: Kubeadm sẽ in ra một khối hướng dẫn, bao gồm:

    • Cách thiết lập kubeconfig cho tài khoản thường,

    • Lệnh gợi ý để cài pod network add-on (hiện tại cluster chưa có mạng cho Pod, lát nữa ta sẽ cài Flannel),

    • Lệnh kubeadm join dùng để join các nodes Worker vào cluster.

    Hãy tìm dòng output tương tự bên dưới và copy nó ra nơi an toàn (ví dụ, lưu nội dung này vào file notepad hoặc note lại). Lệnh này chứa thông tin quan trọng để node Worker có thể tham gia cụm:

    kubeadm join <MASTER_IP>:6443 --token <bootstrap-token> \
      --discovery-token-ca-cert-hash sha256:<discovery-token-hash>

    Ví dụ thực tế, output có thể trông như sau (thông tin IP và token của bạn sẽ khác):

    kubeadm join 192.168.146.166:6443 --token 72ww2b.6orffywqcf5s4p2z \
      --discovery-token-ca-cert-hash sha256:aafb79cdd45a6e3b3fac01fb3efba0817360b01f90a4b6c3f11567108a36ba67

    Trong đó:

    • <MASTER_IP>:6443 là địa chỉ API server của Control Plane (cổng mặc định 6443) – ở ví dụ trên là 138.197.184.45:6443. Cụm của bạn có thể là IP private của máy Master.

    • <bootstrap-token> là token tạm thời kubeadm tạo để Workers xác thực khi join – ví dụ 72ww2b.6orffywqcf5s4p2z. Token này thường có hiệu lực mặc định trong vòng 24 giờ.

    • <discovery-token-ca-cert-hash> là hash SHA256 của CA certificate cụm – dùng để Worker xác minh danh tính Master (ngăn MITM).

    Kubeadm init đã lo tất cả cho chúng ta, việc của bạn là lưu lại toàn bộ chuỗi lệnh join này. Nếu bạn lỡ quên copy, bạn có thể tạo lại token mới và in lệnh join bằng câu lệnh sau trên Master node:

    kubeadm token create --print-join-command

    (Khi chạy, lệnh trên sẽ sinh token mới và output ra một lệnh join tương tự). Như vậy bạn không lo bị mất thông tin kết nối cụm.

    Thiết lập cấu hình kubectl cho user: Để sử dụng kubectl trên node Master (ví dụ để quản lý cluster), chúng ta cần kubeconfig. Kubeadm đã tạo sẵn file kubeconfig cho tài khoản admin tại /etc/kubernetes/admin.conf. Các lệnh sau sẽ copy file này vào thư mục home của user hiện tại (giả sử bạn không chạy các lệnh dưới với user root):

    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

    Lệnh trên giúp bạn (user thường) có quyền truy cập cluster với quyền admin (sử dụng chứng chỉ admin trong file config). Nếu bạn đang làm mọi thứ bằng user root, có thể bỏ qua bước copy và thay vào đó export KUBECONFIG=/etc/kubernetes/admin.conf cho phiên làm việc. Tuy nhiên, khuyến cáo là tạo user thường để quản trị cho an toàn.

    • Triển khai plugin mạng (CNI) cho cluster: Hiện tại, nếu kiểm tra cluster bạn sẽ thấy node Master ở trạng thái NotReady, vì chưa có mạng Pod. Kubernetes yêu cầu một CNI plugin để các Pod có thể giao tiếp với hệ thống mạng. Bạn có thể chọn Calico, Flannel, Weave… Ở đây chúng ta dùng Calico làm ví dụ:

      kubectl apply -f   https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml

      Lệnh trên cài đặt Calico vào cluster (hãy đảm bảo đã dùng --pod-network-cidr=10.244.0.0/16 khi init như ở trên để khớp với Calico). Nếu bạn muốn dùng plugin khác, hãy áp dụng manifest tương ứng (ví dụ Flannel:
      kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.21.4/Documentation/kube-flannel.yml).

  • Kiểm tra nhanh trạng thái node:

    kubectl get nodes

    Kết quả dự kiến: node Master có tên (ví dụ master) hiện ra với trạng thái NotReady ban đầu, sau vài chục giây khi plugin mạng khởi chạy sẽ chuyển thành Ready. Node Master cũng sẽ có vai trò control-planemaster (và có taint để hạn chế pod ứng dụng chạy trên nó).

Tuyệt vời! Cụm Kubernetes của bạn đã được khởi tạo thành công trên máy Master. Control Plane đã sẵn sàng. Bây giờ, chúng ta sẽ kết nối node Worker vào cụm để có nơi chạy các ứng dụng.

Bước 3: Thêm (join) node Worker vào Kubernetes Cluster

Hiện tại, cụm của chúng ta mới chỉ có node Master. Để triển khai ứng dụng, ta cần thêm node Worker (được sử dụng để cho việc chạy các pods ứng dụng). Kubeadm đã cung cấp sẵn lệnh kubeadm join để join node Worker vào cụm.

Thực hiện thêm node Worker:

  • Trên máy Worker, đảm bảo đã hoàn thành Bước 1 (cài đặt kubeadm, kubelet, containerd, tắt swap, etc.).

  • Chạy lệnh join do kubeadm init cung cấp. Lệnh này gồm địa chỉ API server của Master, token và mã băm (hash) để xác thực:

    sudo kubeadm join <Master_IP>:6443 --token <token> \
    --discovery-token-ca-cert-hash sha256:<hash>

    Thay <Master_IP> bằng địa chỉ IP của node Master, <token><hash> theo giá trị cụ thể in ra ở bước kubeadm init (lưu ý token chỉ có hiệu lực trong 24 giờ theo mặc định).
    Ví dụ, với thông tin giả định ở trên, ta chạy trên Worker node:

    sudo kubeadm join 192.168.146.164:6443 --token 72ww2b.6orffywqcf5s4p2z \
    --discovery-token-ca-cert-hash sha256:aafb79cdd45a6e3b3fac01fb3efba0817360b01f90a4b6c3f11567108a36ba67

    (Bạn phải thay bằng đúng IP của Master và token, hash trong cụm của bạn đã ghi lại ở Bước 2). Lệnh trên cần chạy với quyền root , bằng cách sử dụng dụng lệnh sudo -i để vào quyền root (hoặc thêm sudo như trên).

  • Quá trình kubeadm join sẽ thiết lập kubelet trên Worker, tải về các cấu hình cần thiết từ Master và đăng ký node với Control Plane. Khi thấy thông báo This node has joined the cluster có nghĩa là thành công.

Xác minh trên máy Master:

  • Trở lại terminal Master, kiểm tra danh sách node:

    kubectl get nodes

    Bây giờ bạn sẽ thấy 2 nodes: ví dụ master (Ready, control-plane) và worker1 (Ready). Node Worker đã gia nhập cluster thành công và sẵn sàng nhận tải công việc.

  • Kiểm tra chi tiết node Worker (tùy chọn):

    kubectl describe node worker1

    Bạn có thể xem các thông tin về CPU, memory, điều kiện (conditions) và địa chỉ IP của node Worker tại đây.

Nice work! Bạn đã bổ sung một node Worker vào cluster Kubernetes, tăng khả năng mở rộng và tính chịu lỗi cho hệ thống. Giờ cụm của bạn đã có Master để điều phối và Worker để chạy các ứng dụng.

Bước 4: Gán vai trò cho node Worker và tạo Namespace

Để cluster có tổ chức rõ ràng, chúng ta sẽ gán nhãn vai trò cho node Worker và tạo ra một Namespace mới cho ứng dụng. Những thao tác này giúp quản lý tài nguyên dễ dàng hơn, nhất là khi cụm mở rộng.

1. Gán nhãn vai trò (node-role) cho node Worker:
Mặc dù bản thân Kubernetes không bắt buộc phải gán nhãn cho node Worker (node không có nhãn node-role.kubernetes.io/master mặc định được xem là worker rồi), nhưng chúng ta có thể gắn nhãn thủ công để dễ phân biệt.

  • Trên Master, chạy lệnh label để gán vai trò “worker” cho node Worker:

    kubectl label node worker1 node-role.kubernetes.io/worker=worker

    (Giả sử node Worker có tên là worker1. Bạn thay bằng tên thực tế lấy từ lệnh kubectl get nodes).

  • Kiểm tra lại nhãn của các node:

    kubectl get nodes --show-labels

    Kết quả sẽ hiển thị node worker1 kèm nhãn node-role.kubernetes.io/worker=worker. Việc gắn nhãn này nhằm mục đích nhận diện; một số tool giao diện có thể dựa vào nhãn này để liệt kê các nodes worker.

2. Tạo Namespace mới cho ứng dụng:
Namespace cho phép chúng ta nhóm các tài nguyên Kubernetes lại với nhau, tránh xung đột tên và dễ phân quyền. Ở đây, chúng ta tạo namespace tên demo để chứa ứng dụng mẫu.

  • Cách nhanh nhất: tạo namespace bằng lệnh kubectl:

    kubectl create namespace demo
  • Hoặc tạo thông qua file YAML (để thực hành việc khai báo đối tượng Kubernetes qua YAML):

    • Tạo file nano namespace-demo.yaml với nội dung:

      apiVersion: v1
      kind: Namespace
      metadata:
       name: demo
    • Áp dụng file:

      kubectl apply -f namespace-demo.yaml
  • Xác minh Namespace mới:

    kubectl get namespaces

    Bạn sẽ thấy demo nằm trong danh sách (bên cạnh các namespace mặc định như default, kube-system, kube-public, …).

Well done! Bạn đã gán nhãn cho node Worker và tạo namespace thành công. Cluster của bạn giờ có cấu trúc rõ ràng hơn, sẵn sàng cho bước triển khai ứng dụng tiếp theo.

Bước 5: Triển khai ứng dụng trên Kubernetes Cluster

Đến phần hấp dẫn nhất – triển khai ứng dụng lên cluster Kubernetes! Ở đây chúng ta sẽ triển khai một ứng dụng web mẫu là Nginx để minh họa. Chúng ta sẽ tạo một Deployment chạy Nginx và sau đó tạo một Service để có thể truy cập ứng dụng.

1. Tạo Deployment cho ứng dụng Nginx:
Deployment sẽ tạo và quản lý một hoặc nhiều Pod chạy container Nginx. Chúng ta sẽ triển khai Deployment trong namespace demo vừa tạo.

  • Tạo file cấu hình Deployment, ví dụ nano nginx-deployment.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
        name: nginx-deployment
        namespace: demo # Deploy in namespace "demo"
    spec:
       replicas: 1 # Number of Nginx Pods desired
       selector:
          matchLabels:
              app: nginx # Selector to match the Pod template below
       template:
          metadata:
               labels:
                  app: nginx # Label for Pod, match selector above
          spec:
             containers:
             - name: nginx
               image: nginx:latest # Use the latest Nginx image from Docker Hub
               ports:
               - containerPort: 80 # Expose port 80 in container (HTTP)

    Lưu ý: Trong file, trường namespace: demo đảm bảo Deployment được tạo đúng namespace. Nếu bỏ qua, Deployment mặc định vào namespace default. Hãy cẩn thận về thụt lề YAML để tránh lỗi cú pháp.

  • Áp dụng Deployment:

    kubectl apply -f nginx-deployment.yaml
  • Kiểm tra Pod do Deployment tạo ra:

    kubectl get pods -n demo -o wide

    Bạn sẽ thấy một Pod tên dạng nginx-deployment-***** hiện trạng thái Running. Cột NODE sẽ cho biết Pod đó đang chạy trên node nào (có thể là worker1). Chúc mừng, ứng dụng Nginx đã chạy trên cluster!

  • Bây giờ để test thử xem container Nginx có hoạt động không? Hãy dùng port-forward bằng lệnh sau, để test:
    kubectl -n demo port-forward deploy/nginx-deployment 8080:80

    Hãy để nguyên lệnh này chạy trong terminal. Rồi bạn mở trình duyệt trong master node: http://localhost:8080 → thấy “Welcome to nginx!”. Hoặc mở 1 phiên SSH khác vào master node và chạy lệnh CuRL như trong hình sau để test:

Kubernetes Deployment sẽ đảm bảo luôn có số Pod đúng bằng replicas đã khai báo (hiện tại là 1). Bây giờ, chúng ta đã có container Nginx chạy, nhưng làm thế nào để người dùng truy cập được vào ứng dụng Nginx một cách thân thiện?

2. Tạo Service để expose ứng dụng Nginx:
Mặc định, Pod chỉ có địa chỉ IP nội bộ cluster. Service sẽ cung cấp một IP ổn định và cơ chế cân bằng tải (load-balancing) cho các Pod. Ở đây,chúng ta sẽ tạo Service loại ClusterIP (phục vụ bên trong cluster) vì ta sẽ dùng Ingress cho truy cập từ bên ngoài.

  • Tạo Service cho Deployment Nginx bằng lệnh kubectl expose:

    kubectl expose deployment nginx-deployment -n demo \
     --name nginx-service --port 80 --target-port 80 --type ClusterIP

    Giải thích: Lệnh trên tạo một Service tên nginx-service trong namespace demo, ánh xạ cổng 80 của Service tới cổng 80 của container Nginx (target-port). Loại ClusterIP nghĩa là Service có một IP nội bộ cluster, không tự động mở ra bên ngoài ngay (khác với NodePort hay LoadBalancer).

  • Kiểm tra Service vừa tạo:

    kubectl get svc -n demo

    Bạn sẽ thấy nginx-service với cổng 80 và một Cluster-IP (ví dụ 10.97.x.y). Lúc này, bất kỳ Pod nào trong cluster có thể truy cập Nginx thông qua Cluster-IP này (hoặc tên DNS nginx-service.demo.svc.cluster.local).

Hiện tại, ứng dụng Nginx đang chạy ổn định bên trong cluster. Trong các bước tiếp theo, chúng ta sẽ mở rộng ứng dụng để đảm bảo khả năng phục vụ và cấu hình Ingress để truy cập từ bên ngoài qua tên miền nội bộ thay vì dùng IP và cổng trực tiếp.

Bước 6: Scale ứng dụng Nginx lên hai bản sao và kiểm tra tính năng tự động khôi phục

Một lợi ích lớn của Kubernetes là khả năng scaling (tăng/giảm quy mô) và tự phục hồi (auto-healing) ứng dụng. Chúng ta sẽ thử tăng số lượng Pod Nginx, sau đó giảm lại, và xem Kubernetes tự xử lý việc duy trì trạng thái như thế nào.

1. Mở rộng (scale out) Deployment Nginx thành 2 replicas:
Giả sử ứng dụng cần chịu tải cao hơn, chúng ta tăng số Pod từ 1 lên 2. Có hai cách: chỉnh sửa file YAML hoặc dùng lệnh kubectl scale.

  • Cách 1: Sửa file YAML nginx-deployment.yaml: tìm dòng replicas: 1 và đổi thành replicas: 2. Lưu file và áp dụng lại:

    kubectl apply -f nginx-deployment.yaml
  • Cách 2: Sử dụng lệnh kubectl scale:

    kubectl scale deployment/nginx-deployment -n demo --replicas=2
  • Kiểm tra lại các Pod:

    kubectl get pods -n demo -o wide

    Bây giờ bạn sẽ thấy 2 Pod Nginx chạy (tên Pod khác nhau, có thể trên cùng một node hoặc phân tán nếu có nhiều node). Kubernetes đã nhanh chóng tạo thêm một Pod mới để đạt tổng số 2 như yêu cầu. Good job! Ứng dụng của bạn đã được mở rộng, khả năng phục vụ tăng gấp đôi.

2. Giảm quy mô (scale in) số lượng Pod (tuỳ chọn):
Để thực hành, bạn có thể thử giảm số replica về 1 hoặc thậm chí về 0 (nghĩa là tạm ngừng ứng dụng) bằng lệnh tương tự:

kubectl scale deployment/nginx-deployment -n demo --replicas=1

Kiểm tra lại, chỉ còn 1 Pod chạy. Sau đó, bạn có thể scale lên lại 2 để tiếp tục các bước sau. Kubernetes cho phép thay đổi quy mô dịch vụ rất linh hoạt, chỉ trong vài giây.

3. Kiểm tra tính năng tự động khôi phục (auto-healing):
Kubernetes Deployment (thông qua ReplicaSet) luôn giám sát số Pods thực tế. Nếu một Pod bị lỗi hoặc bị xóa đột ngột, ReplicaSet sẽ tạo Pod mới để bù vào, giữ cho số lượng luôn đúng như cấu hình. Hãy thử:

  • Xóa thủ công một Pod Nginx:
    Lấy tên một Pod Nginx (từ kubectl get pods -n demo), sau đó:

    kubectl delete pod <ten-pod-nginx> -n demo

    Ví dụ: kubectl delete pod nginx-deployment-5bbd6f7f5b-xyz12 -n demo. Lệnh này giả lập tình huống Pod gặp sự cố như lỗi chẳng hạn và bị loại bỏ.

  • Quan sát khả năng tự phục hồi:
    Ngay sau khi xóa, kiểm tra liên tục Pod trong deployment:

    kubectl get pods -n demo -w

    (Tham số -w để vào chế độ watch, lệnh sẽ cập nhật hệ thống liên tục). Bạn sẽ thấy Pod vừa xóa chuyển sang trạng thái Terminating, và chỉ vài giây sau, ReplicaSet tạo một Pod Nginx mới với tên khác để duy trì 2 replica. Khi Pod mới lên trạng thái Running, bạn có thể nhấn Ctrl+C để dừng lệnh watch.
    Kết quả: dù một Pod bị “chết”, ứng dụng vẫn có 2 Pod chạy – Kubernetes đã tự chữa lành (auto-heal) bằng cách khởi động container thay thế.

Kết luận phần này: Cluster của bạn đã mở rộng ứng dụng thành công và thể hiện khả năng tự phục hồi ấn tượng. Những tính năng này giúp ứng dụng trong Kubernetes có độ sẵn sàng và tin cậy cao.

Bước 7 (đã chỉnh): Cấu hình Ingress truy cập ứng dụng qua domain nội bộ.

Hiện tại, để truy cập ứng dụng Nginx từ bên ngoài cluster, ta có thể dùng NodePort (mặc định khi không có LB). Tuy nhiên, giải pháp tốt hơn là sử dụng Ingress kết hợp với một tên miền nội bộ. Ingress cho phép chúng ta định tuyến (route) yêu cầu HTTP(S) đến dịch vụ bên trong cluster thông qua tên host và đường dẫn, thay vì cổng kỹ thuật.

7.1 Cài Ingress-NGINX Controller (NodePort – bare-metal)

Ingress chỉ là các quy tắc (rules); để hiện thực chúng, Kubernetes dùng Ingress Controller – một ứng dụng chạy trong cluster lắng nghe các Ingress và cấu hình proxy tương ứng. Ở đây, chúng ta triển khai Ingress-NGINX Controller – do cộng đồng Kubernetes phát triển (không nên nhầm với sản phẩm NGINX Enterprise).

Triển khai ingress-nginx bằng manifest có sẵn, sử dụng lệnh sau:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.0/deploy/static/provider/baremetal/deploy.yaml
# đợi 20–60s rồi kiểm tra
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

Bạn sẽ thấy ingress-nginx-controller ở trạng thái Running. Service mặc định là NodePort (ví dụ 80:30880/TCP).

7.2 (Quan trọng) Tạo IngressClass nginx nếu chưa có

kubectl get ingressclass
  • Nếu chưa có tên nginx, tạo ngay như sau:

cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx
EOF

7.3 Tạo Ingress cho ứng dụng Nginx (có ingressClassName)

Tạo file nano demo-ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
    name: demo-ingress
    namespace: demo
    annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
spec:
    ingressClassName: nginx # <== IMPORTANT
    rules:
    - host: demo.local
      http:
         paths:
         - path: /
           pathType: Prefix
           backend:
              service:
                  name: nginx-service # service ClusterIP in previous step
                  port:
                     number: 80

Áp dụng:

kubectl apply -f demo-ingress.yaml
kubectl -n demo describe ingress demo-ingress # phải thấy: Ingress Class: nginx

7.4 Cấu hình domain nội bộ (máy client)

Xác định NodePort HTTP của controller (vd: 31186 cần chú ý là trong hệ thống của bạn có thể NodePort HTTP sẽ khác) bằng lệnh sau:

kubectl get svc -n ingress-nginx ingress-nginx-controller

Thêm vào C:\Windows\System32\drivers\etc\hosts của máy client ví dụ Windows PC của bạn như sau:

<IP-một-node-trong-cluster> demo.local
# ví dụ:
192.168.146.166 demo.local

7.5 Truy cập & kiểm tra

  • Mở trình duyệt nhập: http://demo.local:<NodePort>
    (ví dụ: http://demo.local:31186)

  • Hoặc cURL (test chuẩn Host header):

Kỳ vọng: HTTP/1.1 200 OK + trang “Welcome to nginx!”.

Lưu ý: Nếu truy cập bằng IP trực tiếp (không có Host demo.local), ingress-nginx sẽ bị vào tình trạng default backend ⇒ trả 404 Not Found. Đây là hành vi đúng.

Mẹo: Bạn có thể tạo nhiều ingress rule cho các host khác nhau và dịch vụ khác nhau trên cùng một ingress controller. Ví dụ app1.local, app2.local trỏ vào các service khác nhau trong cluster – tất cả đều được xử lý bởi Nginx Ingress controller duy nhất.

Kết luận

Qua hướng dẫn chi tiết này, bạn đã thiết lập thành công một cụm Kubernetes đa nodes trên Ubuntu 24.04, triển khai một ứng dụng Nginx mẫu, mở rộng ứng dụng và cấu hình truy cập thông qua Ingress với tên miền nội bộ. Hãy tự hào vì những gì bạn đã làm được – thật tuyệt vời!

Những gì chúng ta đã thực hiện:

  • Cài đặt các thành phần Kubernetes cần thiết (kubeadm, kubelet, kubectl) và container runtime containerd.

  • Cấu hình hệ thống (tắt swap, bật module kernel) để Kubernetes hoạt động trơn tru.

  • Khởi tạo Master node (control plane) với kubeadm, và join thành công một Worker node vào cluster.

  • Gán nhãn vai trò cho node, tạo Namespace để quản lý tài nguyên theo môi trường riêng.

  • Triển khai Deployment cho ứng dụng container (Nginx) và tạo Service để kết nối mạng nội bộ.

  • Thực hiện scaling (tăng/giảm Pod) và chứng kiến khả năng tự động khôi phục Pod khi gặp sự cố – minh chứng cho tính tự động, khả năng chịu lỗi và ổn định của Kubernetes.

  • Cài đặt Ingress Controller (Nginx) và cấu hình Ingress resource, cho phép truy cập ứng dụng qua một tên miền thân thiện (thông qua sửa file hosts nội bộ trong PC của bạn), thay vì sử dụng cổng NodePort không thuận tiện.

Kubernetes còn rất nhiều tính năng mạnh mẽ khác đang chờ bạn khám phá: Từ cập nhật phát phiên bản không gián đoạn (Rolling Update), tự động scaling dựa trên tải (Horizontal Pod Autoscaler), cho đến quản lý cấu hình bí mật (ConfigMap & Secret), v.v. Hướng dẫn này mới chỉ là bước khởi đầu, nhưng bạn đã nắm được những nền tảng cơ bản quan trọng nhất.

Tiếp theo, bạn có thể thử triển khai thêm các ứng dụng khác trên cluster của mình, thiết lập giám sát (monitoring) với Prometheus/Grafana, hay khám phá chức năng CI/CD tích hợp. Hãy tiếp tục hành trình học hỏi của bạn với Kubernetes – một thế giới #DevOps rộng mở đang đón chờ bạn!

#Kubernetes, #K8s, #Ubuntu, #Docker, #Containerd, #Kubeadm, #Ingress, #DevOps

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *