Công nghệ IT
Hướng dẫn cài đặt Kubernetes Master-Node trên Ubuntu 24.04.2
imageimage
Thoại Kỳ
08-07-2025
424 lượt xem

Hướng dẫn cài đặt Kubernetes Master-Node trên Ubuntu 24.04.2 bằng Script

Hướng dẫn cài đặt Kubernetes Control Plane + Worker Node trên Ubuntu 24.04.2

Tài liệu này dùng cho môi trường lab/dev với 2 máy ảo Ubuntu 24.04.2: 1 node Control Plane và 1 Worker Node.

Kubernetes hiện không còn khuyến nghị dùng từ “Master” trong tài liệu chính thức; tuy nhiên trong bài này có thể hiểu k8s-masterControl Plane node.

1. Thông tin cập nhật

Bản hướng dẫn cũ dùng Kubernetes v1.29, hiện đã lỗi thời. File README này đã được chỉnh theo hướng:

  • Dùng Kubernetes v1.36 thông qua repo mới pkgs.k8s.io.
  • Không disable/purge AppArmor mặc định.
  • Không khuyến nghị disable UFW cho production/staging; chỉ disable nếu đang lab và bạn chủ động bật biến LAB_DISABLE_UFW=true.
  • Dùng containerd làm container runtime.
  • Cấu hình SystemdCgroup = true cho containerd.
  • Dùng Flannel release cố định thay vì trỏ vào nhánh master của GitHub.
  • Bổ sung bước kiểm tra, join node và cleanup rõ ràng hơn.

Ghi chú: Nếu muốn dùng version Kubernetes khác, chỉ cần đổi biến K8S_VERSION, ví dụ v1.35 hoặc v1.34. Không nên dùng version đã hết support cho môi trường thật.


2. Mô hình lab đề xuất

HostnameVai tròIP ví dụ
k8s-masterControl Plane192.168.76.10
k8s-node-1Worker Node192.168.76.11

Bạn cần thay IP ví dụ bằng IP thật của máy ảo của bạn.


3. Yêu cầu trước khi cài

Trên cả 2 máy Ubuntu:

  • Ubuntu 24.04.2.
  • Tối thiểu 2 CPU, 2 GB RAM cho lab.
  • 2 máy ping được nhau bằng IP.
  • Có quyền sudo.
  • Đã cấu hình IP tĩnh hoặc DHCP reservation.
  • Hostname của các node không được trùng nhau.
  • Swap phải được tắt.

Kiểm tra nhanh:

bash
free -h nproc hostname ip addr cat /sys/class/dmi/id/product_uuid

Nếu bạn clone VM, hãy đảm bảo hostname và product_uuid không bị trùng giữa các node.


4. Các file cần tạo

Bạn sẽ tạo 3 file:

text
common_setup.sh # Chạy trên cả Control Plane và Worker Node master_setup.sh # Chỉ chạy trên Control Plane node node_join.sh # Chỉ chạy trên Worker Node

5. Cấu hình hostname và /etc/hosts

Trên Control Plane node

bash
sudo hostnamectl set-hostname k8s-master

Trên Worker Node

bash
sudo hostnamectl set-hostname k8s-node-1

Trên cả 2 máy

Mở file:

bash
sudo nano /etc/hosts

Thêm nội dung, nhớ thay IP theo môi trường thật của bạn:

text
192.168.76.10 k8s-master 192.168.76.11 k8s-node-1

Kiểm tra:

bash
ping -c 3 k8s-master ping -c 3 k8s-node-1

6. File common_setup.sh

Chạy file này trên cả Control Plane và Worker Node.

Tạo file:

bash
nano common_setup.sh

Dán nội dung sau:

bash
#!/usr/bin/env bash set -euo pipefail # ============================================================ # Common setup for Kubernetes nodes on Ubuntu 24.04.2 # Run on both Control Plane and Worker nodes # ============================================================ K8S_VERSION="${K8S_VERSION:-v1.36}" LAB_DISABLE_UFW="${LAB_DISABLE_UFW:-false}" log() { echo "" echo "==> $1" } log "Starting common Kubernetes setup" log "1. Updating system packages" sudo apt-get update -y sudo apt-get upgrade -y log "2. Disabling swap" sudo swapoff -a sudo sed -i.bak '/ swap / s/^/#/' /etc/fstab log "3. Configuring firewall policy" if command -v ufw >/dev/null 2>&1; then if [ "${LAB_DISABLE_UFW}" = "true" ]; then echo "LAB_DISABLE_UFW=true, disabling UFW for lab environment only." sudo ufw disable || true else echo "UFW will NOT be disabled." echo "If UFW is enabled, make sure required Kubernetes ports are allowed." echo "For quick lab only, you may run: LAB_DISABLE_UFW=true ./common_setup.sh" fi fi log "4. Keeping AppArmor enabled" echo "AppArmor is not disabled or purged. Only change AppArmor if you have a specific runtime/CNI error." log "5. Loading kernel modules and sysctl settings" cat <<'EOF_K8S_MODULES' | sudo tee /etc/modules-load.d/k8s.conf >/dev/null overlay br_netfilter EOF_K8S_MODULES sudo modprobe overlay sudo modprobe br_netfilter cat <<'EOF_K8S_SYSCTL' | sudo tee /etc/sysctl.d/k8s.conf >/dev/null net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF_K8S_SYSCTL sudo sysctl --system log "6. Installing containerd" sudo apt-get install -y ca-certificates curl gpg apt-transport-https sudo install -m 0755 -d /etc/apt/keyrings if [ ! -f /etc/apt/keyrings/docker.gpg ]; then curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg fi UBUNTU_CODENAME="$(. /etc/os-release && echo "${VERSION_CODENAME}")" ARCH="$(dpkg --print-architecture)" cat <<EOF_DOCKER_REPO | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ${UBUNTU_CODENAME} stable EOF_DOCKER_REPO sudo apt-get update -y sudo apt-get install -y containerd.io log "7. Configuring containerd with systemd cgroup driver" sudo mkdir -p /etc/containerd sudo containerd config default | sudo tee /etc/containerd/config.toml >/dev/null # This works for containerd config generated by the package. # Kubernetes requires kubelet and container runtime to use compatible cgroup drivers. sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml # Make sure CRI plugin is not disabled. sudo sed -i 's/^disabled_plugins = \["cri"\]/disabled_plugins = []/' /etc/containerd/config.toml || true sudo systemctl restart containerd sudo systemctl enable containerd log "8. Adding Kubernetes apt repository: ${K8S_VERSION}" sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL "https://pkgs.k8s.io/core:/stable:/${K8S_VERSION}/deb/Release.key" \ | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg cat <<EOF_K8S_REPO | sudo tee /etc/apt/sources.list.d/kubernetes.list >/dev/null deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${K8S_VERSION}/deb/ / EOF_K8S_REPO log "9. Installing kubelet, kubeadm, kubectl" sudo apt-get update -y sudo apt-get install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl sudo systemctl enable kubelet log "10. Version check" containerd --version || true kubeadm version || true kubectl version --client || true log "Common setup completed" echo "Please reboot this node before running master_setup.sh or node_join.sh." echo "Command: sudo reboot"

Cấp quyền chạy:

bash
chmod +x common_setup.sh

Chạy trên cả 2 máy:

bash
./common_setup.sh

Nếu chỉ dùng lab và muốn tắt UFW tự động:

bash
LAB_DISABLE_UFW=true ./common_setup.sh

Sau khi chạy xong, reboot cả 2 máy:

bash
sudo reboot

7. Nếu không disable UFW, mở port cần thiết

Nếu UFW đang bật, bạn cần mở port Kubernetes.

Trên Control Plane node

bash
sudo ufw allow 6443/tcp sudo ufw allow 2379:2380/tcp sudo ufw allow 10250/tcp sudo ufw allow 10257/tcp sudo ufw allow 10259/tcp

Trên Worker Node

bash
sudo ufw allow 10250/tcp sudo ufw allow 10256/tcp sudo ufw allow 30000:32767/tcp sudo ufw allow 30000:32767/udp

Flannel VXLAN

Flannel VXLAN thường cần UDP 8472 giữa các node:

bash
sudo ufw allow 8472/udp

8. File master_setup.sh

Chỉ chạy file này trên Control Plane node.

Tạo file:

bash
nano master_setup.sh

Dán nội dung sau:

bash
#!/usr/bin/env bash set -euo pipefail # ============================================================ # Kubernetes Control Plane setup # Run only on the Control Plane node # ============================================================ POD_CIDR="${POD_CIDR:-10.244.0.0/16}" MASTER_IP="${MASTER_IP:-$(hostname -I | awk '{print $1}')}" FLANNEL_VERSION="${FLANNEL_VERSION:-v0.28.5}" log() { echo "" echo "==> $1" } log "Checking swap status" if swapon --show | grep -q .; then echo "ERROR: Swap is still enabled. Please disable swap before continuing." swapon --show exit 1 fi log "Initializing Kubernetes Control Plane" echo "MASTER_IP=${MASTER_IP}" echo "POD_CIDR=${POD_CIDR}" sudo kubeadm init \ --apiserver-advertise-address="${MASTER_IP}" \ --pod-network-cidr="${POD_CIDR}" \ --cri-socket=unix:///run/containerd/containerd.sock \ | tee kubeadm-init.log log "Configuring kubectl for current user" mkdir -p "${HOME}/.kube" sudo cp -f /etc/kubernetes/admin.conf "${HOME}/.kube/config" sudo chown "$(id -u):$(id -g)" "${HOME}/.kube/config" log "Installing Flannel CNI ${FLANNEL_VERSION}" kubectl apply -f "https://github.com/flannel-io/flannel/releases/download/${FLANNEL_VERSION}/kube-flannel.yml" log "Control Plane setup completed" echo "" echo "Check cluster status:" echo " kubectl get nodes -o wide" echo " kubectl get pods -A" echo "" echo "Save the kubeadm join command printed above." echo "If you lost it, regenerate it with:" echo " kubeadm token create --print-join-command"

Cấp quyền chạy:

bash
chmod +x master_setup.sh

Chạy:

bash
./master_setup.sh

Nếu máy có nhiều network interface, nên truyền IP rõ ràng:

bash
MASTER_IP=192.168.76.10 ./master_setup.sh

Sau khi chạy xong, kiểm tra:

bash
kubectl get nodes -o wide kubectl get pods -A

Control Plane node có thể chưa Ready ngay lập tức. Đợi Flannel chạy xong rồi kiểm tra lại.


9. Lấy lệnh join node

Sau khi kubeadm init thành công, output sẽ có lệnh dạng:

bash
kubeadm join 192.168.76.10:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>

Nếu quên hoặc token hết hạn, chạy trên Control Plane:

bash
kubeadm token create --print-join-command

Copy lệnh này để dùng cho Worker Node.


10. File node_join.sh

Chỉ chạy file này trên Worker Node.

Tạo file:

bash
nano node_join.sh

Dán nội dung sau:

bash
#!/usr/bin/env bash set -euo pipefail # ============================================================ # Join Worker Node to Kubernetes cluster # Run only on Worker Node # ============================================================ # Replace this value with the real command from kubeadm init output. # Example: # KUBEADM_JOIN_COMMAND='kubeadm join 192.168.76.10:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:xxxxxxxxxx' KUBEADM_JOIN_COMMAND='<PASTE_REAL_KUBEADM_JOIN_COMMAND_HERE>' log() { echo "" echo "==> $1" } log "Checking kubeadm join command" if [ "${KUBEADM_JOIN_COMMAND}" = "<PASTE_REAL_KUBEADM_JOIN_COMMAND_HERE>" ]; then echo "ERROR: Please replace KUBEADM_JOIN_COMMAND with the real kubeadm join command from Control Plane." exit 1 fi log "Checking swap status" if swapon --show | grep -q .; then echo "ERROR: Swap is still enabled. Please disable swap before continuing." swapon --show exit 1 fi log "Joining Worker Node to cluster" sudo ${KUBEADM_JOIN_COMMAND} --cri-socket=unix:///run/containerd/containerd.sock log "Worker Node joined" echo "Please go back to Control Plane and run:" echo " kubectl get nodes -o wide"

Cấp quyền chạy:

bash
chmod +x node_join.sh

Sửa dòng này bằng lệnh thật:

bash
KUBEADM_JOIN_COMMAND='<PASTE_REAL_KUBEADM_JOIN_COMMAND_HERE>'

Ví dụ:

bash
KUBEADM_JOIN_COMMAND='kubeadm join 192.168.76.10:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'

Chạy:

bash
./node_join.sh

11. Kiểm tra cluster trên Control Plane

Chạy trên k8s-master:

bash
kubectl get nodes -o wide kubectl get pods -A

Kết quả mong muốn:

text
NAME STATUS ROLES AGE VERSION k8s-master Ready control-plane ... v1.36.x k8s-node-1 Ready <none> ... v1.36.x

Kiểm tra runtime:

bash
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.containerRuntimeVersion}{"\n"}{end}'

12. Deploy thử một ứng dụng Nginx

Chạy trên Control Plane:

bash
kubectl create deployment nginx-demo --image=nginx:stable kubectl expose deployment nginx-demo --type=NodePort --port=80 kubectl get pods -o wide kubectl get svc nginx-demo

Lấy NodePort:

bash
kubectl get svc nginx-demo

Truy cập thử:

bash
curl http://<NODE_IP>:<NODE_PORT>

Ví dụ:

bash
curl http://192.168.76.11:30080

Xóa demo:

bash
kubectl delete svc nginx-demo kubectl delete deployment nginx-demo

13. Troubleshooting nhanh

Node ở trạng thái NotReady

Kiểm tra CNI:

bash
kubectl get pods -n kube-flannel kubectl get pods -A

Kiểm tra kubelet:

bash
sudo systemctl status kubelet --no-pager sudo journalctl -u kubelet -xe --no-pager

Lỗi container runtime hoặc CRI

Kiểm tra containerd:

bash
sudo systemctl status containerd --no-pager sudo journalctl -u containerd -xe --no-pager sudo crictl info

Kiểm tra socket:

bash
ls -l /run/containerd/containerd.sock

Lỗi swap

bash
swapon --show free -h

Nếu swap còn bật:

bash
sudo swapoff -a sudo sed -i.bak '/ swap / s/^/#/' /etc/fstab sudo reboot

Lỗi token join hết hạn

Chạy trên Control Plane:

bash
kubeadm token create --print-join-command

Kiểm tra port API server từ Worker Node

Chạy trên Worker Node:

bash
nc -vz k8s-master 6443

Nếu không có nc:

bash
sudo apt-get install -y netcat-openbsd nc -vz k8s-master 6443

14. Xóa sạch Kubernetes và dữ liệu liên quan

Thực hiện trên tất cả node bạn muốn xóa Kubernetes.

Cảnh báo: Các lệnh dưới đây sẽ xóa trạng thái cluster trên node. Nếu chạy trên Control Plane và xóa /var/lib/etcd, dữ liệu cluster sẽ mất.

Bước 1: Reset kubeadm

bash
sudo kubeadm reset -f

Bước 2: Xóa cấu hình CNI

bash
sudo rm -rf /etc/cni/net.d sudo rm -rf /var/lib/cni

Bước 3: Xóa cấu hình Kubernetes và kubelet

bash
sudo rm -rf /etc/kubernetes sudo rm -rf /var/lib/kubelet sudo rm -rf /var/lib/dockershim sudo rm -rf /var/run/kubernetes

Bước 4: Xóa dữ liệu etcd trên Control Plane nếu muốn xóa hoàn toàn cluster

Chỉ chạy trên Control Plane cũ nếu bạn muốn xóa sạch cluster state:

bash
sudo rm -rf /var/lib/etcd

Bước 5: Gỡ package Kubernetes

bash
sudo apt-mark unhold kubelet kubeadm kubectl || true sudo apt-get purge -y kubeadm kubectl kubelet kubernetes-cni || true sudo apt-get autoremove -y

Bước 6: Xóa kubeconfig của user hiện tại

bash
rm -rf "${HOME}/.kube"

Bước 7: Xóa containerd nếu muốn xóa cả container runtime

Nếu bạn muốn giữ containerd cho việc khác, bỏ qua bước này.

bash
sudo systemctl stop containerd || true sudo apt-get purge -y containerd.io || true sudo rm -rf /var/lib/containerd sudo rm -rf /etc/containerd

Bước 8: Xóa iptables rule do Kubernetes/CNI tạo ra

Chỉ chạy khi bạn chắc chắn node này không còn dùng iptables rule quan trọng cho dịch vụ khác.

bash
sudo iptables -F sudo iptables -t nat -F sudo iptables -t raw -F sudo iptables -t mangle -F sudo iptables -X sudo iptables -t nat -X sudo iptables -t raw -X sudo iptables -t mangle -X

Nếu hệ thống dùng nftables, có thể kiểm tra thêm:

bash
sudo nft list ruleset

Không flush toàn bộ nftables nếu máy đang dùng firewall cho dịch vụ khác.

Bước 9: Tắt swap lại nếu cần

bash
sudo swapoff -a sudo sed -i.bak '/ swap / s/^/#/' /etc/fstab

Bước 10: Reboot

bash
sudo reboot

15. Tài liệu tham khảo