找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4281

积分

0

好友

599

主题
发表于 1 小时前 | 查看: 1| 回复: 0

基于 kubeadm + Keepalived + HAProxy 构建企业级 HA 集群,涵盖多 Master 架构、etcd 集群、负载均衡、故障转移等核心场景的完整实战指南。

目录

  1. 为什么你的 K8s 集群不够“高可用”?
  2. HA 集群架构设计
  3. 环境规划与准备
  4. 部署负载均衡层
  5. 部署 etcd 集群
  6. 部署多 Master 节点
  7. 部署 Worker 节点
  8. 部署网络插件与存储
  9. 验证高可用能力
  10. 监控与告警配置
  11. 故障排查与恢复
  12. 集群升级与扩展

1. 为什么你的 K8s 集群不够“高可用”?

搭建一个单 Master 的 Kubernetes 集群或许不难,但把它投入生产环境,你可能会在各种意想不到的时刻遭遇“暴击”。高可用不是可选项,而是生产环境的生命线。我们先看几个真实的“翻车”现场。

1.1 真实故障场景回顾

场景 1:单 Master 节点宕机

某创业公司单 Master 集群,Master 节点所在物理机故障,
导致整个集群无法调度新 Pod,API 服务完全不可用。
恢复时间:4 小时
业务损失:订单系统停滞,损失约 50 万元

场景 2:etcd 数据丢失

某电商平台 etcd 单节点部署,磁盘故障导致数据丢失,
整个集群状态信息丢失,无法恢复。
恢复时间:重建集群 8 小时 + 数据恢复 12 小时
业务损失:全平台服务中断,损失约 200 万元

场景 3:网络分区导致脑裂

某金融系统跨机房部署,网络分区导致两个 Master 都认为自己是主节点,
出现脑裂,数据不一致。
恢复时间:6 小时
业务损失:交易数据不一致,需人工对账

这些并非危言耸听,而是每天都在发生的真实故事。单点故障、数据丢失、脑裂问题,每一个都足以让业务停摆。

1.2 高可用核心指标

我们来量化一下,高可用到底带来了哪些提升?

指标 单 Master 多 Master HA 提升
API Server 可用性 99.5% 99.95% ⬆️ 10x
etcd 数据可靠性 单点风险 3 副本冗余 ⬆️ 100x
故障恢复时间 小时级 秒级 ⬆️ 100x
计划内维护 需停机 无感知
脑裂风险 可防控

1.3 高可用层级

高可用是一个立体化的概念,需要从多个层面来构建:

┌─────────────────────────────────────────────────────────┐
│                    应用层高可用                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │  Deployment │  │  StatefulSet│  │  DaemonSet  │     │
│  │  多副本      │  │  持久化存储  │  │  节点级冗余  │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘
                         ▲
┌─────────────────────────────────────────────────────────┐
│                    控制平面高可用                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ 多 Master   │  │ etcd 集群   │  │ 负载均衡器  │     │
│  │  N+1 冗余   │  │  3/5 副本   │  │  双机热备   │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘
                         ▲
┌─────────────────────────────────────────────────────────┐
│                    基础设施高可用                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │  多机房部署  │  │  网络冗余   │  │  存储冗余   │     │
│  │  跨 AZ      │  │  多 CNI     │  │  多 Storage │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘

本文重点聚焦于控制平面高可用,这是构建稳定 Kubernetes 集群的基石。

2. HA 集群架构设计

2.1 推荐架构(3 Master + 3 etcd + N Worker)

我们采用业界广泛验证的经典架构:基于 kubeadm,配合 Keepalived + HAProxy 实现负载均衡和高可用。

                                   ┌─────────────────┐
                                   │   外部负载均衡   │
                                   │  (F5/Nginx/SLB)│
                                   └────────┬────────┘
                                            │
                                   ┌────────▼────────┐
                                   │   VIP 浮动 IP    │
                                   │  (Keepalived)  │
                                   └────────┬────────┘
                                            │
         ┌───────────────────────────────────┼───────────────────────────────────┐
         │                                   │                                   │
         │                          ┌────────▼────────┐                          │
         │                          │   HAProxy 集群   │                          │
         │                          │   (主备模式)     │                          │
         │                          └────────┬────────┘                          │
         │                                   │                                   │
         │              ┌────────────────────┼────────────────────┐              │
         │              │                    │                    │              │
         │    ┌─────────▼─────────┐ ┌────────▼────────┐ ┌────────▼─────────┐    │
         │    │   Master Node 1   │ │  Master Node 2  │ │   Master Node 3  │    │
         │    │                   │ │                 │ │                  │    │
         │    │  - API Server     │ │ - API Server    │ │  - API Server    │    │
         │    │  - Controller     │ │ - Controller    │ │  - Controller    │    │
         │    │  - Scheduler      │ │ - Scheduler     │ │  - Scheduler     │    │
         │    │  - etcd (内嵌)    │ │ - etcd (内嵌)   │ │  - etcd (内嵌)   │    │
         │    └─────────┬─────────┘ └────────┬────────┘ └────────┬─────────┘    │
         │              │                    │                    │              │
         │              └────────────────────┼────────────────────┘              │
         │                                   │                                   │
         │              ┌────────────────────┼────────────────────┐              │
         │              │                    │                    │              │
         │    ┌─────────▼─────────┐ ┌────────▼────────┐ ┌────────▼─────────┐    │
         │    │   Worker Node 1   │ │  Worker Node 2  │ │   Worker Node N  │    │
         │    │                   │ │                 │ │                  │    │
         │    │  - Kubelet        │ │ - Kubelet       │ │  - Kubelet       │    │
         │    │  - Kube-proxy     │ │ - Kube-proxy    │ │  - Kube-proxy    │    │
         │    │  - Container Runtime│- Container Runtime│- Container Runtime│    │
         │    │  - Pod            │ │ - Pod           │ │  - Pod           │    │
         │    └───────────────────┘ └─────────────────┘ └──────────────────┘    │
         │                                                                       │
         └───────────────────────────────────────────────────────────────────────┘

核心思想:所有组件均无单点。

  • 负载均衡:通过 Keepalived 的 VIP 提供单一访问入口,由 HAProxy 将流量分发到后端的多个 API Server。
  • 控制平面:至少三个 Master 节点,奇数个避免脑裂。
  • 数据存储:etcd 以集群模式运行,同样为奇数个副本。

2.2 架构选型对比

没有最好的架构,只有最适合的。下面是几种常见方案的对比:

架构模式 优点 缺点 适用场景
堆叠 etcd 部署简单,资源节省 etcd 与 API Server 相互影响 中小规模集群 (<100 节点)
独立 etcd 性能隔离,更稳定 需要额外节点 大规模集群 (>100 节点)
外部 LB 高可用,性能好 成本高,依赖外部设备 企业生产环境
Keepalived+HAProxy 开源免费,灵活 需要自行维护 通用场景

本文选择 Keepalived+HAProxy 作为负载均衡方案,堆叠式 etcd 以简化部署,这是绝大多数场景下的最佳平衡点。

2.3 网络规划

清晰的网络规划是成功的一半。以下是一个示例方案:

网络规划示例:

管理网络:192.168.1.0/24
  - Master 节点:192.168.1.10-192.168.1.12
  - Worker 节点:192.168.1.20-192.168.1.50
  - HAProxy:192.168.1.5-192.168.1.6
  - VIP:192.168.1.100

Pod 网络:10.244.0.0/16
  - 每个节点分配 /24 子网

Service 网络:10.96.0.0/12

请根据你的实际环境进行调整。

3. 环境规划与准备

3.1 服务器规划

建议的最小化生产环境配置如下:

主机名 IP 地址 角色 配置 数量
lb-01 192.168.1.5 负载均衡主 2C4G 1
lb-02 192.168.1.6 负载均衡备 2C4G 1
master-01 192.168.1.10 控制节点 4C8G 1
master-02 192.168.1.11 控制节点 4C8G 1
master-03 192.168.1.12 控制节点 4C8G 1
worker-01 192.168.1.20 工作节点 8C16G 1
worker-02 192.168.1.21 工作节点 8C16G 1
worker-03 192.168.1.22 工作节点 8C16G 1

说明:Master 节点资源主要用于运行控制平面组件;Worker 节点资源根据实际业务负载决定。

3.2 系统初始化脚本

在所有节点上执行此脚本,完成基础环境配置。

#!/bin/bash
# init.sh - 系统初始化脚本

set -e

echo "========== 开始系统初始化 =========="

# 1. 关闭防火墙
echo "关闭防火墙..."
systemctl stop firewalld || true
systemctl disable firewalld || true
systemctl stop ufw || true
systemctl disable ufw || true

# 2. 关闭 SELinux
echo "关闭 SELinux..."
setenforce 0 || true
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config || true

# 3. 关闭 Swap
echo "关闭 Swap..."
swapoff -a
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

# 4. 配置内核参数
echo "配置内核参数..."
cat > /etc/sysctl.d/k8s.conf << EOF
# 启用 IP 转发
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1

# 桥接网络监听
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1

# 内存管理
vm.swappiness = 0
vm.overcommit_memory = 1
vm.panic_on_oom = 0

# 文件句柄
fs.file-max = 2097152
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 512

# 网络连接
net.core.somaxconn = 32768
net.ipv4.tcp_max_syn_backlog = 8096
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 1024 65535
EOF

sysctl --system

# 5. 配置系统限制
echo "配置系统限制..."
cat > /etc/security/limits.d/k8s.conf << EOF
* soft nofile 65536
* hard nofile 65536
* soft nproc 65536
* hard nproc 65536
* soft memlock unlimited
* hard memlock unlimited
EOF

# 6. 配置时间同步
echo "配置时间同步..."
timedatectl set-timezone Asia/Shanghai
systemctl enable chronyd || systemctl enable ntpd
systemctl start chronyd || systemctl start ntpd

# 7. 配置 hosts
echo "配置 hosts..."
cat >> /etc/hosts << EOF
192.168.1.5   lb-01
192.168.1.6   lb-02
192.168.1.10  master-01
192.168.1.11  master-02
192.168.1.12  master-03
192.168.1.20  worker-01
192.168.1.21  worker-02
192.168.1.22  worker-03
192.168.1.100 k8s-ha-vip
EOF

# 8. 加载内核模块
echo "加载内核模块..."
cat > /etc/modules-load.d/k8s.conf << EOF
overlay
br_netfilter
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
EOF

modprobe overlay
modprobe br_netfilter
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack

# 9. 配置 SSH 免密(可选)
echo "配置 SSH 免密..."
# ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
# ssh-copy-id root@master-01
# ssh-copy-id root@master-02
# ssh-copy-id root@master-03
# ssh-copy-id root@worker-01
# ssh-copy-id root@worker-02
# ssh-copy-id root@worker-03

echo "========== 系统初始化完成 =========="

3.3 安装容器运行时

我们选择 containerd 作为容器运行时,它是目前 Kubernetes 社区推荐的选择。

#!/bin/bash
# install-containerd.sh - 安装 containerd

set -e

echo "========== 安装 containerd =========="

# 1. 安装依赖
apt-get update || yum update -y
apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release || \
yum install -y yum-utils device-mapper-persistent-data lvm2

# 2. 添加 Docker 官方源(containerd)
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg || \
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 3. 安装 containerd
apt-get update || yum makecache fast
apt-get install -y containerd.io || yum install -y containerd.io

# 4. 生成默认配置
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml

# 5. 修改配置(使用 systemd cgroup)
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sed -i 's#k8s.gcr.io/pause:3.6#registry.aliyuncs.com/google_containers/pause:3.9#' /etc/containerd/config.toml

# 6. 启动 containerd
systemctl daemon-reload
systemctl enable containerd
systemctl start containerd

# 7. 验证安装
crictl --runtime-endpoint unix:///run/containerd/containerd.sock info

echo "========== containerd 安装完成 =========="

3.4 安装 Kubernetes 组件

在所有节点上安装 kubelet、kubeadm 和 kubectl。

#!/bin/bash
# install-k8s.sh - 安装 Kubernetes 组件

set -e

# 配置参数
K8S_VERSION="1.28.4"
CR_VERSION="0.12.0"  # crictl 版本

echo "========== 安装 Kubernetes v${K8S_VERSION} =========="

# 1. 添加 Kubernetes 源
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF

# 2. 安装 kubelet, kubeadm, kubectl
yum install -y kubelet-${K8S_VERSION} kubeadm-${K8S_VERSION} kubectl-${K8S_VERSION} --disableexcludes=kubernetes

# 3. 配置 kubelet
cat > /etc/sysconfig/kubelet << EOF
KUBELET_EXTRA_ARGS="--cgroup-driver=systemd --container-runtime-endpoint=unix:///run/containerd/containerd.sock --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9"
EOF

# 4. 启动 kubelet
systemctl daemon-reload
systemctl enable kubelet
systemctl start kubelet

# 5. 安装 crictl
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v${CR_VERSION}/crictl-v${CR_VERSION}-linux-amd64.tar.gz
tar zxvf crictl-v${CR_VERSION}-linux-amd64.tar.gz -C /usr/local/bin
rm -f crictl-v${CR_VERSION}-linux-amd64.tar.gz

# 6. 配置 crictl
cat > /etc/crictl.yaml << EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
debug: false
pull-image-on-create: false
EOF

# 7. 配置 kubectl 自动补全
echo "source <(kubectl completion bash)" >> ~/.bashrc
echo "alias k=kubectl" >> ~/.bashrc
echo "complete -F __start_kubectl k" >> ~/.bashrc

echo "========== Kubernetes 安装完成 =========="
echo "验证安装:"
echo "  kubelet --version"
echo "  kubeadm version"
echo "  kubectl version --client"

4. 部署负载均衡层

高可用的第一道关口。我们将使用 Keepalived 实现 VIP 飘移,HAProxy 实现四层负载均衡。

4.1 部署 Keepalived + HAProxy

lb-01lb-02 节点上执行此脚本。

#!/bin/bash
# deploy-haproxy.sh - 在所有 LB 节点执行

set -e

echo "========== 部署 HAProxy + Keepalived =========="

# 1. 安装 HAProxy 和 Keepalived
yum install -y haproxy keepalived

# 2. 配置 HAProxy
cat > /etc/haproxy/haproxy.cfg << 'EOF'
global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
    mode                    tcp
    log                     global
    option                  tcplog
    option                  dontlognull
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

# API Server 负载均衡
listen k8s-api-server
    bind 0.0.0.0:6443
    mode tcp
    balance roundrobin
    option tcp-check
    server master-01 192.168.1.10:6443 check fall 3 rise 2 inter 5s
    server master-02 192.168.1.11:6443 check fall 3 rise 2 inter 5s
    server master-03 192.168.1.12:6443 check fall 3 rise 2 inter 5s

# kubelet API 负载均衡
listen k8s-kubelet-api
    bind 0.0.0.0:10250
    mode tcp
    balance roundrobin
    option tcp-check
    server worker-01 192.168.1.20:10250 check fall 3 rise 2 inter 5s
    server worker-02 192.168.1.21:10250 check fall 3 rise 2 inter 5s
    server worker-03 192.168.1.22:10250 check fall 3 rise 2 inter 5s

# etcd 负载均衡
listen k8s-etcd
    bind 0.0.0.0:2379
    mode tcp
    balance roundrobin
    option tcp-check
    server master-01 192.168.1.10:2379 check fall 3 rise 2 inter 5s
    server master-02 192.168.1.11:2379 check fall 3 rise 2 inter 5s
    server master-03 192.168.1.12:2379 check fall 3 rise 2 inter 5s

# 健康检查页面
listen stats
    bind 0.0.0.0:8888
    mode http
    stats enable
    stats uri /haproxy?stats
    stats refresh 5s
    stats admin if LOCALHOST
EOF

# 3. 配置 Keepalived(主节点 lb-01)
cat > /etc/keepalived/keepalived.conf << 'EOF'
! Configuration File for keepalived

global_defs {
    router_id LVS_DEVEL
    script_user root
    enable_script_security
}

vrrp_script check_haproxy {
    script "/etc/keepalived/check_haproxy.sh"
    interval 2
    weight -20
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.100/24 dev eth0 label eth0:vip
    }
    track_script {
        check_haproxy
    }
    notify_master "/etc/keepalived/master.sh"
    notify_backup "/etc/keepalived/backup.sh"
    notify_fault "/etc/keepalived/fault.sh"
}
EOF

# 4. 配置 Keepalived(备节点 lb-02)
# 在备节点上,修改 state 为 BACKUP,priority 为 90
cat > /etc/keepalived/keepalived.conf << 'EOF'
! Configuration File for keepalived

global_defs {
    router_id LVS_DEVEL
    script_user root
    enable_script_security
}

vrrp_script check_haproxy {
    script "/etc/keepalived/check_haproxy.sh"
    interval 2
    weight -20
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.100/24 dev eth0 label eth0:vip
    }
    track_script {
        check_haproxy
    }
}
EOF

# 5. 创建健康检查脚本
cat > /etc/keepalived/check_haproxy.sh << 'EOF'
#!/bin/bash
if ! pgrep -x "haproxy" > /dev/null; then
    exit 1
fi
exit 0
EOF
chmod +x /etc/keepalived/check_haproxy.sh

# 6. 创建通知脚本
cat > /etc/keepalived/master.sh << 'EOF'
#!/bin/bash
echo "Become MASTER, start HAProxy"
systemctl start haproxy
EOF
chmod +x /etc/keepalived/master.sh

cat > /etc/keepalived/backup.sh << 'EOF'
#!/bin/bash
echo "Become BACKUP"
EOF
chmod +x /etc/keepalived/backup.sh

cat > /etc/keepalived/fault.sh << 'EOF'
#!/bin/bash
echo "Enter FAULT state"
EOF
chmod +x /etc/keepalived/fault.sh

# 7. 启动服务
systemctl daemon-reload
systemctl enable haproxy
systemctl start haproxy
systemctl enable keepalived
systemctl start keepalived

echo "========== HAProxy + Keepalived 部署完成 =========="
echo "VIP: 192.168.1.100"
echo "HAProxy Stats: http://<IP>:8888/haproxy?stats"

4.2 验证负载均衡

部署完成后,务必进行验证。

# 检查 VIP 状态
ip addr show eth0 | grep 192.168.1.100

# 检查 HAProxy 状态
systemctl status haproxy
curl http://localhost:8888/haproxy?stats

# 测试 API Server 连通性
curl -k https://192.168.1.100:6443/healthz

# 查看连接状态
echo "show stat" | socat stdio /var/lib/haproxy/stats | grep k8s-api-server

5. 部署 etcd 集群

etcd 是 Kubernetes 的“数据库”,其高可用性至关重要。我们采用堆叠式部署,即将 etcd 与 Master 组件部署在同一节点上。

5.1 独立 etcd 集群部署(推荐)

如果你追求更高的性能和稳定性,可以将 etcd 部署在独立的节点上。这里以堆叠式为例,在 Master 节点上部署。

#!/bin/bash
# deploy-etcd.sh - 在 Master 节点执行

set -e

ETCD_VERSION="3.5.9"
CLUSTER_TOKEN="k8s-etcd-cluster"
ETCD_DATA_DIR="/var/lib/etcd"

echo "========== 部署 etcd 集群 =========="

# 1. 下载 etcd
wget https://github.com/etcd-io/etcd/releases/download/v${ETCD_VERSION}/etcd-v${ETCD_VERSION}-linux-amd64.tar.gz
tar zxvf etcd-v${ETCD_VERSION}-linux-amd64.tar.gz
mv etcd-v${ETCD_VERSION}-linux-amd64/{etcd,etcdctl} /usr/local/bin/
rm -rf etcd-v${ETCD_VERSION}-linux-amd64*

# 2. 创建 etcd 用户
useradd -r -s /sbin/nologin etcd
mkdir -p ${ETCD_DATA_DIR}
chown -R etcd:etcd ${ETCD_DATA_DIR}

# 3. 生成 etcd 证书(使用 kubeadm 生成的证书)
# 或手动生成
mkdir -p /etc/kubernetes/pki/etcd

# 4. 配置 etcd 服务(master-01)
cat > /etc/systemd/system/etcd.service << EOF
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
After=network.target

[Service]
Type=notify
User=etcd
Group=etcd
ExecStart=/usr/local/bin/etcd \
  --name=etcd-1 \
  --data-dir=${ETCD_DATA_DIR} \
  --listen-client-urls=https://192.168.1.10:2379,https://127.0.0.1:2379 \
  --advertise-client-urls=https://192.168.1.10:2379 \
  --listen-peer-urls=https://192.168.1.10:2380 \
  --initial-advertise-peer-urls=https://192.168.1.10:2380 \
  --initial-cluster=etcd-1=https://192.168.1.10:2380,etcd-2=https://192.168.1.11:2380,etcd-3=https://192.168.1.12:2380 \
  --initial-cluster-token=${CLUSTER_TOKEN} \
  --initial-cluster-state=new \
  --client-cert-auth=true \
  --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt \
  --cert-file=/etc/kubernetes/pki/etcd/server.crt \
  --key-file=/etc/kubernetes/pki/etcd/server.key \
  --peer-client-cert-auth=true \
  --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt \
  --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt \
  --peer-key-file=/etc/kubernetes/pki/etcd/peer.key \
  --auto-compaction-retention=1 \
  --quota-backend-bytes=8589934592 \
  --heartbeat-interval=250 \
  --election-timeout=2000
Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

# 5. 在 master-02 和 master-03 上修改相应配置
# master-02: name=etcd-2, IP=192.168.1.11
# master-03: name=etcd-3, IP=192.168.1.12

# 6. 启动 etcd
systemctl daemon-reload
systemctl enable etcd
systemctl start etcd

# 7. 验证集群状态
etcdctl --endpoints=https://192.168.1.10:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  member list

etcdctl --endpoints=https://192.168.1.10:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  endpoint status --write-out=table

echo "========== etcd 集群部署完成 =========="

5.2 etcd 性能优化

对于生产环境,建议调整以下参数以获得最佳性能。

# etcd 性能调优参数
# /etc/systemd/system/etcd.service

ExecStart=/usr/local/bin/etcd \
  # 数据目录(使用 SSD)
  --data-dir=/var/lib/etcd \

  # 自动压缩(保留最近 1 小时数据)
  --auto-compaction-retention=1 \

  # 后端数据库大小限制(8GB)
  --quota-backend-bytes=8589934592 \

  # 心跳间隔(250ms)
  --heartbeat-interval=250 \

  # 选举超时(2000ms)
  --election-timeout=2000 \

  # 快照计数
  --snapshot-count=10000 \

  # 最大请求大小(1.5MB)
  --max-request-bytes=1572864 \

  # 预分配空间
  --prealloc=16384 \

5.3 etcd 备份与恢复

定期备份是 etcd 运维的黄金法则。你必须有一个可靠的备份恢复方案。

备份脚本:

#!/bin/bash
# etcd-backup.sh - etcd 备份脚本

set -e

BACKUP_DIR="/backup/etcd"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/etcd-snapshot-${DATE}.db"

mkdir -p ${BACKUP_DIR}

# 备份
etcdctl --endpoints=https://192.168.1.10:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot save ${BACKUP_FILE}

# 验证备份
etcdctl snapshot status ${BACKUP_FILE} --write-out=table

# 清理 7 天前的备份
find ${BACKUP_DIR} -name "etcd-snapshot-*.db" -mtime +7 -delete

echo "备份完成:${BACKUP_FILE}"

恢复脚本:

#!/bin/bash
# etcd-restore.sh - etcd 恢复脚本

set -e

BACKUP_FILE=$1

if [ -z "${BACKUP_FILE}" ]; then
    echo "用法:$0 <备份文件>"
    exit 1
fi

# 停止 etcd
systemctl stop etcd

# 清除旧数据
rm -rf /var/lib/etcd/*

# 恢复数据
etcdctl snapshot restore ${BACKUP_FILE} \
  --data-dir=/var/lib/etcd \
  --name=etcd-1 \
  --initial-cluster=etcd-1=https://192.168.1.10:2380,etcd-2=https://192.168.1.11:2380,etcd-3=https://192.168.1.12:2380 \
  --initial-cluster-token=k8s-etcd-cluster \
  --initial-advertise-peer-urls=https://192.168.1.10:2380

# 设置权限
chown -R etcd:etcd /var/lib/etcd

# 启动 etcd
systemctl start etcd

echo "恢复完成"

6. 部署多 Master 节点

这是构建高可用集群的核心步骤。我们将使用 kubeadm 来初始化第一个 Master,然后将其它 Master 加入集群。

6.1 生成 kubeadm 配置

首先,创建一个详细的 kubeadm 配置文件,它能让你对集群有更精细的控制。

# kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.28.4

# 控制平面配置
controlPlaneEndpoint: "192.168.1.100:6443"  # VIP 地址

# API Server 配置
apiServer:
  certSANs:
  - "192.168.1.100"
  - "192.168.1.10"
  - "192.168.1.11"
  - "192.168.1.12"
  - "kubernetes"
  - "kubernetes.default"
  - "kubernetes.default.svc"
  - "kubernetes.default.svc.cluster.local"
  - "localhost"
  - "127.0.0.1"
  extraArgs:
    authorization-mode: Node,RBAC
    enable-admission-plugins: NodeRestriction,PodSecurityPolicy
    audit-log-path: /var/log/kubernetes/audit.log
    audit-log-maxage: "30"
    audit-log-maxbackup: "10"
    audit-log-maxsize: "100"
  extraVolumes:
  - name: audit-log
    hostPath: /var/log/kubernetes
    mountPath: /var/log/kubernetes
    readOnly: false
    pathType: DirectoryOrCreate

# Controller Manager 配置
controllerManager:
  extraArgs:
    bind-address: 0.0.0.0
    node-cidr-mask-size: "24"
    node-monitor-grace-period: 40s
    pod-eviction-timeout: 5m0s

# Scheduler 配置
scheduler:
  extraArgs:
    bind-address: 0.0.0.0

# etcd 配置(独立部署)
etcd:
  external:
    endpoints:
    - https://192.168.1.10:2379
    - https://192.168.1.11:2379
    - https://192.168.1.12:2379
    caFile: /etc/kubernetes/pki/etcd/ca.crt
    certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
    keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key

# 网络配置
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
  podSubnet: 10.244.0.0/16

# 镜像仓库
imageRepository: registry.aliyuncs.com/google_containers

---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
containerRuntimeEndpoint: unix:///run/containerd/containerd.sock
maxPods: 110
podPidsLimit: 4096
resolvConf: /etc/resolv.conf
rotateCertificates: true
serverTLSBootstrap: true
evictionHard:
  memory.available: "100Mi"
  nodefs.available: "10%"
  nodefs.inodesFree: "5%"
  imagefs.available: "15%"

---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
ipvs:
  strictARP: true
  scheduler: "lc"

6.2 初始化第一个 Master

master-01 节点上执行初始化。

#!/bin/bash
# init-first-master.sh

set -e

echo "========== 初始化第一个 Master 节点 =========="

# 1. 拉取镜像
kubeadm config images pull --config kubeadm-config.yaml

# 2. 初始化集群
kubeadm init --config kubeadm-config.yaml \
  --upload-certs \
  --v=5

# 3. 配置 kubectl
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

# 4. 验证集群
kubectl cluster-info
kubectl get nodes
kubectl get pods -n kube-system

# 5. 保存 join 命令
kubeadm token create --print-join-command > /tmp/join-command.sh
chmod +x /tmp/join-command.sh

# 6. 获取证书密钥
kubeadm init phase upload-certs --upload-certs --config kubeadm-config.yaml

echo "========== 第一个 Master 初始化完成 =========="
echo "请保存以下信息:"
echo "1. Join 命令:cat /tmp/join-command.sh"
echo "2. 证书密钥:kubeadm init phase upload-certs --upload-certs"

6.3 加入其他 Master 节点

master-02master-03 上执行加入操作。

#!/bin/bash
# join-master.sh

set -e

echo "========== 加入 Master 节点 =========="

# 从第一个 Master 复制证书
# 方式 1:使用 kubeadm join 命令(推荐)
kubeadm join 192.168.1.100:6443 \
  --control-plane \
  --certificate-key <certificate-key> \
  --apiserver-advertise-address=<当前节点 IP>

# 方式 2:手动复制证书
# scp root@master-01:/etc/kubernetes/pki/* /etc/kubernetes/pki/
# scp -r root@master-01:/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf

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

echo "========== Master 节点加入完成 =========="

6.4 验证 Master 高可用

所有 Master 加入后,进行高可用性验证。

# 查看所有节点状态
kubectl get nodes -o wide

# 查看控制平面组件
kubectl get pods -n kube-system -l component in (kube-apiserver,kube-controller-manager,kube-scheduler)

# 查看 etcd 状态
kubectl get pods -n kube-system -l component=etcd

# 测试 API Server 故障转移
# 1. 停止 master-01 的 API Server
ssh root@master-01 "systemctl stop kubelet"

# 2. 验证集群仍然可用
kubectl get nodes

# 3. 恢复 master-01
ssh root@master-01 "systemctl start kubelet"

# 查看集群信息
kubectl cluster-info

7. 部署 Worker 节点

控制平面就绪后,就可以将计算节点加入集群了。

7.1 加入 Worker 节点

在 Worker 节点上执行从第一个 Master 获取的 join 命令。

#!/bin/bash
# join-worker.sh

set -e

echo "========== 加入 Worker 节点 =========="

# 在 Master 节点生成 join 命令
# kubeadm token create --print-join-command

# 在 Worker 节点执行
kubeadm join 192.168.1.100:6443 \
  --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash> \
  --apiserver-advertise-address=<当前节点 IP> \
  --node-name=<节点名称> \
  --cri-socket unix:///run/containerd/containerd.sock

# 配置节点标签
kubectl label node worker-01 node-role.kubernetes.io/worker=worker
kubectl label node worker-01 node-type=general

# 配置节点污点(可选)
kubectl taint node worker-01 dedicated=special-workload:NoSchedule

echo "========== Worker 节点加入完成 =========="

7.2 节点配置优化

针对 Worker 节点进行一些优化,以提升稳定性和性能。

#!/bin/bash
# optimize-worker.sh

set -e

# 1. 配置系统参数
cat >> /etc/sysctl.d/k8s-worker.conf << EOF
# 优化网络连接
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# 优化文件句柄
fs.file-max = 2097152
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 8192

# 内存优化
vm.swappiness = 0
vm.overcommit_memory = 1
vm.vfs_cache_pressure = 50
EOF

sysctl --system

# 2. 配置容器运行时
cat >> /etc/containerd/config.toml << EOF

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true

[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
    endpoint = ["https://registry-1.docker.io"]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
    endpoint = ["https://gcr.io"]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
    endpoint = ["https://registry.aliyuncs.com/google_containers"]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
    endpoint = ["https://quay.io"]
EOF

systemctl restart containerd

# 3. 配置 kubelet 参数
cat > /var/lib/kubelet/config.yaml << EOF
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
containerRuntimeEndpoint: unix:///run/containerd/containerd.sock
maxPods: 110
podPidsLimit: 4096
serializeImagePulls: false
imagePullProgressDeadline: 5m
evictionHard:
  memory.available: "100Mi"
  nodefs.available: "10%"
  nodefs.inodesFree: "5%"
  imagefs.available: "15%"
evictionSoft:
  memory.available: "300Mi"
  nodefs.available: "15%"
evictionSoftGracePeriod:
  memory.available: 2m
  nodefs.available: 2m
evictionMaxPodGracePeriod: 180
EOF

systemctl restart kubelet

echo "========== Worker 节点优化完成 =========="

8. 部署网络插件与存储

集群节点就绪后,需要安装网络插件使 Pod 之间能够通信,并配置存储以满足有状态应用的需求。

8.1 部署 Calico 网络

Calico 是性能出色的网络插件,也支持网络策略。

# calico.yaml
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  # 使用 Calico 网络
  variant: Calico

  # 镜像仓库
  registry: registry.aliyuncs.com/calico

  # 网络配置
  calicoNetwork:
    # IP 池配置
    ipPools:
    - blockSize: 26
      cidr: 10.244.0.0/16
      encapsulation: VXLANCrossSubnet
      natOutgoing: Enabled
      nodeSelector: all()

    # BGP 配置(跨子网通信)
    bgp: Enabled

    # 多接口支持
    nodeAddressAutodetectionV4:
      firstFound: true

  # 控制平面副本数
  controlPlaneReplicas: 3

  # 组件配置
  componentResources:
  - componentName: Node
    resourceRequirements:
      requests:
        cpu: 250m
        memory: 64Mi
      limits:
        cpu: 500m
        memory: 128Mi
  - componentName: Typha
    resourceRequirements:
      requests:
        cpu: 100m
        memory: 32Mi
      limits:
        cpu: 200m
        memory: 64Mi

---
apiVersion: operator.tigera.io/v1
kind: APIServer
metadata:
  name: default
spec: {}
# 部署 Calico
kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml
kubectl apply -f calico.yaml

# 验证网络
kubectl get pods -n calico-system
kubectl get nodes -o wide

# 测试网络连通性
kubectl run test1 --image=busybox --restart=Never -- sleep 3600
kubectl run test2 --image=busybox --restart=Never -- sleep 3600
kubectl exec test1 -- ping -c 4 test2

8.2 部署 CoreDNS

CoreDNS 是集群的服务发现核心,需要确保其高可用。

# coredns-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
            ttl 30
        }
        prometheus :9153
        forward . 114.114.114.114 8.8.8.8 {
            max_concurrent 1000
        }
        cache 30
        loop
        reload
        loadbalance
    }
# 部署 CoreDNS(高可用)
kubectl scale deployment coredns -n kube-system --replicas=3

# 配置 Pod 反亲和性
kubectl patch deployment coredns -n kube-system --type=json -p='
[
  {"op": "add", "path": "/spec/template/spec/affinity",
   "value": {
     "podAntiAffinity": {
       "preferredDuringSchedulingIgnoredDuringExecution": [{
         "weight": 100,
         "podAffinityTerm": {
           "labelSelector": {
             "matchExpressions": [{
               "key": "k8s-app",
               "operator": "In",
               "values": ["kube-dns"]
             }]
           },
           "topologyKey": "kubernetes.io/hostname"
         }
       }]
     }
   }
  }
]'

8.3 部署存储(NFS 示例)

为有状态应用提供持久化存储。这里以 NFS 为例创建 StorageClass。

# nfs-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: nfs.csi.k8s.io
parameters:
  server: 192.168.1.50
  share: /data/kubernetes
reclaimPolicy: Retain
volumeBindingMode: Immediate
mountOptions:
  - hard
  - timeo=130
  - retrans=2
  - noresvport
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 100Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs-storage
  nfs:
    server: 192.168.1.50
    path: /data/kubernetes
  mountOptions:
    - hard
    - timeo=130

9. 验证高可用能力

部署完成不代表万事大吉,必须通过测试来验证高可用能力是否真正生效。

9.1 故障转移测试

模拟各种故障场景,观察集群的自我恢复能力。

#!/bin/bash
# ha-test.sh - 高可用测试脚本

set -e

echo "========== 开始高可用测试 =========="

# 测试 1:Master 节点故障
echo "测试 1:Master 节点故障转移"
kubectl get nodes
echo "停止 master-01..."
ssh root@master-01 "systemctl stop kubelet"
sleep 10
kubectl get nodes
echo "恢复 master-01..."
ssh root@master-01 "systemctl start kubelet"
sleep 30

# 测试 2:API Server 故障
echo "测试 2:API Server 故障转移"
echo "停止 master-02 的 API Server..."
ssh root@master-02 "crictl pods --name kube-apiserver -q | xargs -r crictl stopp"
sleep 10
kubectl get nodes
echo "验证 API 可用性..."
kubectl get pods -n kube-system

# 测试 3:etcd 故障
echo "测试 3:etcd 故障转移"
echo "停止 master-03 的 etcd..."
ssh root@master-03 "systemctl stop etcd"
sleep 10
kubectl get nodes
echo "验证集群状态..."
kubectl get pods -n kube-system
echo "恢复 etcd..."
ssh root@master-03 "systemctl start etcd"

# 测试 4:负载均衡故障
echo "测试 4:负载均衡故障转移"
echo "停止 lb-01 的 Keepalived..."
ssh root@lb-01 "systemctl stop keepalived"
sleep 5
echo "检查 VIP 漂移..."
ssh root@lb-02 "ip addr show eth0 | grep 192.168.1.100"
kubectl get nodes
echo "恢复 Keepalived..."
ssh root@lb-01 "systemctl start keepalived"

# 测试 5:网络分区模拟
echo "测试 5:网络分区模拟"
echo "隔离 master-01 的网络..."
ssh root@master-01 "iptables -A INPUT -j DROP"
sleep 30
kubectl get nodes
echo "恢复网络..."
ssh root@master-01 "iptables -F"

echo "========== 高可用测试完成 =========="

9.2 性能基准测试

量化集群的性能表现,建立性能基线。

#!/bin/bash
# performance-test.sh

echo "========== 性能基准测试 =========="

# 1. API Server 响应时间
echo "API Server 响应时间测试..."
for i in {1..100}; do
    start=$(date +%s%N)
    kubectl get pods > /dev/null 2>&1
    end=$(date +%s%N)
    echo "请求 $i: $(( (end - start) / 1000000 )) ms"
done

# 2. Pod 启动时间
echo "Pod 启动时间测试..."
time kubectl run test-perf --image=nginx --restart=Never
kubectl wait --for=condition=ready pod/test-perf --timeout=120s
kubectl delete pod test-perf

# 3. 调度延迟
echo "调度延迟测试..."
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: perf-test
spec:
  replicas: 10
  selector:
    matchLabels:
      app: perf-test
  template:
    metadata:
      labels:
        app: perf-test
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          requests:
            cpu: 100m
            memory: 64Mi
EOF
time kubectl rollout status deployment/perf-test
kubectl delete deployment perf-test

echo "========== 性能测试完成 =========="

10. 监控与告警配置

没有监控的系统就像在黑暗中开车。我们需要一套完整的监控告警体系来保障集群健康。

10.1 部署 Prometheus Operator

使用 Helm 快速部署完整的监控栈。

# 添加 Helm 仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# 部署 kube-prometheus-stack
helm install prometheus prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
  --set prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues=false \
  --set grafana.adminPassword=admin123 \
  --set alertmanager.alertmanagerSpec.replicas=3

10.2 K8s 集群监控告警规则

定义关键的告警规则,以便在问题出现时及时获知。

# k8s-alerts.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: k8s-cluster-alerts
  namespace: monitoring
  labels:
    prometheus: prometheus
    role: alert-rules
spec:
  groups:
  - name: k8s.rules
    rules:
    # Master 节点不可用
    - alert: K8sMasterNodeNotReady
      expr: kube_node_status_condition{node=~".*master.*", condition="Ready", status="true"} == 0
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "Master 节点 {{ $labels.node }} 未就绪"
        description: "Master 节点 {{ $labels.node }} 已经 5 分钟未就绪"

    # Worker 节点不可用
    - alert: K8sWorkerNodeNotReady
      expr: kube_node_status_condition{node=~".*worker.*", condition="Ready", status="true"} == 0
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Worker 节点 {{ $labels.node }} 未就绪"
        description: "Worker 节点 {{ $labels.node }} 已经 5 分钟未就绪"

    # etcd 成员缺失
    - alert: K8sEtcdMemberMissing
      expr: count(etcd_server_has_leader) < 3
      for: 2m
      labels:
        severity: critical
      annotations:
        summary: "etcd 集群成员缺失"
        description: "etcd 集群当前只有 {{ $value }} 个成员,少于 3 个"

    # etcd 无 Leader
    - alert: K8sEtcdNoLeader
      expr: etcd_server_has_leader == 0
      for: 1m
      labels:
        severity: critical
      annotations:
        summary: "etcd 集群无 Leader"
        description: "etcd 集群当前没有 Leader,无法提供服务"

    # API Server 不可用
    - alert: K8sAPIServerDown
      expr: up{job="kubernetes-apiservers"} == 0
      for: 2m
      labels:
        severity: critical
      annotations:
        summary: "API Server 不可用"
        description: "API Server {{ $labels.instance }} 已经 2 分钟不可用"

    # 节点 CPU 使用率过高
    - alert: K8sNodeCPUHigh
      expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "节点 {{ $labels.instance }} CPU 使用率过高"
        description: "节点 {{ $labels.instance }} CPU 使用率 {{ $value }}%"

    # 节点内存使用率过高
    - alert: K8sNodeMemoryHigh
      expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "节点 {{ $labels.instance }} 内存使用率过高"
        description: "节点 {{ $labels.instance }} 内存使用率 {{ $value }}%"

    # Pod 频繁重启
    - alert: K8sPodCrashLooping
      expr: rate(kube_pod_container_status_restarts_total[15m]) * 60 * 5 > 0
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Pod {{ $labels.pod }} 频繁重启"
        description: "Pod {{ $labels.pod }} 在 5 分钟内重启 {{ $value }} 次"

    # 持久卷空间不足
    - alert: K8sPVSpaceLow
      expr: (kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes) * 100 < 15
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "持久卷 {{ $labels.persistentvolumeclaim }} 空间不足"
        description: "持久卷 {{ $labels.persistentvolumeclaim }} 剩余空间 {{ $value }}%"

10.3 Grafana 仪表板

导入预置的仪表板,快速可视化集群状态。

# 导入预置仪表板
# 315 - Kubernetes cluster monitoring (via Prometheus)
# 6417 - Kubernetes API server
# 594 - etcd dashboard
# 7 - Node Exporter Full

# 访问 Grafana
kubectl port-forward svc/prometheus-grafana -n monitoring 3000:80
# 用户名:admin, 密码:admin123

11. 故障排查与恢复

即使做了万全准备,故障仍有可能发生。掌握排查和恢复的方法至关重要。

11.1 常见故障排查

一个集成的排查脚本,可以帮助你快速定位问题。

#!/bin/bash
# troubleshoot.sh - 故障排查脚本

echo "========== K8s 集群故障排查 =========="

# 1. 检查节点状态
echo "=== 节点状态 ==="
kubectl get nodes -o wide
kubectl describe node $(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')

# 2. 检查系统 Pod
echo "=== 系统 Pod 状态 ==="
kubectl get pods -n kube-system -o wide
kubectl get pods -n kube-system --field-selector=status.phase!=Running

# 3. 检查 etcd 状态
echo "=== etcd 状态 ==="
etcdctl --endpoints=https://192.168.1.10:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  endpoint status --write-out=table

# 4. 检查证书有效期
echo "=== 证书有效期 ==="
for cert in /etc/kubernetes/pki/*.crt /etc/kubernetes/pki/etcd/*.crt; do
    echo "$cert:"
    openssl x509 -in $cert -noout -dates
done

# 5. 检查组件日志
echo "=== API Server 日志 ==="
kubectl logs -n kube-system -l component=kube-apiserver --tail=50

echo "=== Controller Manager 日志 ==="
kubectl logs -n kube-system -l component=kube-controller-manager --tail=50

echo "=== Scheduler 日志 ==="
kubectl logs -n kube-system -l component=kube-scheduler --tail=50

# 6. 检查网络
echo "=== 网络连通性 ==="
kubectl run test-network --image=busybox --rm -it --restart=Never -- ping -c 4 kubernetes.default

# 7. 检查资源使用
echo "=== 资源使用 ==="
kubectl top nodes
kubectl top pods -n kube-system

# 8. 检查事件
echo "=== 集群事件 ==="
kubectl get events -n kube-system --sort-by='.lastTimestamp'

11.2 Master 节点恢复

当某个 Master 节点彻底故障时,如何安全地将其移除并重新加入。

#!/bin/bash
# recover-master.sh - Master 节点恢复

set -e

MASTER_TO_RECOVER=$1

if [ -z "${MASTER_TO_RECOVER}" ]; then
    echo "用法:$0 <要恢复的 Master 节点>"
    exit 1
fi

echo "========== 恢复 Master 节点:${MASTER_TO_RECOVER} =========="

# 1. 从集群中移除故障节点
kubectl drain ${MASTER_TO_RECOVER} --ignore-daemonsets --delete-emptydir-data --force
kubectl delete node ${MASTER_TO_RECOVER}

# 2. 在故障节点上重置 kubeadm
ssh root@${MASTER_TO_RECOVER} "kubeadm reset -f"

# 3. 清理证书
ssh root@${MASTER_TO_RECOVER} "rm -rf /etc/kubernetes/pki/*"

# 4. 重新加入集群
ssh root@${MASTER_TO_RECOVER} << 'EOF'
kubeadm join 192.168.1.100:6443 \
  --control-plane \
  --certificate-key <certificate-key> \
  --apiserver-advertise-address=<节点 IP>
EOF

# 5. 验证恢复
kubectl wait node/${MASTER_TO_RECOVER} --for=condition=Ready --timeout=300s

echo "========== Master 节点恢复完成 =========="

11.3 etcd 数据恢复

当 etcd 数据损坏或丢失时,从备份中恢复。

#!/bin/bash
# restore-etcd.sh - etcd 数据恢复

set -e

BACKUP_FILE=$1

if [ -z "${BACKUP_FILE}" ]; then
    echo "用法:$0 <备份文件>"
    exit 1
fi

echo "========== 恢复 etcd 数据 =========="

# 1. 停止所有 Master 节点的 etcd
for node in master-01 master-02 master-03; do
    ssh root@${node} "systemctl stop etcd"
done

# 2. 在 master-01 上恢复数据
ssh root@master-01 << EOF
rm -rf /var/lib/etcd/*
etcdctl snapshot restore ${BACKUP_FILE} \
  --data-dir=/var/lib/etcd \
  --name=etcd-1 \
  --initial-cluster=etcd-1=https://192.168.1.10:2380,etcd-2=https://192.168.1.11:2380,etcd-3=https://192.168.1.12:2380 \
  --initial-cluster-token=k8s-etcd-cluster
chown -R etcd:etcd /var/lib/etcd
systemctl start etcd
EOF

# 3. 在其他节点上重建 etcd
for node in master-02 master-03; do
    ssh root@${node} << EOF
rm -rf /var/lib/etcd/*
systemctl start etcd
EOF
done

# 4. 验证集群
sleep 30
etcdctl --endpoints=https://192.168.1.10:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  endpoint status --write-out=table

echo "========== etcd 数据恢复完成 =========="

12. 集群升级与扩展

集群的运维是持续的过程,包括版本升级和规模伸缩。

12.1 集群升级流程

安全、平滑地升级 Kubernetes 版本。

#!/bin/bash
# upgrade-cluster.sh - 集群升级脚本

set -e

OLD_VERSION="1.28.4"
NEW_VERSION="1.29.0"

echo "========== 升级 K8s 集群:${OLD_VERSION} -> ${NEW_VERSION} =========="

# 1. 升级 kubeadm
yum install -y kubeadm-${NEW_VERSION} --disableexcludes=kubernetes

# 2. 验证升级计划
kubeadm upgrade plan

# 3. 升级第一个 Master
kubeadm upgrade apply v${NEW_VERSION} -y

# 4. 升级其他 Master(逐个)
for node in master-02 master-03; do
    echo "升级 ${node}..."

    # 驱逐节点
    kubectl drain ${node} --ignore-daemonsets --delete-emptydir-data --force

    # 升级 kubelet 和 kubectl
    ssh root@${node} "yum install -y kubelet-${NEW_VERSION} kubectl-${NEW_VERSION} --disableexcludes=kubernetes"

    # 重启 kubelet
    ssh root@${node} "systemctl daemon-reload && systemctl restart kubelet"

    # 升级 kubeadm
    ssh root@${node} "kubeadm upgrade node"

    # 恢复节点
    kubectl uncordon ${node}

    # 验证
    kubectl wait node/${node} --for=condition=Ready --timeout=300s
done

# 5. 升级 Worker 节点
for node in worker-01 worker-02 worker-03; do
    echo "升级 Worker ${node}..."

    kubectl drain ${node} --ignore-daemonsets --delete-emptydir-data --force

    ssh root@${node} "yum install -y kubelet-${NEW_VERSION} kubeadm-${NEW_VERSION} kubectl-${NEW_VERSION} --disableexcludes=kubernetes"
    ssh root@${node} "kubeadm upgrade node"
    ssh root@${node} "systemctl daemon-reload && systemctl restart kubelet"

    kubectl uncordon ${node}
    kubectl wait node/${node} --for=condition=Ready --timeout=300s
done

# 6. 验证升级
kubectl version
kubectl get nodes

echo "========== 集群升级完成 =========="

12.2 添加新节点

水平扩展集群,增加计算能力。

#!/bin/bash
# add-node.sh - 添加新节点

set -e

NEW_NODE_IP=$1
NEW_NODE_NAME=$2

if [ -z "${NEW_NODE_IP}" ] || [ -z "${NEW_NODE_NAME}" ]; then
    echo "用法:$0 <新节点 IP> <新节点名称>"
    exit 1
fi

echo "========== 添加新节点:${NEW_NODE_NAME} (${NEW_NODE_IP}) =========="

# 1. 在新节点上执行系统初始化
ssh root@${NEW_NODE_IP} "bash -s" < init.sh
ssh root@${NEW_NODE_IP} "bash -s" < install-containerd.sh
ssh root@${NEW_NODE_IP} "bash -s" < install-k8s.sh

# 2. 生成 join 命令
JOIN_COMMAND=$(kubeadm token create --print-join-command)

# 3. 加入集群
ssh root@${NEW_NODE_IP} "${JOIN_COMMAND} --node-name=${NEW_NODE_NAME}"

# 4. 配置标签
kubectl label node ${NEW_NODE_NAME} node-role.kubernetes.io/worker=worker

# 5. 验证
kubectl wait node/${NEW_NODE_NAME} --for=condition=Ready --timeout=300s

echo "========== 新节点添加完成 =========="

12.3 移除节点

安全地缩容集群,移除指定节点。

#!/bin/bash
# remove-node.sh - 移除节点

set -e

NODE_NAME=$1

if [ -z "${NODE_NAME}" ]; then
    echo "用法:$0 <节点名称>"
    exit 1
fi

echo "========== 移除节点:${NODE_NAME} =========="

# 1. 驱逐 Pod
kubectl drain ${NODE_NAME} --ignore-daemonsets --delete-emptydir-data --force

# 2. 从集群删除
kubectl delete node ${NODE_NAME}

# 3. 在节点上重置 kubeadm
ssh root@${NODE_NAME} "kubeadm reset -f"

echo "========== 节点移除完成 =========="

总结

恭喜你!至此,一个生产级高可用的 Kubernetes 集群已经部署完成。但这只是开始,持续的运维和优化才是保证其长期稳定运行的关键。

高可用检查清单

部署完成后,对照此清单进行检查:

检查项 状态 说明
Master 节点数量 ✅ 3 个 奇数个,避免脑裂
etcd 集群 ✅ 3 副本 独立部署或堆叠
负载均衡 ✅ Keepalived+HAProxy VIP 浮动
网络插件 ✅ Calico 高性能
DNS 高可用 ✅ CoreDNS×3 反亲和性部署
存储高可用 ✅ NFS/ceph 多副本
监控告警 ✅ Prometheus 完整覆盖
备份策略 ✅ etcd 定时备份 可恢复
证书管理 ✅ 自动轮换 避免过期

性能基准

为你的集群建立性能基线,并定期对比:

指标 目标值
API Server P99 延迟 < 100ms
Pod 启动时间 < 30s
故障恢复时间 < 30s
etcd 写入延迟 < 10ms
网络延迟(同节点) < 0.1ms
网络延迟(跨节点) < 1ms

运维建议

  1. 定期演练:每季度进行故障转移演练,包括 Master 节点、etcd、负载均衡器的故障模拟。
  2. 监控告警:不要满足于默认告警,根据业务特点定制关键指标的告警规则,并确保告警能有效通知到人。
  3. 备份策略:etcd 备份是最后一道防线。除了每日全量备份,在重大变更前一定要手动备份。
  4. 证书管理:证书过期是常见的“低级”故障。利用监控提前告警,或使用 cert-manager 等工具自动管理。
  5. 容量规划:不要让集群“满负荷”运行。节点资源使用率(CPU/内存)建议长期保持在 70% 以下,为突发流量预留缓冲。
  6. 升级策略:关注 Kubernetes 社区发布的安全公告。制定保守的升级策略,小版本可以每季度评估升级一次,大版本升级需要更充分的测试。

写在最后

高可用不是一次性的配置,而是一种持续的状态和运维理念。本文提供的架构和脚本是经过验证的可靠起点,但请务必根据你的具体环境(硬件、网络、业务需求)进行调整和优化。

希望这份详尽的指南能帮助你构建出坚如磐石的 Kubernetes 生产环境。如果你在部署过程中遇到问题,或者有更好的实践经验,欢迎在 云栈社区 的云原生板块与广大开发者交流探讨。

本文基于生产环境实践经验总结,具体配置请根据实际场景调整。
高可用不是配置出来的,是演练出来的!




上一篇:CVE-2026-32635:Angular高危XSS漏洞分析,影响数千Web应用
下一篇:Spring Boot 内嵌 API 安全网关:JWT+限流+权限控制实战
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-20 07:04 , Processed in 0.496141 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表