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

667

积分

1

好友

83

主题
发表于 昨天 03:19 | 查看: 5| 回复: 0

Kubernetes已经成为容器编排的事实标准,但搭建一个生产可用的K8s集群并非易事。本文将基于实战经验,从零开始构建一个高可用的企业级K8s集群,并总结在部署过程中最常见的10个“坑”及其解决方案。

一、概述

1.1 背景介绍

初次搭建K8s集群时,很多开发者可能仅通过kubeadm init命令便宣告成功,但真正投入生产环境后,各种问题会接踵而至:证书过期导致集群不可用、etcd数据丢失难以恢复、网络插件选择不当影响性能、Master节点单点故障造成业务中断等。本文将系统梳理这些经验,帮助读者构建一个稳定、可靠的生产级集群。

1.2 技术特点

企业级K8s集群的核心要求

  • 高可用:Master节点采用多副本部署,消除单点故障风险。
  • 可扩展:能够便捷地横向扩展Worker节点。
  • 安全:实施RBAC权限控制、网络策略隔离及镜像安全扫描。
  • 可观测:集成完善的监控、日志收集与告警体系。
  • 灾备:建立定时的etcd备份恢复机制与多集群容灾方案。

架构设计: 采用三节点Master高可用架构,通过负载均衡器(VIP)对外暴露API Server。

┌─────────────────┐
│   LoadBalancer  │
│  (VIP: 10.0.0.100)│
└────────┬────────┘
         │
┌────────▼────────┐ ┌────────▼────────┐ ┌────────▼────────┐
│    Master-1     │ │    Master-2     │ │    Master-3     │
│   (API+ETCD)    │ │   (API+ETCD)    │ │   (API+ETCD)    │
└─────────────────┘ └─────────────────┘ └─────────────────┘
         │                  │                  │
┌────────▼────────┐ ┌────────▼────────┐ ┌────────▼────────┐
│     Node-1      │ │     Node-2      │ │     Node-N      │
│   (Kubelet+CNI) │ │   (Kubelet+CNI) │ │   (Kubelet+CNI) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
1.3 适用场景
  • 从零开始搭建生产环境的K8s集群。
  • 将测试或开发集群升级至生产可用标准。
  • 深入理解K8s高可用集群的架构原理与部署细节。
1.4 环境要求
组件 版本要求 说明
操作系统 CentOS 7.9 / Ubuntu 20.04+ 推荐使用Ubuntu系统
Kubernetes 1.28+ 本文以1.28版本为例
Container Runtime containerd 1.7+ K8s 1.24后不再默认支持Docker
网络插件 Calico 3.26+ 生产环境推荐
服务器配置 4C8G+ Master节点最低配置
服务器规划 角色 主机名 IP 配置
Master-1 k8s-master-1 10.0.0.11 4C8G 100G
Master-2 k8s-master-2 10.0.0.12 4C8G 100G
Master-3 k8s-master-3 10.0.0.13 4C8G 100G
Node-1 k8s-node-1 10.0.0.21 8C16G 200G
Node-2 k8s-node-2 10.0.0.22 8C16G 200G
Node-3 k8s-node-3 10.0.0.23 8C16G 200G
VIP - 10.0.0.100 负载均衡虚拟IP

二、详细部署步骤

2.1 准备工作

以下操作需在所有节点上执行。

系统基础配置

# 设置主机名(每台机器执行对应的命令)
hostnamectl set-hostname k8s-master-1

# 配置主机名解析
cat >> /etc/hosts << 'EOF'
10.0.0.11 k8s-master-1
10.0.0.12 k8s-master-2
10.0.0.13 k8s-master-3
10.0.0.21 k8s-node-1
10.0.0.22 k8s-node-2
10.0.0.23 k8s-node-3
10.0.0.100 k8s-api  # VIP
EOF

# 关闭防火墙与SELinux(生产环境建议配置具体规则)
systemctl stop firewalld && systemctl disable firewalld
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config

# 关闭swap(Kubernetes强制要求)
swapoff -a
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# 验证
free -h  # Swap一行应显示为0

内核参数优化

# 加载内核模块
cat > /etc/modules-load.d/k8s.conf << 'EOF'
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter

# 配置内核参数
cat > /etc/sysctl.d/k8s.conf << 'EOF'
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
# 性能优化参数
net.ipv4.tcp_max_syn_backlog = 65535
net.core.somaxconn = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
fs.file-max = 655360
fs.inotify.max_user_watches = 524288
EOF
sysctl --system

安装容器运行时containerd: 从K8s 1.24开始,不再内置对Docker的支持,推荐使用containerd。

# 安装依赖
yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加Docker仓库(内含containerd)
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装containerd
yum install -y containerd.io
# 生成并修改默认配置
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# 为国内用户修改sandbox镜像地址
sed -i 's|registry.k8s.io/pause:3.8|registry.aliyuncs.com/google_containers/pause:3.9|' /etc/containerd/config.toml
# 启动并设置开机自启
systemctl enable containerd
systemctl start containerd
# 验证安装
ctr version

安装kubeadm、kubelet、kubectl

# 配置阿里云Kubernetes Yum源
cat > /etc/yum.repos.d/kubernetes.repo << 'EOF'
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

# 安装指定版本(此处以1.28.0为例)
yum install -y kubelet-1.28.0 kubeadm-1.28.0 kubectl-1.28.0
systemctl enable kubelet  # 先启用,暂不启动
2.2 配置高可用负载均衡

在初始化集群前,需先建立API Server的高可用访问点。这里采用成熟的HAProxy + Keepalived方案。

安装软件包(在计划部署负载均衡的Master节点上执行,例如Master-1和Master-2):

yum install -y haproxy keepalived

配置HAProxy (/etc/haproxy/haproxy.cfg):

global
    log /dev/log local0
    log /dev/log local1 notice
    daemon

defaults
    mode                    tcp
    log                     global
    option                  tcplog
    option                  dontlognull
    timeout connect         5000
    timeout client          50000
    timeout server          50000

frontend kubernetes-apiserver
    bind *:6443
    mode tcp
    option tcplog
    default_backend kubernetes-apiserver

backend kubernetes-apiserver
    mode tcp
    option tcp-check
    balance roundrobin
    server k8s-master-1 10.0.0.11:6443 check fall 3 rise 2
    server k8s-master-2 10.0.0.12:6443 check fall 3 rise 2
    server k8s-master-3 10.0.0.13:6443 check fall 3 rise 2

listen stats
    bind *:8080
    mode http
    stats enable
    stats uri /stats
    stats auth admin:admin123

配置Keepalived

  • Master-1 (MASTER角色) (/etc/keepalived/keepalived.conf):
    
    global_defs {
    router_id LVS_K8S
    }

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

vrrp_instance VI_1 { state MASTER interface eth0 # 请根据实际情况修改网卡名 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass K8SHA_KA } virtual_ipaddress { 10.0.0.100/24 # VIP } track_script { check_haproxy } }

- **Master-2 (BACKUP角色)**:配置文件与Master-1类似,主要修改`state BACKUP`和`priority 90`。

**健康检查脚本** (`/etc/keepalived/check_haproxy.sh`):
```bash
#!/bin/bash
if ! pidof haproxy > /dev/null; then
    systemctl restart haproxy
    sleep 3
    if ! pidof haproxy > /dev/null; then
        exit 1
    fi
fi
exit 0

赋予脚本执行权限并启动服务:

chmod +x /etc/keepalived/check_haproxy.sh
systemctl enable haproxy keepalived
systemctl start haproxy keepalived
# 验证VIP是否成功绑定
ip addr show | grep 10.0.0.100
2.3 初始化Kubernetes集群

准备kubeadm配置文件 (在Master-1上执行): 创建文件 kubeadm-config.yaml

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.28.0
controlPlaneEndpoint: "10.0.0.100:6443" # 指向VIP
imageRepository: registry.aliyuncs.com/google_containers # 国内镜像源
networking:
  dnsDomain: cluster.local
  serviceSubnet: "10.96.0.0/12"
  podSubnet: "10.244.0.0/16" # 需与后续Calico配置匹配
etcd:
  local:
    dataDir: /var/lib/etcd
apiServer:
  certSANs: # 证书包含所有可能的访问地址
  - "10.0.0.100"
  - "10.0.0.11"
  - "10.0.0.12"
  - "10.0.0.13"
  - "k8s-api"
  - "k8s-master-1"
  - "k8s-master-2"
  - "k8s-master-3"
  extraArgs:
    audit-log-path: /var/log/kubernetes/audit.log
    audit-log-maxage: "30"
    audit-log-maxbackup: "3"
    audit-log-maxsize: "100"
controllerManager:
  extraArgs:
    bind-address: 0.0.0.0
scheduler:
  extraArgs:
    bind-address: 0.0.0.0
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 10.0.0.11 # 当前Master节点的IP
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/control-plane

初始化第一个Master节点

# 预拉取所需镜像
kubeadm config images pull --config kubeadm-config.yaml
# 执行初始化
kubeadm init --config=kubeadm-config.yaml --upload-certs

初始化成功后,会输出用于加入集群的命令,请务必妥善保存。输出内容通常包含两种命令:一种用于加入其他控制平面节点(--control-plane),另一种用于加入工作节点。

配置kubectl访问:

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

加入其他Master节点: 在Master-2和Master-3上,使用初始化输出中提供的--control-plane命令加入集群。加入后,同样需要复制admin.conf配置文件到本地。

加入Worker节点: 在所有Node节点上,使用初始化输出中提供的(不带--control-plane参数的)join命令加入集群。

2.4 安装网络插件

集群初始化后,节点状态为NotReady,因为尚未安装容器网络接口(CNI)插件。生产环境推荐使用Calico。

# 安装Calico
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml

# 如果Pod子网与默认值(192.168.0.0/16)不同,需设置环境变量
# kubectl set env daemonset/calico-node -n kube-system CALICO_IPV4POOL_CIDR="10.244.0.0/16"

# 等待所有系统Pod就绪
kubectl get pods -n kube-system -w
# 验证节点状态
kubectl get nodes # 所有节点应变为Ready状态
2.5 集群功能验证
# 查看集群节点详情
kubectl get nodes -o wide
# 查看核心组件状态
kubectl get cs
# 查看kube-system命名空间下的Pod
kubectl get pods -n kube-system

# 运行一个测试Pod
kubectl run nginx --image=nginx:alpine
kubectl get pods
# 创建NodePort Service暴露测试Pod
kubectl expose pod nginx --port=80 --type=NodePort
kubectl get svc
# 通过 http://<任意Node的IP>:<NodePort> 访问测试页面

# 清理测试资源
kubectl delete pod nginx
kubectl delete svc nginx

三、关键配置与避坑指南

3.1 证书过期处理(坑1)

K8s集群证书默认有效期为1年,过期将导致集群不可用。

查看证书有效期

kubeadm certs check-expiration

手动更新所有证书

# 1. 备份现有证书
cp -r /etc/kubernetes/pki /etc/kubernetes/pki.bak
# 2. 更新证书
kubeadm certs renew all
# 3. 重启控制平面静态Pod(API Server等)
# 获取Pod ID并重启
crictl pods --namespace kube-system | grep -E 'kube-apiserver|kube-controller|kube-scheduler|etcd' | awk '{print $1}' | xargs crictl rmp -f
# 系统会自动重建Pod
# 4. 更新kubectl使用的配置文件
cp /etc/kubernetes/admin.conf $HOME/.kube/config

配置自动更新(推荐): 创建每月执行的定时任务 /etc/cron.monthly/k8s-cert-renew

#!/bin/bash
kubeadm certs renew all
crictl pods --namespace kube-system | grep -E 'kube-apiserver|kube-controller|kube-scheduler' | awk '{print $1}' | xargs crictl rmp -f

记得赋予脚本执行权限。

3.2 etcd备份与恢复(坑2)

etcd存储了集群的所有状态数据,定期备份是保障集群安全的重中之重,属于必须建立的数据库备份实践。

备份脚本示例 (/opt/scripts/etcd_backup.sh):

#!/bin/bash
BACKUP_DIR="/data/etcd-backup"
DATE=$(date +%Y%m%d_%H%M%S)
ETCDCTL_API=3

mkdir -p ${BACKUP_DIR}

etcdctl snapshot save ${BACKUP_DIR}/etcd-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

# 验证备份文件
etcdctl snapshot status ${BACKUP_DIR}/etcd-snapshot-${DATE}.db

# 清理旧备份,保留最近7天
find ${BACKUP_DIR} -name "*.db" -mtime +7 -delete

echo "Backup completed: ${BACKUP_DIR}/etcd-snapshot-${DATE}.db"

配置定时备份(每天凌晨2点):

0 2 * * * /opt/scripts/etcd_backup.sh >> /var/log/etcd-backup.log 2>&1

恢复流程(灾难恢复时):

# 1. 停止所有Master节点的kube-apiserver(通过移动manifest文件)
mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/

# 2. 在其中一个Master节点执行恢复(以Master-1为例)
ETCDCTL_API=3 etcdctl snapshot restore /data/etcd-backup/etcd-snapshot-xxx.db \
  --data-dir=/var/lib/etcd-restore \
  --name=k8s-master-1 \
  --initial-cluster="k8s-master-1=https://10.0.0.11:2380,k8s-master-2=https://10.0.0.12:2380,k8s-master-3=https://10.0.0.13:2380" \
  --initial-advertise-peer-urls=https://10.0.0.11:2380

# 3. 替换etcd数据目录
mv /var/lib/etcd /var/lib/etcd.bak
mv /var/lib/etcd-restore /var/lib/etcd
# 在其他Master节点上重复此步骤

# 4. 恢复kube-apiserver
mv /tmp/kube-apiserver.yaml /etc/kubernetes/manifests/
3.3 集群健康检查脚本

创建一个综合检查脚本 (k8s_health_check.sh) 便于日常运维:

#!/bin/bash
echo "========================================"
echo "K8s集群健康检查 $(date)"
echo "========================================"
echo ""
echo "=== 节点状态 ==="
kubectl get nodes -o wide
echo ""
echo "=== 系统Pod状态 ==="
kubectl get pods -n kube-system -o wide | grep -v Running
echo ""
echo "=== 异常Pod ==="
kubectl get pods -A | grep -v Running | grep -v Completed
echo ""
echo "=== etcd健康状态 ==="
kubectl exec -n kube-system etcd-k8s-master-1 -- 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 \
  endpoint health
echo ""
echo "=== 证书有效期 ==="
kubeadm certs check-expiration 2>/dev/null
echo ""
echo "=== 资源使用 ==="
kubectl top nodes 2>/dev/null || echo "需要安装metrics-server"
echo "========================================"
3.4 十大常见“坑”与解决方案总结
问题描述 解决方案
1 证书1年过期,集群突然不可用 设置cron任务自动更新证书
2 etcd数据丢失,集群彻底崩溃 严格执行每日定时备份etcd
3 Master单点故障导致业务中断 部署至少3节点的Master高可用集群
4 默认网络插件flannel性能不佳 生产环境改用Calico或Cilium
5 网络插件Pod子网配置不匹配 确保kubeadm配置与CNI配置的podSubnet一致
6 containerd未配置SystemdCgroup 修改containerd配置,设置SystemdCgroup = true
7 未关闭swap,kubelet无法启动 在所有节点上永久关闭swap分区
8 国内环境无法拉取k8s.gcr.io镜像 使用阿里云、华为云等国内镜像仓库源
9 证书SAN列表不全,外部访问失败 初始化时在certSANs中列出所有IP和域名
10 跨大版本升级导致兼容性问题 遵循官方建议,逐次小版本升级,先测试后生产

四、生产环境最佳实践

4.1 节点规划建议
集群规模 Master节点 Worker节点 etcd部署模式
小型 (< 50 Pod) 3 3+ 内置(本文方案)
中型 (50 - 500 Pod) 3 10+ 内置
大型 (> 500 Pod) 3 50+ 考虑外置独立集群(3-5节点)

资源配置参考

  • Master节点:小型集群4C8G,中型8C16G,大型16C32G。
  • Worker节点:通用型8C16G,计算密集型16C32G,内存密集型8C64G。
4.2 安全加固
# 1. 应用最小权限RBAC原则
kubectl create clusterrolebinding ops-admin \
  --clusterrole=admin \
  --user=ops@example.com

# 2. 实施默认拒绝的网络策略
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
EOF

# 3. 启用Pod安全标准(Restricted模式)
kubectl label namespace default pod-security.kubernetes.io/enforce=restricted
4.3 版本升级注意事项

升级前务必备份etcd并查看官方发布说明

# 查看可升级版本
yum list --showduplicates kubeadm

# 标准升级流程(先Master后Node)
# 1. 升级首个Master节点的kubeadm
yum install -y kubeadm-1.29.0
# 2. 查看升级计划
kubeadm upgrade plan
# 3. 执行升级
kubeadm upgrade apply v1.29.0
# 4. 升级其他Master节点
kubeadm upgrade node
# 5. 升级所有节点的kubelet和kubectl
yum install -y kubelet-1.29.0 kubectl-1.29.0
systemctl daemon-reload
systemctl restart kubelet

五、故障排查与监控

常用排查命令

# 查看资源详情
kubectl describe node <node-name>
kubectl describe pod <pod-name>
# 查看日志
kubectl logs <pod-name> [-c <container-name>]
# 进入容器
kubectl exec -it <pod-name> -- /bin/sh
# 查看集群事件
kubectl get events --sort-by='.lastTimestamp'
# 查看kubelet日志
journalctl -u kubelet -f

安装基础监控metrics-server

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.4/components.yaml
# 如果节点证书不被认可,可编辑部署添加`--kubelet-insecure-tls`参数
# kubectl edit deployment metrics-server -n kube-system
# 验证
kubectl top nodes
kubectl top pods

六、总结

构建一个稳定的企业级Kubernetes集群,高可用是基石(3 Master + 负载均衡),etcd备份是生命线证书管理不可忽视。网络插件选择(如Calico)、逐版本谨慎升级也是保障生产环境稳定的关键。

完成基础集群搭建后,可以进一步探索云原生生态,例如采用GitOps工作流(如ArgoCD)实现持续部署,或集成服务网格(如Istio)进行细粒度的流量管理。

运维端口参考 组件 端口 说明
kube-apiserver 6443 API Server
etcd 2379/2380 客户端/对等通信
kubelet 10250 Kubelet API
kube-scheduler 10259 Scheduler
kube-controller-manager 10257 Controller Manager

常用命令速查


# 集群管理
kubeadm init
kubeadm join
kubeadm reset
kubeadm token create --print-join-command

# 资源操作
kubectl get nodes/pods/svc
kubectl describe <resource> <name>
kubectl logs <pod>
kubectl exec -it <pod> -- sh

# 运维调试
kubectl get events
journalctl -u kubelet
crictl ps
crictl logs <container-id>



上一篇:逻辑漏洞实战:利用多端接口差异实现越权访问(斩获3k)
下一篇:全志T153工业核心板选型指南:4核CPU与多通信接口实战解析
您需要登录后才可以回帖 登录 | 立即注册

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

GMT+8, 2025-12-10 20:59 , Processed in 0.085139 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

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