从零构建高可用Kubernetes容器云平台:架构设计、部署实战与运维优化
2026/8/27 16:34:29 网站建设 项目流程

1. 项目概述:从零到一构建企业级容器云平台

去年带队参加了那场备受关注的云计算国赛,其中容器云平台搭建这个赛项,可以说是对综合工程能力的一次大考。它远不止是敲几条docker run或者kubectl apply命令那么简单,而是要求你在有限时间内,从裸机服务器开始,规划、部署、配置、优化一整套高可用的生产级容器编排环境。这背后考验的是对容器技术栈的深度理解、对网络与存储的架构设计能力,以及面对突发问题的快速排障功底。今天,我就把当时备赛和实战中的完整思路、关键步骤,以及那些在官方文档里不会写的“坑”和技巧,系统地梳理一遍。无论你是正在备赛的学生,还是希望在企业内部搭建类似平台的运维工程师,这篇从实战中淬炼出来的指南,都能给你提供一条清晰的路径和大量可复现的细节。

这个项目的核心目标,是构建一个符合生产环境基本要求的Kubernetes集群。它需要具备:控制平面的高可用,避免单点故障;安全的网络通信,包括Pod间网络、服务发现和外部访问;持久化存储支持,让有状态应用能稳定运行;完整的监控与日志,以便洞察集群状态。我们会使用最主流的组件栈:Kubernetes作为编排引擎,Calico或Flannel提供网络,Helm简化应用部署,并整合Prometheus、Grafana和ELK(或EFK)作为可观测性支柱。整个流程我会拆解为环境准备、集群部署、网络与存储配置、应用部署与运维、高可用与优化五个核心阶段,每个阶段都会深入原理并附上可操作的命令和配置。

2. 核心架构设计与组件选型解析

2.1 整体拓扑与节点规划

在开始敲命令之前,合理的架构设计是成功的基石。对于比赛或中小型生产环境,我推荐采用多主多节点的高可用架构。这意味着你需要至少三台服务器作为控制平面(Master)节点,两台或以上作为工作(Worker)节点。如果资源受限,三台服务器也可以每台同时扮演Master和Worker的角色(即“All-in-One”高可用模式),但这会对服务器资源要求更高。

节点角色与最小配置建议:

  • 控制平面节点 (Master):至少3台。主要运行API Server、Scheduler、Controller Manager、etcd等核心组件。建议配置:4核CPU,8GB内存,50GB磁盘。etcd对磁盘I/O延迟非常敏感,务必使用SSD硬盘。
  • 工作节点 (Worker):至少2台。运行业务容器。建议配置:根据业务负载而定,比赛环境通常4核8GB起步。磁盘需要预留空间存放容器镜像和日志。
  • 负载均衡器 (可选但强烈推荐):在Master节点前放置一个负载均衡器(如HAProxy + Keepalived),将API Server的流量(默认6443端口)分发到多个Master上。这是实现控制平面高可用的关键。在资源紧张时,可以用一台独立的低配服务器或甚至在一个Master节点上部署。

避坑提示:切勿在生产环境使用单Master架构。一旦该Master宕机,整个集群的管理功能将瘫痪(尽管已运行的Pod可能不受影响)。比赛评分标准中,高可用性通常是重要得分点。

2.2 关键组件选型与考量

1. 容器运行时 (Container Runtime):虽然Docker最为人熟知,但Kubernetes自1.20版本后已逐步弃用Docker作为默认运行时。推荐直接使用containerd。它更轻量、更原生,是CNCF毕业项目,也是当前K8s社区默认推荐。安装Kubernetes时,通过kubeadm可以自动安装配置containerd。

2. 网络插件 (CNI):这是容器云平台的“神经系统”。主流选择有Calico和Flannel。

  • Calico:功能强大,支持复杂的网络策略(NetworkPolicy),可以实现基于Pod的微隔离。性能较好,支持BGP协议与物理网络集成。如果你的场景需要严格的安全策略,Calico是首选。
  • Flannel:配置简单,专注于提供基本的Overlay网络(如VXLAN),满足Pod间互通的基本需求。它更轻量,但网络策略功能需要额外组件(如Cilium)或较新版本才支持。比赛选择建议:国赛环境通常对网络策略有要求,因此选择Calico更为稳妥。它能更好地展示你对网络安全管控的理解。

3. 存储插件 (CSI):Kubernetes本身不提供持久化存储,需要对接外部存储系统。在无云厂商特定存储服务的环境下,通常选择:

  • NFS:最简单快捷,适合实验和比赛。在所有节点上搭建一个NFS Server,然后通过nfs-client-provisioner这个CSI驱动,动态提供PV(持久卷)。缺点是单点故障和性能瓶颈。
  • Ceph/ROOK:提供分布式块、文件、对象存储,真正生产级的选择。但部署复杂,资源消耗大,在时间有限的比赛中需谨慎评估。实操策略:为了快速满足“提供持久化存储能力”的要求,我会详细讲解如何部署一个高可用的NFS服务,并结合nfs-subdir-external-provisionernfs-client-provisioner的进化版)实现动态卷供应。

4. 辅助工具链:

  • Helm:Kubernetes的包管理器。像安装MySQL、Redis、WordPress这些复杂应用,用Helm一行命令就能搞定,极大提升部署效率。必装。
  • Dashboard (可选):Web管理界面。方便直观查看资源,但比赛时可能更看重命令行熟练度。
  • Ingress Controller:管理集群外部HTTP/HTTPS流量的入口,常用Nginx Ingress Controller。这是暴露服务给外部的标准方式。

3. 基础环境准备与系统调优

3.1 系统初始化与通用配置

假设我们有三台服务器,IP为192.168.1.{10,11,12},主机名分别为k8s-master-01, k8s-master-02, k8s-worker-01。

第一步:系统配置(所有节点执行)

  1. 主机名与Hosts解析:
    # 设置主机名(以master-01为例) hostnamectl set-hostname k8s-master-01 # 编辑 /etc/hosts,添加所有节点 192.168.1.10 k8s-master-01 192.168.1.11 k8s-master-02 192.168.1.12 k8s-worker-01
  2. 关闭防火墙与SELinux(比赛环境常见要求,生产环境需细化策略):
    systemctl stop firewalld && systemctl disable firewalld setenforce 0 sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
  3. 关闭Swap:Kubernetes要求禁用Swap以确保调度稳定性。
    swapoff -a sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab # 永久禁用
  4. 加载内核模块与修改内核参数:
    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-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 EOF sysctl --system
    ip_forward=1是核心,它允许Linux主机转发IP数据包,这是容器跨节点通信的基石。

3.2 安装容器运行时与Kubernetes核心组件

第二步:安装Containerd(所有节点)这里采用从官方仓库安装的方式,比用yum install docker再改配置更干净。

# 配置yum源 yum install -y yum-utils 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 # 关键修改:将SystemdCgroup设为true,与kubelet集成更好 sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml # 启动并设置开机自启 systemctl enable --now containerd

第三步:安装kubeadm, kubelet, kubectl(所有节点)

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 EOF # 安装指定版本(比赛通常指定版本,例如1.28.x) yum install -y kubelet-1.28.0 kubeadm-1.28.0 kubectl-1.28.0 --disableexcludes=kubernetes systemctl enable --now kubelet

注意:kubelet服务此时会不断重启是正常的,因为它还在等待kubeadm来初始化集群配置。

4. 高可用Kubernetes集群部署实战

4.1 使用kubeadm初始化首个控制平面

我们选择在k8s-master-01上执行初始化。初始化配置文件是灵魂所在,建议生成后仔细修改。

# 生成默认配置 kubeadm config print init-defaults > kubeadm-config.yaml

编辑kubeadm-config.yaml,关键修改如下:

apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration nodeRegistration: criSocket: "unix:///var/run/containerd/containerd.sock" # 指定containerd imagePullPolicy: IfNotPresent --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.28.0 controlPlaneEndpoint: "192.168.1.100:6443" # 虚拟IP或负载均衡器地址 networking: podSubnet: "10.244.0.0/16" # 与后续Calico的默认网段匹配 serviceSubnet: "10.96.0.0/12" apiServer: certSANs: # 证书扩展域名 - "192.168.1.100" - "192.168.1.10" - "k8s-master-01"

这里controlPlaneEndpoint是关键。我们计划用192.168.1.100这个虚拟IP(VIP)来代表高可用的API Server。这个VIP需要通过Keepalived + HAProxy来实现。

先部署负载均衡层:k8s-master-01k8s-master-02上安装配置HAProxy和Keepalived。以Master-01为例(作为Keepalived MASTER):

  1. 安装HAProxy:
    yum install -y haproxy
    配置/etc/haproxy/haproxy.cfg,关键部分:
    frontend k8s-api bind 192.168.1.100:6443 mode tcp option tcplog default_backend k8s-api-servers backend k8s-api-servers mode tcp balance roundrobin server k8s-master-01 192.168.1.10:6443 check server k8s-master-02 192.168.1.11:6443 check
  2. 安装Keepalived:
    yum install -y keepalived
    配置/etc/keepalived/keepalived.conf
    vrrp_instance VI_1 { state MASTER # 另一台设为BACKUP interface eth0 virtual_router_id 51 priority 100 # BACKUP节点设为90 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.100/24 } }
    启动服务:systemctl enable --now haproxy keepalived。在另一台Master上做类似配置(state为BACKUP,priority更低)。

现在执行初始化:k8s-master-01上,使用我们修改好的配置文件进行初始化:

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

--upload-certs参数会将证书加密上传,方便其他控制平面节点加入。成功后会输出kubeadm join命令,务必保存好。

配置kubectl:

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

4.2 安装Calico网络插件

在初始化主节点后,集群处于NotReady状态,因为网络插件还未安装。

# 下载Calico的Operator安装清单 curl https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/tigera-operator.yaml -O kubectl create -f tigera-operator.yaml # 下载自定义资源清单,并修改CIDR与之前podSubnet一致 curl https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/custom-resources.yaml -O # 编辑custom-resources.yaml,确保spec.calicoNetwork.ipPools.cidr为10.244.0.0/16 kubectl create -f custom-resources.yaml

等待几分钟,执行kubectl get pods -n calico-system,看到所有Pod为Running状态,且kubectl get nodes显示节点状态为Ready,即表示网络插件安装成功。

4.3 加入其他控制平面与工作节点

加入第二个控制平面节点 (k8s-master-02):使用初始化成功后输出的kubeadm join命令,它看起来像这样:

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

加入后,在该节点上也复制admin.conf文件以使用kubectl。

加入工作节点 (k8s-worker-01):使用不带--control-plane--certificate-key参数的join命令:

kubeadm join 192.168.1.100:6443 --token <token> \ --discovery-token-ca-cert-hash sha256:<hash>

至此,一个高可用的Kubernetes集群骨架已经搭建完成。你可以通过kubectl get nodes看到所有节点,并通过kubectl get pods -n kube-system查看核心系统组件。

5. 存储系统搭建与动态供应配置

5.1 构建高可用NFS服务器

为了提供存储服务,我们在集群外部(或用一个独立的节点)搭建一个高可用NFS服务。这里用一个简单的主备模式(DRBD + Pacemaker)举例,比赛时若时间紧可用单点NFS,但需说明其局限性。

假设我们用两台额外服务器nfs-01 (192.168.1.20)nfs-02 (192.168.1.21)

  1. 在两台NFS服务器上安装配置DRBD,同步一块磁盘(例如/dev/sdb1)。
  2. 配置Pacemaker管理NFS服务虚拟IP(如192.168.1.30)和DRBD资源。
  3. 在活跃节点上,将DRBD设备挂载到/data/nfs,并配置/etc/exports
    /data/nfs 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check)
  4. 启动NFS服务。

这样,Kubernetes集群内的所有节点(IP在192.168.1.0/24网段)都能挂载这个NFS共享目录。

5.2 部署NFS Subdir External Provisioner

在Kubernetes集群内,我们需要一个驱动来对接这个NFS服务,实现动态创建PV。

# 添加Helm仓库 helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/ # 安装provisioner helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \ --set nfs.server=192.168.1.30 \ --set nfs.path=/data/nfs \ --set storageClass.defaultClass=true \ --namespace kube-system

安装成功后,执行kubectl get sc,你会看到一个名为nfs-client(或类似)的StorageClass被标记为default。这意味着,当用户创建PVC(持久卷声明)而不指定StorageClass时,会自动使用这个NFS后端来动态创建PV。

测试动态存储:创建一个测试PVCtest-pvc.yaml

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi

应用它:kubectl apply -f test-pvc.yaml。稍等片刻,你会发现一个对应的PV自动创建出来了,并且状态是Bound。同时,在NFS服务器的/data/nfs目录下,会多出一个以namespace-pvc名命名的子目录。这证明动态存储供应工作正常。

6. 应用部署、暴露与可观测性建设

6.1 使用Helm部署典型应用

以部署一个WordPress博客为例,它包含MySQL数据库和WordPress应用本身,完美展示有状态应用和Web应用的部署。

# 添加Bitnami仓库(包含丰富的应用Chart) helm repo add bitnami https://charts.bitnami.com/bitnami # 安装MySQL,并指定使用我们刚创建的存储类 helm install mysql bitnami/mysql \ --set auth.rootPassword=rootpassword \ --set primary.persistence.storageClass=nfs-client \ --set architecture=standalone # 安装WordPress,并关联MySQL服务 helm install wordpress bitnami/wordpress \ --set mariadb.enabled=false \ --set externalDatabase.host=mysql \ --set externalDatabase.user=root \ --set externalDatabase.password=rootpassword \ --set externalDatabase.database=wordpress \ --set persistence.storageClass=nfs-client \ --set service.type=NodePort

安装后,kubectl get svc wordpress可以看到WordPress服务被分配了一个NodePort(如30080)。通过访问任何节点IP的30080端口,就能打开WordPress安装界面。

6.2 配置Ingress实现域名访问

NodePort不适合生产环境。我们部署Nginx Ingress Controller,并通过Ingress规则用域名访问服务。

# 安装Ingress-Nginx(使用官方Helm Chart) helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm install ingress-nginx ingress-nginx/ingress-nginx \ --set controller.service.type=NodePort \ --set controller.service.nodePorts.http=30080 \ --set controller.service.nodePorts.https=30443

创建一个Ingress资源wordpress-ingress.yaml

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: wordpress-ingress spec: ingressClassName: nginx rules: - host: wp.k8s.local http: paths: - path: / pathType: Prefix backend: service: name: wordpress port: number: 80

应用后,由于没有真实DNS,我们需要在客户端(或比赛环境的管理机)的/etc/hosts文件中添加解析:<任意节点IP> wp.k8s.local。之后即可通过http://wp.k8s.local访问WordPress。

6.3 集成监控与日志系统

监控方案(Prometheus + Grafana):

# 添加Prometheus社区仓库 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts # 安装kube-prometheus-stack(包含Prometheus, Grafana, AlertManager等) helm install prometheus prometheus-community/kube-prometheus-stack \ --namespace monitoring \ --create-namespace

安装后,通过kubectl get svc -n monitoring找到Grafana服务的NodePort,访问即可。默认用户/密码是admin/prom-operator。里面已经预置了Kubernetes集群的各项监控仪表盘。

日志方案(EFK:Elasticsearch + Fluentd + Kibana):部署EFK栈相对复杂,比赛时如果时间有限,可以阐述架构:Fluentd以DaemonSet方式运行在每个节点上,收集容器和系统日志,输出到Elasticsearch集群,最后用Kibana展示。可以使用Helm Chartelastic/elasticsearchelastic/kibana来简化部署。

7. 集群运维、问题排查与性能优化

7.1 日常运维命令与状态检查

掌握一些高效的kubectl命令组合能极大提升运维速度:

  • 快速查看集群状态:kubectl get nodes -o wide
  • 查看Pod详情(包括事件):kubectl describe pod <pod-name> -n <namespace>
  • 查看Pod日志:kubectl logs -f <pod-name> -c <container-name>
  • 进入Pod调试:kubectl exec -it <pod-name> -- /bin/sh
  • 查看服务端点:kubectl get ep <service-name>
  • 查看Ingress状态:kubectl get ingress
  • 查看PVC/PV绑定情况:kubectl get pvc,pv
  • 查看集群事件:kubectl get events --sort-by='.lastTimestamp'

7.2 常见问题排查实录

问题1:Pod一直处于Pending状态。

  • 排查思路:kubectl describe pod查看事件。最常见原因是资源不足(CPU/Memory)或没有满足条件的节点(如nodeSelector不匹配)。也可能是PVC无法绑定(StorageClass问题或容量不足)。
  • 解决:检查节点资源kubectl describe node,检查PVC状态kubectl get pvc

问题2:Pod处于ImagePullBackOff或ErrImagePull状态。

  • 排查思路:镜像拉取失败。可能是镜像名称错误、私有仓库无权限或网络不通。
  • 解决:kubectl describe pod查看具体错误信息。若是私有仓库,需要创建imagePullSecrets

问题3:Service无法访问。

  • 排查思路:
    1. 检查Service的Selector是否与Pod的Label匹配:kubectl get svcSELECTORkubectl get pods --show-labels看Pod标签。
    2. 检查Endpoints是否正常:kubectl get ep <service-name>,应该有对应的Pod IP。
    3. 如果是ClusterIP类型,在集群内另一个Pod里用curl <service-name>.<namespace>.svc.cluster.local测试。
    4. 如果是NodePort,检查防火墙是否放行了节点端口。

问题4:NFS存储卷挂载失败。

  • 排查思路:在Pod所在节点上,手动尝试挂载NFS目录:mount -t nfs <nfs-server-ip>:/data/nfs /mnt/test。常见问题是NFS服务器防火墙未开放(2049端口),或/etc/exports配置的网段不正确,或no_root_squash参数未加导致权限问题。

7.3 集群性能与安全优化建议

  1. 资源请求与限制(Requests/Limits):为每个Pod的容器设置合理的CPU/Memory请求和限制。这是保障集群稳定性的第一道防线,避免某个应用耗尽节点资源。
    resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m"
  2. Pod反亲和性(Pod Anti-Affinity):对于多副本的应用(如MySQL主从),使用podAntiAffinity确保副本不会被调度到同一个节点上,提高容灾能力。
  3. 网络策略(NetworkPolicy):使用Calico的NetworkPolicy实现微隔离。例如,只允许前端Pod访问后端数据库的特定端口。
  4. 镜像仓库加速:在国内环境,为containerd配置国内镜像加速器(如阿里云、中科大镜像源),可以极大提升镜像拉取速度。
  5. 日志轮转:配置kubeletcontainerd的日志轮转策略,避免日志占满磁盘空间。在/etc/containerd/config.toml中可配置。

搭建这样一个容器云平台,就像完成一个精密的系统工程。从系统调优到集群初始化,从网络选型到存储集成,每一步都需要清晰的理解和细致的操作。比赛中,除了完成基本功能,那些对高可用设计的考量、对异常问题的快速定位、以及清晰的文档说明,往往是拉开差距的关键。在实际生产环境中,还需要考虑备份(etcd备份)、升级策略、安全审计等更多维度。希望这份基于实战的拆解,能为你提供一个扎实的起点和清晰的路线图。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询