从零搭建企业级K8s集群

一、概述

1.1 背景介绍

Kubernetes已经成为容器编排的事实标准,但搭建一个生产可用的K8s集群并不简单。

我第一次搭建K8s集群的时候,照着官方文档用kubeadm init,看起来很顺利,结果上线后各种问题:证书过期集群挂了、etcd数据丢了恢复不了、网络插件选错了性能很差、master单点导致业务中断...

后来陆陆续续踩了无数坑,才算搞明白企业级K8s集群应该怎么搭。这篇文章就是把这些经验整理出来,让你少走弯路。

1.2 技术特点

企业级K8s集群的要求

  • 高可用:Master节点多副本,任何单点故障不影响集群

  • 可扩展:能方便地添加Node节点

  • 安全:RBAC权限控制、网络隔离、镜像安全扫描

  • 可观测:完善的监控、日志、告警

  • 灾备:etcd备份恢复、多集群容灾

架构设计

复制代码
                        ┌─────────────────┐
                        │   LoadBalancer  │
                        │  (VIP: 10.0.0.100)│
                        └────────┬────────┘
                                 │
         ┌───────────────────────┼───────────────────────┐
         │                       │                       │
    ┌────▼────┐            ┌────▼────┐            ┌────▼────┐
    │ Master-1 │            │ Master-2 │            │ Master-3 │
    │ API+ETCD │            │ API+ETCD │            │ API+ETCD │
    └─────────┘            └─────────┘            └─────────┘

    ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
    │ Node-1  │  │ Node-2  │  │ Node-3  │  │ Node-N  │
    │ Kubelet │  │ Kubelet │  │ Kubelet │  │ Kubelet │
    │ CNI     │  │ CNI     │  │ CNI     │  │ CNI     │
    └─────────┘  └─────────┘  └─────────┘  └─────────┘

1.3 适用场景

  • 场景一:从零搭建生产环境K8s集群

  • 场景二:将测试集群升级为生产级别

  • 场景三:学习K8s集群架构原理

1.4 环境要求

组件 版本要求 说明
操作系统 CentOS 7.9 / Ubuntu 20.04+ 推荐Ubuntu
Kubernetes 1.28+ 本文使用1.28
Container Runtime containerd 1.7+ 不再使用Docker
网络插件 Calico 3.26+ 推荐Calico
服务器配置 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 负载均衡

二、详细步骤

2.1 准备工作

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

◆ 2.1.1 系统配置
复制代码
# 设置主机名(每台机器执行对应的)
hostnamectl set-hostname k8s-master-1

# 配置hosts
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

# 关闭防火墙(生产环境建议配置规则而非关闭)
systemctl stop firewalld
systemctl disable firewalld

# 关闭SELinux
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config

# 关闭swap(K8s要求)
swapoff -a
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

# 确认关闭
free -h  # Swap应该显示0
◆ 2.1.2 内核参数
复制代码
# 加载必要模块
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
◆ 2.1.3 安装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
◆ 2.1.4 安装kubeadm、kubelet、kubectl
复制代码
# 添加阿里云K8s仓库
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

# 安装指定版本
yum install -y kubelet-1.28.0 kubeadm-1.28.0 kubectl-1.28.0

# 设置开机启动(先不启动)
systemctl enable kubelet

2.2 高可用负载均衡

在初始化集群之前,需要先配置API Server的高可用。

◆ 2.2.1 方案选择
方案 优点 缺点
HAProxy + Keepalived 成熟稳定,自建可控 需要额外维护
云厂商SLB 省心,高可用 依赖云厂商
kube-vip K8s原生,轻量 相对较新

这里用HAProxy + Keepalived方案,在Master-1和Master-2上部署:

复制代码
# 安装
yum install -y haproxy keepalived
◆ 2.2.2 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
◆ 2.2.3 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
#!/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 初始化集群

◆ 2.3.1 准备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
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
◆ 2.3.2 初始化第一个Master
复制代码
# 预拉取镜像
kubeadm config images pull --config kubeadm-config.yaml

# 初始化
kubeadm init --config=kubeadm-config.yaml --upload-certs

# 记住输出的join命令!类似:
# 加入Master:
# kubeadm join 10.0.0.100:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx --control-plane --certificate-key xxx
# 加入Node:
# kubeadm join 10.0.0.100:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx

# 配置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
◆ 2.3.3 加入其他Master节点

在Master-2和Master-3上执行:

复制代码
kubeadm join 10.0.0.100:6443 \
  --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash> \
  --control-plane \
  --certificate-key <certificate-key>

配置kubectl:

复制代码
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
◆ 2.3.4 加入Worker节点

在所有Node上执行:

复制代码
kubeadm join 10.0.0.100:6443 \
  --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>

2.4 安装网络插件

集群初始化后节点是NotReady状态,需要安装CNI网络插件:

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

# 如果使用其他Pod CIDR,需要修改
kubectl setenv 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  # 可能显示Unhealthy,这是已知问题,不影响使用

# 查看系统Pod
kubectl get pods -n kube-system

# 创建测试Pod
kubectl run nginx --image=nginx:alpine
kubectl get pods

# 测试服务
kubectl expose pod nginx --port=80 --type=NodePort
kubectl get svc
# 访问 http://<NodeIP>:<NodePort>

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

三、示例代码和配置

3.1 证书过期处理(坑1)

K8s证书默认1年过期,过期后集群不可用。

查看证书有效期

复制代码
kubeadm certs check-expiration

更新证书

复制代码
# 备份旧证书
cp -r /etc/kubernetes/pki /etc/kubernetes/pki.bak

# 更新所有证书
kubeadm certs renew all

# 重启控制平面组件
crictl pods --namespace kube-system | grep -E 'kube-apiserver|kube-controller|kube-scheduler|etcd' | awk '{print $1}' | xargs crictl rmp -f

# 更新kubeconfig
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存储了所有集群数据,必须定期备份。

备份脚本

复制代码
#!/bin/bash
# /opt/scripts/etcd_backup.sh

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
mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/

# 2. 在所有Master执行恢复
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. 替换数据目录
mv /var/lib/etcd /var/lib/etcd.bak
mv /var/lib/etcd-restore /var/lib/etcd

# 4. 恢复kube-apiserver
mv /tmp/kube-apiserver.yaml /etc/kubernetes/manifests/

3.3 常见问题排查脚本

复制代码
#!/bin/bash
# k8s_health_check.sh

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 我踩过的10个大坑

问题描述 解决方案
1 证书1年过期,集群挂了 设置自动更新cron任务
2 etcd数据丢失,集群完蛋 每天备份etcd
3 Master单点故障 3节点高可用
4 flannel性能差 改用Calico
5 网络插件装错,Pod无法通信 确认podSubnet匹配
6 containerd没配SystemdCgroup 节点NotReady
7 swap没关 kubelet起不来
8 国内拉不到镜像 改用阿里云镜像源
9 证书SAN没加全 初始化时配置certSANs
10 升级版本跨度太大 逐版本升级

四、最佳实践和注意事项

4.1 最佳实践

◆ 4.1.1 节点规划
集群规模 Master节点 Worker节点 etcd
小型(<50 Pod) 3 3+ 内置
中型(50-500 Pod) 3 10+ 内置
大型(>500 Pod) 3 50+ 外置3-5节点
◆ 4.1.2 资源配置建议

Master节点

复制代码
小型集群:4C8G
中型集群:8C16G
大型集群:16C32G

Worker节点

复制代码
通用型:8C16G
计算密集:16C32G
内存密集:8C64G
◆ 4.1.3 安全加固
复制代码
# 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安全标准
kubectl label namespace default pod-security.kubernetes.io/enforce=restricted

4.2 注意事项

◆ 4.2.1 版本升级
复制代码
# 查看可用版本
yum list --showduplicates kubeadm

# 升级步骤(先Master后Node)
# 1. 升级kubeadm
yum install -y kubeadm-1.29.0

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

# 3. 执行升级(第一个Master)
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
◆ 4.2.2 常见错误
错误 原因 解决
NodeNotReady CNI未安装或kubelet问题 检查kubelet日志
ImagePullBackOff 镜像拉取失败 检查镜像地址和网络
CrashLoopBackOff 容器启动失败 查看Pod日志
Pending 资源不足或调度问题 describe pod查看Events

五、故障排查和监控

5.1 常用排查命令

复制代码
# 查看节点详情
kubectl describe node <node-name>

# 查看Pod详情
kubectl describe pod <pod-name>

# 查看Pod日志
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

5.2 安装监控

复制代码
# 安装metrics-server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.4/components.yaml

# 修改配置(如果证书有问题)
kubectl edit deployment metrics-server -n kube-system
# 添加 --kubelet-insecure-tls

# 验证
kubectl top nodes
kubectl top pods

六、总结

6.1 技术要点回顾

  • 高可用是基础:3 Master + VIP负载均衡

  • etcd备份是保险:每天备份,定期验证

  • 证书管理要重视:设置自动更新

  • 网络插件要选对:生产推荐Calico

  • 升级要谨慎:逐版本升级,先测试后生产

6.2 进阶学习方向

    1. GitOps:ArgoCD/Flux持续部署
    1. 服务网格:Istio流量管理
    1. 多集群:Federation/Liqo
    1. Operator开发:自定义资源管理

6.3 参考资料

  • • Kubernetes官方文档

  • • kubeadm文档

  • • Calico文档

附录

A. 命令速查表

复制代码
# 集群管理
kubeadm init                    # 初始化集群
kubeadm join# 加入集群
kubeadm reset                   # 重置节点
kubeadm token create --print-join-command  # 生成join命令

# kubectl常用
kubectl get nodes               # 查看节点
kubectl get pods -A             # 查看所有Pod
kubectl describe pod <name>     # Pod详情
kubectl logs <pod>              # 查看日志
kubectl exec -it <pod> -- sh    # 进入容器

# 故障排查
kubectl get events              # 查看事件
journalctl -u kubelet           # kubelet日志
crictl ps                       # 查看容器
crictl logs <container-id>      # 容器日志

B. 端口列表

组件 端口 说明
kube-apiserver 6443 API Server
etcd 2379/2380 etcd client/peer
kubelet 10250 Kubelet API
kube-scheduler 10259 Scheduler
kube-controller 10257 Controller Manager

C. 术语表

术语 说明
Master 控制平面节点
Node/Worker 工作节点
etcd 分布式键值存储
CNI 容器网络接口
Pod 最小调度单元
Service 服务抽象
Deployment 无状态应用管理
相关推荐
NewBee_Lxx2 小时前
docker nginx
运维·docker·容器
你想考研啊2 小时前
kubectl获取pod报拉取错误
云原生·eureka
阿里云云原生2 小时前
告别“看不见的内存”!SysOM 如何实现 Java 进程内存全景分析?
java·云原生
阿里云云原生3 小时前
Entity 查询:可观测性系统中的“实体搜索引擎”,实战指南!
云原生
龙亘川4 小时前
【课程2.4】开发环境搭建:K8s集群部署、芋道框架集成、ThingsBoard对接
java·容器·kubernetes·智慧城市·智慧城市一网统管 ai 平台
Empty_7775 小时前
K8S-Ingress资源对象
云原生·容器·kubernetes
忍冬行者5 小时前
kubeadm安装的三个masterd的k8s的etcd数据库故障,如何通过备份数据进行恢复
数据库·kubernetes·etcd
猴哥聊项目管理5 小时前
2025年项目管理软件10款云原生部署方案的稳定性对比
安全·云原生·金融·软件工程·项目管理工具·项目管理软件·企业管理
robin59115 小时前
容器-汇总所有环境下的日志排查问题
linux·容器·kubernetes