从零构建高可用K8s集群:生产级架构设计与全链路实践

发布时间:2026/5/16 8:04:12

从零构建高可用K8s集群:生产级架构设计与全链路实践 1. 项目概述从零构建一个生产就绪的K8s集群最近在社区里看到不少朋友对“samip5/k8s-cluster”这个项目标题感兴趣这其实指向了一个非常经典且硬核的实践手动搭建一个高可用的Kubernetes集群。这不仅仅是跑几条kubeadm init命令那么简单它涉及从底层基础设施规划、网络选型、安全加固到生产级运维配置的全链路。我花了将近一周时间从零开始基于主流的云服务器环境完整复现并优化了这样一个集群的构建过程。如果你正打算将业务迁移到K8s或者想深入理解K8s的每一个组件是如何协同工作的那么跟着这篇笔记走一遍绝对比看十篇理论文章更有收获。整个过程会涵盖集群初始化、网络插件CNI选型与部署、Ingress控制器配置、存储方案集成以及最重要的——如何让你的集群具备生产环境所需的健壮性和可观测性。无论是运维工程师、后端开发者还是架构师都能从中找到自己需要的实操细节和避坑指南。2. 集群架构设计与核心组件选型2.1 节点规划与高可用方案在动手之前清晰的架构设计是成功的基石。对于生产环境至少需要三个控制平面节点以实现高可用以及两个以上的工作节点。我选择了3台配置为2核4G的机器作为控制平面2台4核8G的机器作为工作节点。这里有个关键点控制平面节点也可以同时作为工作节点运行Pod但对于资源敏感或要求严格隔离的环境建议将taint应用到控制平面节点上禁止常规工作负载调度。高可用方案上我采用了堆叠式Stacked控制平面。这意味着每个控制平面节点都运行一个kube-apiserver、kube-scheduler、kube-controller-manager的实例同时它们也作为etcd集群的成员。另一种方案是使用外部etcd集群分离了数据存储层复杂度更高但理论上容错性更好。对于大多数中小规模场景堆叠式方案在部署和维护上更简单直接。负载均衡器是另一个核心我使用了一个独立的节点部署HAProxy和Keepalived为三个kube-apiserver实例提供一个虚拟IPVIP。所有节点都将通过这个VIP来访问API Server这样当任何一个控制平面节点宕机时VIP会漂移到健康的节点实现无缝故障转移。注意云厂商的托管负载均衡器如AWS的NLB、阿里云的SLB是更省心的选择但自建方案能让你更透彻地理解流量走向和故障切换机制这也是本项目“硬核”的一部分。2.2 网络与存储方案决策网络是K8s集群的神经系统。CNI容器网络接口插件选择众多我最终选定了Calico。原因有三一是其性能出色支持的网络策略NetworkPolicy功能强大且成熟是实现Pod间微隔离的利器二是它对BGP协议的支持便于与物理网络集成三是社区活跃文档丰富。Flannel更简单但功能相对单一Cilium功能强大但复杂度也高。对于初次构建生产集群Calico在功能与复杂度之间取得了很好的平衡。存储方面需要区分临时存储和持久化存储。临时存储由节点本地磁盘提供。持久化存储则需要对接外部存储系统。我选择了NFS作为起步方案因为它部署简单适合共享存储场景如多个Pod读写同一个WordPress目录。同时我也集成了Rook/Ceph这是一个云原生的分布式存储系统能提供块存储RBD、文件系统CephFS和对象存储S3兼容服务为有状态应用如数据库提供更可靠、高性能的持久卷。在生产中通常需要根据应用类型混合使用多种存储供给器Provisioner。3. 基础环境准备与系统调优3.1 操作系统与内核参数调优所有节点我统一使用Ubuntu 22.04 LTS。第一步是进行系统级优化这对集群的稳定性至关重要。首先关闭Swap因为K8s设计上假设节点有足够的内存使用Swap会导致性能不可预测。sudo swapoff -a # 永久生效注释掉 /etc/fstab 中swap相关的行 sudo sed -i /swap/s/^/#/ /etc/fstab接下来是配置内核参数并加载必要的内核模块。创建文件/etc/sysctl.d/k8s.confcat 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 vm.swappiness 0 EOF sudo sysctl --system加载overlay和br_netfilter模块sudo modprobe overlay sudo modprobe br_netfilter # 确保开机加载 echo -e overlay\nbr_netfilter | sudo tee /etc/modules-load.d/k8s.conf这些设置确保了容器网络特别是CNI插件和存储overlayfs能正常工作并优化了网络转发和防火墙策略。3.2 容器运行时与Kubernetes组件安装我选择了containerd作为容器运行时它比Docker更轻量是K8s社区推荐的选择。安装containerd并配置其使用systemd作为cgroup驱动这与K8s默认保持一致。# 安装containerd sudo apt-get update sudo apt-get install -y containerd # 生成默认配置 sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml # 修改配置使用systemd cgroup驱动 sudo sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl enable containerd接着安装kubeadm、kubelet和kubectl。这里必须注意版本一致性我选择了当前稳定的1.28.x版本。sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/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.28/deb/ / | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubelet1.28.* kubeadm1.28.* kubectl1.28.* sudo apt-mark hold kubelet kubeadm kubectl # 防止意外升级实操心得务必使用apt-mark hold锁定版本。在集群生命周期内所有节点的kubelet、kubeadm版本必须严格一致否则在后续升级或节点加入时会出现难以排查的兼容性问题。4. 高可用集群初始化与节点加入4.1 负载均衡器部署与集群初始化在独立的LB节点上安装并配置HAProxy和Keepalived。/etc/haproxy/haproxy.cfg的关键配置如下它监听6443端口K8s API Server端口并将流量轮询转发到三个控制平面节点的6443端口。frontend k8s-api bind *:6443 mode tcp option tcplog default_backend k8s-control-plane backend k8s-control-plane mode tcp balance roundrobin option tcp-check server k8s-cp-1 192.168.1.101:6443 check fall 3 rise 2 server k8s-cp-2 192.168.1.102:6443 check fall 3 rise 2 server k8s-cp-3 192.168.1.103:6443 check fall 3 rise 2Keepalived则负责管理虚拟IPVIP例如192.168.1.100。配置完成后确保从任何节点都能ping通这个VIP。接下来在第一个控制平面节点k8s-cp-1上使用kubeadm生成初始化配置文件并进行关键定制kubeadm config print init-defaults kubeadm-config.yaml编辑这个文件主要修改localAPIEndpoint.advertiseAddress: 设置为当前节点的IP。controlPlaneEndpoint: 设置为上面配置的VIP地址和端口如192.168.1.100:6443。这是高可用的关键。networking.podSubnet: 设置为Calico默认的192.168.0.0/16需与后续Calico配置匹配。nodeRegistration.criSocket: 设置为unix:///var/run/containerd/containerd.sock。然后执行初始化sudo kubeadm init --configkubeadm-config.yaml --upload-certs这个命令会输出两段至关重要的信息一是让其他控制平面节点加入集群的命令包含--control-plane和--certificate-key二是让工作节点加入集群的命令kubeadm join ...。务必保存好。4.2 其他控制平面与工作节点加入在第一个控制平面初始化成功后按照其输出的命令依次在第二、第三个控制平面节点上执行加入命令。例如sudo kubeadm join 192.168.1.100:6443 --token token \ --discovery-token-ca-cert-hash sha256:hash \ --control-plane --certificate-key certificate-key这个过程会自动从集群下载证书并部署控制平面组件。加入完成后在任意控制平面节点上执行kubectl get nodes应该能看到三个控制平面节点状态均为Ready。工作节点的加入更简单只需执行不带--control-plane和--certificate-key参数的kubeadm join命令即可。所有节点加入后基础集群骨架就搭建完成了。踩坑记录在节点加入时最常见的错误是网络不通或防火墙规则阻止。务必确保所有节点间的以下端口双向畅通6443 (API Server), 2379-2380 (etcd), 10250 (kubelet), 10259 (kube-scheduler), 10257 (kube-controller-manager)。此外Calico默认使用BGP端口179如果节点间有防火墙也需要放行。5. 网络插件Calico与核心插件部署5.1 Calico安装与网络策略验证在所有节点就绪后集群内Pod之间还无法通信需要安装CNI插件。使用Tigera Calico operator方式安装这是目前推荐的方式kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/tigera-operator.yaml kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/custom-resources.yaml安装完成后等待几分钟执行kubectl get pods -n calico-system所有Pod应为Running状态。此时再检查节点状态原来的NotReady应该会变成Ready并且kubectl get pods -A可以看到CoreDNS的Pod也成功运行了。为了验证网络策略功能可以创建一个测试命名空间和两个Nginx Pod并应用一个拒绝所有入站流量的策略。你会发现应用策略后一个Pod将无法ping通或curl到另一个Pod。这证明了Calico的网络策略已经生效为后续实现服务间零信任网络打下了基础。5.2 CoreDNS与Metrics Server配置CoreDNS是集群内部的服务发现核心安装Calico后通常会自动运行。我们需要根据集群规模调整其资源配置。编辑kubectl edit configmap coredns -n kube-system可以调整缓存大小、上游DNS服务器等。对于Pod数量超过500的集群建议适当增加CoreDNS的副本数和内存限制。Metrics Server是集群资源监控数据聚合器是Horizontal Pod Autoscaler (HPA) 和kubectl top命令的基础。部署它kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml部署后通常需要修改其部署参数添加--kubelet-insecure-tls标志以跳过证书验证在测试环境因为自签名证书经常导致连接问题。执行kubectl top nodes和kubectl top pods验证是否正常工作。6. 持久化存储与Ingress控制器集成6.1 基于NFS与Rook/Ceph的存储方案首先部署一个简单的NFS服务器可以在一台独立的节点上然后在K8s中部署NFS Client Provisioner。它能够动态创建PersistentVolumePV。创建StorageClassnfs-client后应用只需声明一个PersistentVolumeClaimPVC指定storageClassName: nfs-client即可自动绑定一个PV。对于更生产化的需求我部署了Rook/Ceph。步骤相对复杂部署Rook Operatorkubectl apply -f ...创建CephCluster自定义资源定义存储节点、磁盘、网络等。创建StorageClass例如rook-ceph-block提供RBD块存储。部署完成后可以创建PVC测试。Rook/Ceph的优势在于它提供了分布式、高可用的存储数据有多副本单个节点或磁盘故障不会导致数据丢失非常适合数据库等有状态应用。6.2 Ingress-Nginx与证书管理Ingress是外部流量进入集群内部服务的统一入口。我选择了社区维护的ingress-nginx控制器。通过Helm安装最为方便helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx \ --create-namespace \ --set controller.service.typeLoadBalancer # 如果云厂商支持或使用NodePort安装后需要将域名如app.yourdomain.com的DNS A记录指向Ingress控制器的公网IPLoadBalancer类型或节点IPNodePort类型配合外部负载均衡器。为了让服务支持HTTPS需要配置TLS证书。我使用Cert-Manager来自动化申请和续期Let‘s Encrypt免费证书。部署Cert-Manager后创建一个ClusterIssuer指向Let‘s Encrypt生产或测试环境。之后在Ingress资源中只需添加注解cert-manager.io/cluster-issuer: letsencrypt-prod并指定tls字段Cert-Manager就会自动创建证书Secret并注入Ingress。证书快过期时也会自动续期实现了全自动的HTTPS化管理。7. 生产级运维监控、日志与安全加固7.1 可观测性栈部署Prometheus Grafana Loki监控是生产环境的眼睛。我使用kube-prometheus-stack原名Prometheus Operator一键部署监控体系。它包含了Prometheus、Alertmanager和一套针对K8s优化的Grafana仪表盘。helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack -n monitoring --create-namespace部署后通过端口转发或Ingress暴露Grafana服务即可看到丰富的集群CPU、内存、网络、存储监控仪表盘并能对节点、Pod、服务的各项指标设置告警规则。对于日志我选择了Loki Promtail组合。Loki负责索引和存储日志Promtail作为DaemonSet运行在每个节点上采集容器日志。相比EFKElasticsearch, Fluentd, Kibana栈Loki更轻量查询语法与Prometheus的PromQL类似学习成本低。部署同样可以使用Helm完成。这样我们就建立了从指标到日志的完整可观测性链条。7.2 集群安全加固实践安全是一个持续的过程。以下是一些基础的加固措施Pod安全标准Pod Security Standards在命名空间级别实施Restricted策略禁止特权容器、限制能力Capabilities、强制只读根文件系统等。网络策略NetworkPolicy使用Calico的NetworkPolicy实现“默认拒绝所有”然后按需开放必要的Pod间通信遵循最小权限原则。RBAC权限控制避免使用cluster-admin等过高权限的ServiceAccount。为每个应用或团队创建特定的ServiceAccount和Role/RoleBinding授予其完成工作所需的最小权限。Etcd加密在kube-apiserver启动参数中配置--encryption-provider-config对存储在etcd中的Secret资源进行静态加密。定期升级关注K8s社区的安全公告制定并执行定期的集群升级计划修复已知漏洞。8. 日常操作、故障排查与经验总结8.1 常用运维命令与问题诊断集群运行后以下命令组合是日常运维和故障排查的利器查看资源状态kubectl get nodes, pods, svc, pvc -A -o wide描述资源详情kubectl describe pod pod-name -n namespace查看事件Events是定位启动失败的关键。查看Pod日志kubectl logs -f pod-name -n namespace -c container-name。进入Pod调试kubectl exec -it pod-name -n namespace -- /bin/sh。资源使用排行kubectl top nodeskubectl top pods -A。查看集群事件kubectl get events -A --sort-by.lastTimestamp 按时间排序查看所有警告和错误。当节点状态异常NotReady时按以下顺序排查登录问题节点检查kubelet服务状态systemctl status kubelet。查看kubelet日志journalctl -u kubelet -f。检查容器运行时systemctl status containerdcrictl ps。检查网络ping其他节点IP和API Server VIP检查Calico Pod状态。8.2 核心经验与避坑指南经过这次完整的搭建我总结了几个最深切的体会第一配置即代码版本控制一切。所有kubeadm的配置文件、Helm的values.yaml、自定义资源如Calico和Rook的配置都必须纳入Git版本库。这保证了环境可重现也是团队协作和审计的基础。第二理解比操作更重要。不要满足于命令能跑通。多去理解kubeadm init背后生成了哪些证书、kube-proxy的iptables/ipvs模式区别、Calico的BGP工作模式、PVC/PV/StorageClass的绑定流程。这些理解在出问题时能帮你快速定位方向。第三从小规模测试开始渐进式完善。不要试图一次性把所有生产级配置如高级网络策略、复杂的HPA、精细的Resource Quota都加上。先让集群跑起来部署一两个简单应用然后逐步引入监控、日志、Ingress、存储每加一层都充分测试。这样问题容易被隔离和解决。第四备份etcd备份etcd备份etcd这是集群状态的唯一真相来源。定期使用etcdctl备份快照并测试恢复流程。同时考虑使用Velero等工具对集群资源和持久卷进行应用级备份。最后这个自建的“samip5/k8s-cluster”项目是一个绝佳的学习平台但它也意味着你需要承担全部运维责任。对于核心生产业务评估人力成本后或许托管K8s服务如EKS, GKE, AKS是更经济高效的选择。但无论如何亲手搭建一遍的经历会让你在面对任何K8s环境时都更有底气。

相关新闻