4. Kubernetes集群部署:kubeadm部署生产级集群、高可用架构设计、集群升级与备份策略

聊到Kubernetes集群部署,我见过不少团队在这个环节栽跟头。有人图省事直接用minikube上生产,有人照着官方文档一步步来结果网络插件死活起不来。说实话,部署一个能用的集群不难,难的是部署一个能扛住生产压力的集群。今天我就把这几年的实战经验掰开揉碎,跟你聊聊怎么用kubeadm搭一套靠谱的生产级集群。

4.1 为什么选kubeadm?

市面上部署K8s的工具不少,kops、kubespray、Rancher各有千秋。但我个人习惯用kubeadm。为什么?因为它够轻量、够标准。kubeadm是Kubernetes官方出品的部署工具,说白了就是把集群初始化的流程封装成了几个命令。你不需要理解背后所有的证书签发、组件启动细节,但又能保留对集群的完全控制权。

我在项目中遇到过用一键部署工具翻车的情况——版本依赖锁死、自定义配置困难、出了问题都不知道日志在哪。kubeadm就没这毛病,它生成的集群跟手动搭建的几乎一样,后续运维起来特别顺手。

4.2 环境准备:别在起跑线上摔倒

部署之前,先把环境收拾利索。我见过太多人上来就装,结果卡在某个依赖上半天找不出原因。

⚠️ 重要提醒: 所有节点的时间必须同步!K8s的证书验证依赖时间戳,时间偏差超过5分钟,集群直接罢工。我曾经半夜被叫起来处理集群不可用,最后发现是NTP服务挂了。

节点规划建议:

  • Master节点: 至少3台,奇数台。etcd需要多数派才能工作,3台能容忍1台故障,5台能容忍2台
  • Worker节点: 根据业务量来,建议从3台起步
  • 操作系统: Ubuntu 22.04 LTS 或 CentOS 7.9+,内核版本不低于5.4
  • 容器运行时: containerd 1.6+,别用Docker了,K8s 1.24以后已经弃用Docker作为运行时

基础配置清单:

# 关闭swap
sudo swapoff -a
# 永久关闭(编辑/etc/fstab注释掉swap行)

# 加载内核模块
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# 设置内核参数
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sudo sysctl --system

4.3 使用kubeadm部署生产级集群

环境准备好了,咱们开始动手。我会把步骤拆开讲,每一步都告诉你为什么这么做。

4.3.1 安装kubeadm、kubelet、kubectl

这三个组件版本必须一致。我习惯用阿里云的镜像源,国内下载速度快很多。

# 添加Kubernetes源
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl

curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg

echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubelet=1.28.0-00 kubeadm=1.28.0-00 kubectl=1.28.0-00
sudo apt-mark hold kubelet kubeadm kubectl
💡 小技巧: 用apt-mark hold锁定版本,防止意外升级导致集群版本不一致。我见过有人没锁版本,apt upgrade后kubelet和kubeadm版本对不上,集群直接崩了。

4.3.2 初始化第一个Master节点

初始化之前,先准备好配置文件。我个人习惯用配置文件而不是命令行参数,这样后续升级、重建都能复用。

cat <<EOF | sudo tee kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: "192.168.1.10"  # 改成你的Master IP
  bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: "v1.28.0"
controlPlaneEndpoint: "192.168.1.100:6443"  # 负载均衡器地址
apiServer:
  extraArgs:
    authorization-mode: "Node,RBAC"
controllerManager: {}
scheduler: {}
etcd:
  local:
    dataDir: "/var/lib/etcd"
networking:
  serviceSubnet: "10.96.0.0/12"
  podSubnet: "10.244.0.0/16"
  dnsDomain: "cluster.local"
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"  # 使用IPVS模式,性能更好
EOF

sudo kubeadm init --config=kubeadm-config.yaml --upload-certs

这里有个关键点——controlPlaneEndpoint。生产环境一定要配负载均衡器,别直接把Master IP写死。你想想看,如果Master挂了,kubelet连不上API Server,整个集群就瘫痪了。用负载均衡器,至少能保证API Server的高可用。

4.3.3 加入其他Master节点

初始化完成后,会输出一条join命令,类似这样:

kubeadm join 192.168.1.100:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx --control-plane --certificate-key xxxxx

在另外两台Master上执行这条命令就行。注意--control-plane参数,不加的话会当成Worker节点加入。

⚠️ 踩坑记录: token有效期默认24小时,certificate-key有效期2小时。如果超时了,用kubeadm token create --print-join-command重新生成。我曾经因为准备环境花了太久,结果token过期了,排查了半天才发现。

4.3.4 安装网络插件

集群初始化后,CoreDNS会一直处于Pending状态,因为还没装网络插件。我推荐Calico,功能全面、性能稳定。

kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26/manifests/custom-resources.yaml

等几分钟,确认所有Pod都Running了:

kubectl get pods -n calico-system
kubectl get nodes  # 所有节点都应该是Ready状态

4.4 高可用架构设计

单Master集群玩玩还行,上生产必须高可用。高可用说白了就是:任何一个组件挂了,集群还能正常工作。

4.4.1 控制平面高可用

控制平面的核心是API Server、Controller Manager、Scheduler和etcd。API Server是无状态的,前面挂负载均衡器就行。Controller Manager和Scheduler通过选主机制实现高可用——同一时间只有一个实例在工作,主挂了备自动顶上。

etcd是状态存储,它的高可用最复杂。我建议用独立的etcd集群,别跟K8s控制平面混部。原因很简单:etcd对磁盘IO敏感,跟其他组件抢资源容易出问题。

组件 高可用方式 推荐数量
API Server 负载均衡器 + 多实例 3台
Controller Manager 选主(Leader Election) 3台
Scheduler 选主(Leader Election) 3台
etcd Raft共识算法 3台或5台

4.4.2 负载均衡器配置

负载均衡器可以用硬件F5,也可以用软件方案。我个人推荐HAProxy + Keepalived,简单可靠。

# HAProxy配置示例
frontend kubernetes-frontend
    bind *:6443
    mode tcp
    option tcplog
    default_backend kubernetes-backend

backend kubernetes-backend
    mode tcp
    option tcp-check
    balance roundrobin
    server master1 192.168.1.10:6443 check fall 3 rise 2
    server master2 192.168.1.11:6443 check fall 3 rise 2
    server master3 192.168.1.12:6443 check fall 3 rise 2
🔑 关键点: 负载均衡器本身也要高可用。用Keepalived给HAProxy配一个VIP,两台HAProxy一主一备。这样负载均衡器挂了也不影响集群访问。

4.5 集群升级策略

升级K8s集群,说白了就是版本迭代。但K8s的升级有个铁律:只能逐版本升级,不能跨大版本。比如1.27升1.28可以,1.27直接升1.29不行。

4.5.1 升级前的准备工作

我每次升级前都会做这几件事:

  • 备份etcd: 这是最重要的,etcd里存着集群的所有状态
  • 检查API兼容性:kubectl convert检查旧API是否被废弃
  • 查看变更日志: 重点关注不兼容的变更
  • 先在测试环境验证: 千万别直接上生产,我吃过这个亏

4.5.2 升级步骤

升级顺序是:先升级Master节点,再升级Worker节点。每个节点都要先升级kubeadm,再升级kubelet和kubectl。

# 1. 在Master节点上升级kubeadm
sudo apt-get update
sudo apt-get install -y kubeadm=1.28.1-00 --allow-change-held-packages

# 2. 检查升级计划
sudo kubeadm upgrade plan

# 3. 执行升级
sudo kubeadm upgrade apply v1.28.1

# 4. 升级kubelet和kubectl
sudo apt-get install -y kubelet=1.28.1-00 kubectl=1.28.1-00 --allow-change-held-packages
sudo systemctl restart kubelet

# 5. 确认节点状态
kubectl get nodes
💡 经验之谈: Worker节点升级时,先执行kubectl drain驱逐Pod,升级完再执行kubectl uncordon。这样能保证业务不中断。我习惯一次升级一个Worker节点,观察10分钟没问题再升级下一个。

4.6 备份策略:别等出事了才后悔

备份这事,说起来简单做起来难。我见过太多团队备份脚本写好了但从来没验证过恢复流程,真到出事了才发现备份文件是坏的。

4.6.1 备份什么

K8s集群需要备份的核心数据:

  • etcd数据: 集群的所有资源对象、配置信息
  • 证书文件: /etc/kubernetes/pki/ 目录下的所有文件
  • kubeadm配置: 初始化时用的配置文件
  • 存储类配置: 如果有自定义的StorageClass

4.6.2 备份etcd

etcd备份推荐用etcdctl的snapshot命令:

# 创建快照
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 \
  snapshot save /backup/etcd-snapshot-$(date +%Y%m%d).db

# 恢复快照(在etcd数据目录清空后执行)
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot-20240101.db \
  --data-dir=/var/lib/etcd-restore
⚠️ 重要: 备份文件要存到远程存储,别跟集群放在同一台机器上。我习惯每天凌晨做一次全量备份,保留最近7天的备份。另外,每个月至少做一次恢复演练,确保备份文件可用。

4.6.3 自动化备份脚本

手动备份不靠谱,写个定时任务吧:

#!/bin/bash
# /usr/local/bin/etcd-backup.sh

BACKUP_DIR="/backup/etcd"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7

mkdir -p $BACKUP_DIR

ETCDCTL_API=3 etcdctl snapshot save $BACKUP_DIR/snapshot_$DATE.db \
  --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

# 压缩并上传到远程存储
gzip $BACKUP_DIR/snapshot_$DATE.db
rsync -avz $BACKUP_DIR/ user@backup-server:/remote-backup/

# 清理过期备份
find $BACKUP_DIR -type f -mtime +$RETENTION_DAYS -delete

然后加到crontab里:

0 2 * * * /usr/local/bin/etcd-backup.sh

嗯,到这里,K8s集群部署的核心内容就讲完了。从环境准备到高可用设计,从升级策略到备份恢复,每一步都有坑,但只要你按规范来,生产集群稳稳的。下一章咱们聊聊集群的日常运维和监控告警,到时候见。