Hôm trước tôi nâng cụm Kubernetes nội bộ cho team. Cụm này chỉ chạy 3 control plane, VIP cho kube-apiserver, etcd stacked do kubeadm quản lý. Trước khi làm tôi thử rút điện một con control plane để xem kubectl có còn mượt không :))
Kết quả là có lúc chờ hơi lâu vì VIP không kịp chuyển và một apiserver đang lag. Tôi ngồi note lại thành một checklist để lần sau cho anh em trong team sẵn dùng, chia sẻ ai thấy cần thì tham khảo nhé.
Mục tiêu
- Control plane 3 node chịu lỗi ổn. Mất một node,
kubectlvẫn đáp vàschedulervẫn chạy. - TTFB
kubectlp95 trong sự cố vẫn dưới 500 ms trong mạng nội bộ. - Quá trình leader failover của
controller-managervàschedulerdiễn ra nhanh, cỡ 1 đến 2 giây. - Nâng cấp từ
v1.30lênv1.31bằng bằngkubeadmtheo kiểu rolling mà không cắt hơi thở cả cụm (trong on-prem architecture khá nhiều cụm chạy version cũ cũng nhiều lý do mà chưa upgrade).
Kiến trúc gọn để làm việc
3 servers Ubuntu 22.04:
192.168.1.11cp-1192.168.1.12cp-2192.168.1.13cp-3- VIP
192.168.1.10
Thành phần
etcdstacked trên mỗi control plane dokubeadmquản lýkube-apiserverchạy cả 3kube-controller-managervàkube-schedulerchạy cả 3, dùngLeaseđể bầu leader- Lớp truy cập chọn một trong hai:
- Keepalived giữ VIP, HAProxy TCP 6443 cân bằng vào 3
apiserver - Hoặc
kube-vipchạy static pod, announce VIP trực tiếp
- Keepalived giữ VIP, HAProxy TCP 6443 cân bằng vào 3
Chuẩn bị hệ thống
Tắt swap và bật sysctl cần thiết
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes.conf
net.bridge.bridge-nf-call-iptables=1
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables=1
EOF
sudo sysctl --system
Cài containerd và bộ kube
sudo apt-get update && sudo apt-get install -y containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
sudo systemctl enable --now containerd
sudo apt-get install -y apt-transport-https ca-certificates curl
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubeadm=1.30.0-1.1 kubelet=1.30.0-1.1 kubectl=1.30.0-1.1
sudo systemctl enable --now kubelet
Cấu hình VIP kiểu Keepalived + HAProxy
Keepalived
Keepalived vrrp đơn giản:
# /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state BACKUP
interface ens160
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 42secret
}
virtual_ipaddress {
192.168.1.10/24
}
}
HAProxy
HAProxy TCP 6443:
# /etc/haproxy/haproxy.cfg
global
log /dev/log local0
defaults
mode tcp
timeout client 60s
timeout server 60s
timeout connect 5s
frontend fe_k8s
bind 0.0.0.0:6443
default_backend be_k8s
backend be_k8s
option tcp-check
tcp-check connect
server cp1 192.168.1.11:6443 check
server cp2 192.168.1.12:6443 check
server cp3 192.168.1.13:6443 check
Nếu bạn muốn gọn hơn thì kube-vip cũng được. Nhược điểm khó tinh chỉnh health-check kiểu HAProxy.
Khởi tạo control plane bằng kubeadm
Cấu hình kubeadm
Config chuẩn có controlPlaneEndpoint trỏ về VIP.
cat <<EOF > kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.30.0
controlPlaneEndpoint: "192.168.1.10:6443"
networking:
podSubnet: "10.244.0.0/16"
etcd:
local:
dataDir: /var/lib/etcd
apiServer:
extraArgs:
audit-log-maxage: "7"
audit-log-maxbackup: "10"
audit-log-maxsize: "100"
audit-log-path: "/var/log/kubernetes/apiserver/audit.log"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.1.11
bindPort: 6443
nodeRegistration:
criSocket: unix:///run/containerd/containerd.sock
EOF
Chạy lệnh
sudo kubeadm init --config kubeadm-config.yaml
Cài CNI và Join nodes
Cài CNI rồi join thêm hai control plane.
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
kubeadm token create --print-join-command
# Trên cp-2 và cp-3
sudo kubeadm join 192.168.1.10:6443 --token
<token> --discovery-token-ca-cert-hash sha256:<hash> --control-plane
Observability và SLI bắt buộc cho control plane
Tối thiểu có kube-state-metrics, node-exporter, metrics-server hoặc Prometheus Operator. Bạn cần theo dõi:
kube-apiserverrequest duration p95 và p99- Lease leader election của
controller-managervàscheduler etcdbackend commit duration p95- admission webhooks error và saturation của
apiserver
Các kịch bản Chaos Engineering để xác thực cụm HA
A. Tắt kube-apiserver ở cp-1
sudo crictl ps | grep kube-apiserver
sudo crictl stop
<id_apiserver>
Quan sát VIP vẫn nghe 6443, kubectl get pods vẫn trả.
B. Thử nghiệm Node Failure
HAProxy còn 2 backend, workload vẫn chạy. Bạn xem leader của controller-manager có chuyển nhanh không.
C. Thử nghiệm với Latency vàPacket Loss
sudo tc qdisc add dev ens160 root netem delay 200ms loss 20%
sleep 60
sudo tc qdisc del dev ens160 root netem
Bạn đo p95 request apiserver. Lý tưởng vẫn dưới 500 ms.
D. Dừng etcd trên một node
sudo systemctl stop etcd
Xem quorum còn 2 thành viên. API vẫn sống.
Quy trình nâng cấp control plane ít gián đoạn bằng kubeadm
Nguyên tắc
- Nâng từng control plane một. Luôn giữ tối thiểu 2 node hoạt động.
- Không cần
draincontrol plane.Cordonlà đủ. - Thứ tự hay dùng là
cp-2,cp-3, cuối cùngcp-1.
Các bước trên mỗi control plane đích
-
Nâng
kubeadmtrướcsudo apt-get install -y kubeadm=1.31.0-1.1 sudo kubeadm upgrade plan sudo kubeadm upgrade apply v1.31.0 -
Nâng
kubeletvàkubectlsudo apt-get install -y kubelet=1.31.0-1.1 kubectl=1.31.0-1.1 sudo systemctl daemon-reload sudo systemctl restart kubelet -
Kiểm tra health
kubectl get nodes kubectl get --raw /readyz?verbose
Lặp lại node tiếp theo. Xong hết thì nâng cp-1.
Upgrade worker để đồng bộ
Làm rolling từng worker. Respect PodDisruptionBudget. Câu lệnh kubeadm node phase upgrade và nâng kubelet tương tự control plane.
Những pha dễ vấp và cách gỡ
- VIP không chịu failover vì VRRP bị chặn. Kiểm tra firewall, nếu cần dùng unicast VRRP.
- Certificate
apiserversai khiếnHAProxycheck pass nhưngkubectllỗi. Đểkubeadmquản lý PKI trong/etc/kubernetes/pki, đừng chỉnh tay. - Skew version lệch quá 1 minor. Hạ nhiệt, đi từng nấc như tài liệu
kubeadmkhuyến nghị. etcdphình to và chậm. Theo dõi backend size,defragđịnh kỳ.ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key defrag
Bảo mật tối thiểu nên enable
- Audit log cho
apiservernhư config ở trên - RBAC đúng role. Nếu có IdP thì dùng OIDC
- Admission policy chặn image tag
latest, có thể kèm Cosign verify nếu bạn làm supply chain - Gia hạn certificate tự động bằng
kubeadm certificates renew. Có cron check hạn trước 30 ngày
Checklist
- Dashboard RED cho
apiservervà SLO p95 request - Thử nghiệm rút một
apiserverhàng tháng để tự tin khi có sự cố etcdsnapshot hàng giờ lên object storage và thử restore mỗi quý- Kế hoạch upgrade có thời lượng rõ ràng và một lối quay đầu về gói
kubecũ
Rollback nhanh khi gặp xui
- Một control plane nâng xong mà
apiserverkhông lên. Cài lại góikubeadmvàkubeletphiên cũ, kiểm chứng PKI, restartkubelet. - Nhiều control plane dính lỗi cùng lúc. Hãy giữ VIP ở con còn hoạt động bằng priority cao hơn trong
keepalived. Sửa từng máy một.
Thế là hết rồi đấy
Nếu có update thêm gì tôi sẽ cập nhật. Còn cơ bản thì là như vậy đó, tôi thấy mấu chốt là khả năng failover của VIP phải hiệu quả, luôn có ít nhất hai instance apiserver hoạt động, etcd duy trì được quorum, và việc nâng cấp phải theo từng staged, đồng thời được giám sát chặt chẽ qua metrics. Bạn có thể bắt đầu bằng việc dựng đủ ba node, bật metric, chạy các kịch bản giả lập sự cố đã nêu. Sau đó, khi thực hiện nâng cấp thật, bạn sẽ tự tin hơn rất nhiều.




