企业级K8S生产环境搭建实录:3管理节点+3计算节点+Harbor高可用架构详解

最近和几位技术负责人聊天,大家普遍反映一个痛点:从技术博客里学来的Kubernetes部署方案,在个人实验环境跑得挺欢,一旦要搬到公司内部的生产环境,各种问题就冒出来了。节点挂了怎么办?镜像拉取慢得像蜗牛,CI/CD流水线动不动就卡住。更头疼的是,那些教程往往只讲“单管理节点”的简易部署,对于要求服务不中断、数据不丢失的真实业务场景,参考价值有限。这让我意识到,一份聚焦于中小企业真实生产需求、涵盖多节点高可用安全镜像仓库以及可落地配置细节的指南,确实有其价值。它不是另一个“一键安装”脚本的堆砌,而是试图还原你在机房或云上,面对多台服务器时,需要思考的架构选择、参数调优和故障预案。无论你是计划将内部应用容器化,还是为团队搭建一个稳定的开发和测试平台,希望接下来的内容能提供一条清晰、可复现的路径。

1. 架构设计与核心组件选型

在动手敲命令之前,花些时间厘清架构是避免后期返工的关键。我们构建的是一个典型的中小企业生产级Kubernetes集群,核心目标是在有限的资源下(例如6台物理机或虚拟机),实现控制平面的高可用和数据平面的弹性扩展。

核心架构拓扑可以这样理解:我们将三台服务器作为管理节点(Master Node),它们共同组成集群的“大脑”,运行着API Server、Scheduler、Controller Manager等关键组件。为确保这个大脑不会因单点故障而宕机,这些组件本身将以多副本形式运行,并通过一个负载均衡器(HAProxy) 对外提供统一的访问入口。另外三台服务器作为计算节点(Worker Node),承载实际的应用容器负载。所有节点都需要从统一的镜像仓库拉取容器镜像,这里我们选择功能丰富且支持高可用的Harbor。

注意:将Harbor部署在独立的第七台服务器上是推荐做法。这避免了资源竞争,也便于单独进行安全加固、备份和升级,符合生产环境职责分离的原则。

在这个架构中,有几个容易被新手忽略但至关重要的企业级考量点:

  • etcd集群:Kubernetes的所有集群状态数据都存储在etcd中。我们将其部署在三台管理节点上,形成一个3节点的分布式键值数据库集群。这要求我们仔细配置etcd的通信参数,确保其数据一致性和高可用性。
  • 负载均衡器(HAProxy):它并非Kubernetes的内部组件,而是一个前置的、独立的服务。它的作用是,将客户端(如kubectl、CI/CD系统)对Kubernetes API的请求,均匀、可靠地分发到后端的三个管理节点的API Server上。即使其中一个管理节点故障,API服务依然可用。
  • 容器运行时与镜像加速:我们选用Docker作为容器运行时。在生产环境中,从公共仓库拉取镜像的速度和稳定性是瓶颈,因此必须配置可靠的镜像加速器或内部代理。

为了更清晰地展示集群中各组件的部署位置与交互关系,可以参考下表:

组件/角色部署节点数量关键职责高可用实现方式
HAProxy可部署于任一节点或独立LB1 (可多实例)为K8s API Server提供负载均衡结合Keepalived实现VIP漂移
K8s API Server所有管理节点3集群API入口,处理所有REST请求通过HAProxy实现流量分发
K8s Scheduler所有管理节点3为Pod选择运行的Node多副本,领导者选举
K8s Controller Manager所有管理节点3维护集群状态(如副本数)多副本,领导者选举
etcd所有管理节点3存储集群所有配置与状态数据组成3节点Raft集群
Kubelet & Container Runtime所有计算节点3管理Pod生命周期,运行容器节点级,无状态,可替换
Harbor (Core)独立服务器1 (可集群)企业级私有镜像仓库通过外部数据库和存储实现无状态扩展

这个架构平衡了复杂度与可靠性。三节点etcd集群可以容忍一个节点故障;三管理节点确保控制平面服务持续可用;计算节点则可以视业务压力随时增减。

2. 基础环境与Kubernetes高可用集群部署

假设你已经准备好了7台安装Ubuntu 22.04 LTS的服务器(或虚拟机),并配置了静态IP和互信SSH。我们从所有节点的通用配置开始。

2.1 系统级统一配置

首先,在所有7台服务器上执行以下操作,为Kubernetes运行准备一个干净、稳定的基础环境。

关闭并禁用SWAP。Kubernetes调度器需要依赖足够的内存资源来做出决策,SWAP的引入会导致性能不稳定和不可预测性。

# 临时关闭当前所有SWAP空间
swapoff -a
# 永久禁用,编辑fstab文件,注释掉包含swap的行
sed -i '/swap/s/^/#/' /etc/fstab

加载内核模块并修改系统参数。容器网络和存储等功能需要特定的内核模块支持。

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

# 设置网络桥接的IP转发及流量处理参数
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

安装基础工具。确保curlvimsocatconntrack等工具可用。

apt-get update && apt-get install -y curl vim socat conntrack ipset

2.2 使用KubeKey构建高可用集群

手动部署一个高可用集群涉及大量繁琐的配置。这里我们选用KubeSphere社区开源的KubeKey工具,它能极大地简化流程,特别是对于etcd和负载均衡器的集成部署。

  1. 下载并准备KubeKey。在一台作为“部署机”的管理节点(例如guanlijiedian1)上操作。

    # 设置下载区域为中国,加速获取
    export KKZONE=cn
    # 下载最新版KubeKey
    curl -sfL https://get-kk.kubesphere.io | sh -
    # 赋予执行权限
    chmod +x kk
    
  2. 生成集群配置文件。这里我们指定使用较稳定的Kubernetes v1.26.x版本。

    ./kk create config --with-kubernetes v1.26.15 --with-kubesphere v3.4.1
    

    这个命令会生成一个名为config-sample.yaml的模板文件。接下来是最关键的一步:根据我们的架构定制这个文件。

  3. 深度定制config-sample.yaml。用编辑器打开该文件,你需要重点关注以下几个部分:

    • hosts:列出所有6台K8s节点(3管理+3计算)的详细信息。
    hosts:
    - {name: guanlijiedian1, address: 192.168.1.101, internalAddress: 192.168.1.101, user: root, password: "YourSecurePassword"}
    - {name: guanlijiedian2, address: 192.168.1.102, internalAddress: 192.168.1.102, user: root, password: "YourSecurePassword"}
    - {name: guanlijiedian3, address: 192.168.1.103, internalAddress: 192.168.1.103, user: root, password: "YourSecurePassword"}
    - {name: jisuanjiedian1, address: 192.168.1.111, internalAddress: 192.168.1.111, user: root, password: "YourSecurePassword"}
    - {name: jisuanjiedian2, address: 192.168.1.112, internalAddress: 192.168.1.112, user: root, password: "YourSecurePassword"}
    - {name: jisuanjiedian3, address: 192.168.1.113, internalAddress: 192.168.1.113, user: root, password: "YourSecurePassword"}
    
    • roleGroups:明确定义各节点的角色。
      • etcd: 包含三台管理节点,组成etcd集群。
      • control-plane: 同样包含三台管理节点,运行控制平面组件。
      • worker: 包含三台计算节点。
    roleGroups:
      etcd:
      - guanlijiedian1
      - guanlijiedian2
      - guanlijiedian3
      control-plane:
      - guanlijiedian1
      - guanlijiedian2
      - guanlijiedian3
      worker:
      - jisuanjiedian1
      - jisuanjiedian2
      - jisuanjiedian3
    
    • controlPlaneEndpoint:这是高可用的核心配置。你需要提供一个负载均衡器(HAProxy)的访问地址和端口。假设我们在192.168.1.100上部署了HAProxy,监听6443端口。
    controlPlaneEndpoint:
      domain: lb.k8s.local # 内部域名,可选
      address: "192.168.1.100" # HAProxy的VIP或主机IP
      port: 6443
    
    • etcd:配置etcd集群参数。生产环境建议配置SSL证书认证,KubeKey默认会创建。可以关注数据目录和资源预留。
    etcd:
      type: kubekey # 使用KubeKey内置部署方式
      # 数据目录,确保所在磁盘有足够空间和IOPS
      dataDir: /var/lib/etcd
    
    • kubernetes:配置容器运行时(我们选Docker)和网络插件(如Calico)。
    kubernetes:
      version: v1.26.15
      clusterName: cluster.local
      containerManager: docker # 指定使用docker
      etcdBackupDir: /var/backups/k8s-etcd # 配置etcd备份目录
      network:
        plugin: calico
        calico:
          ipipMode: Always # 或 CrossSubnet,根据网络环境选择
          vxlanMode: Never
          vethMTU: 1440 # 根据底层网络MTU调整
    
  4. 执行集群创建。配置文件确认无误后,开始部署。

    ./kk create cluster -f config-sample.yaml -y
    

    这个过程会持续较长时间(约10-30分钟,取决于网络和机器性能),KubeKey会自动完成所有节点的初始化、组件安装和配置。最终,你会看到集群创建成功的提示,并获取到kubeconfig文件,通常位于~/.kube/config

2.3 验证集群与高可用性测试

部署完成后,立即进行验证。

# 查看所有节点状态,应均为Ready
kubectl get nodes -o wide

# 查看所有管理节点上的核心Pod状态(在kube-system命名空间)
kubectl get pods -n kube-system -o wide | grep -E 'apiserver|scheduler|controller-manager|etcd'

# 查看etcd集群成员健康状态(在任一管理节点上执行)
docker exec -it $(docker ps | grep etcd | awk '{print $1}') etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/ssl/etcd/ssl/ca.pem --cert=/etc/ssl/etcd/ssl/node-guanlijiedian1.pem --key=/etc/ssl/etcd/ssl/node-guanlijiedian1-key.pem endpoint health

高可用测试:尝试手动停止其中一个管理节点(如guanlijiedian2)的kube-apiserver容器,或直接重启该节点。在此期间,使用kubectl命令(其访问地址指向HAProxy的VIP)应仍然可以正常操作集群,只是响应可能略有延迟。这证明了负载均衡器和多副本控制平面组件起到了作用。

3. Harbor企业级镜像仓库部署与安全加固

有了稳定的K8s集群,我们需要一个安全、高效的“后勤中心”来存储和管理容器镜像。Harbor正是为此而生。

3.1 Docker环境准备与优化

在独立的Harbor服务器上,我们首先安装Docker。这里不采用系统仓库的版本,而是使用官方二进制包,便于版本控制。

# 下载特定版本的Docker二进制包(以20.10.24为例)
wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.24.tgz
tar -xzvf docker-20.10.24.tgz
# 将二进制文件复制到系统路径
sudo cp docker/* /usr/bin/

# 创建docker组并添加当前用户
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker # 刷新组权限

# 配置systemd服务单元
sudo tee /etc/systemd/system/docker.service <<-'EOF'
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=1048576
LimitNPROC=1048576
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target
EOF

配置镜像加速器:这是提升镜像拉取速度、减轻公网依赖的关键一步。我们以阿里云加速器为例。

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://<你的专属加速器域名>.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "live-restore": true
}
EOF

提示:请务必替换registry-mirrors中的地址为你从阿里云容器镜像服务控制台获取的专属加速器地址。live-restore选项允许Docker守护进程重启时容器继续运行,对生产环境友好。

# 重新加载配置并启动Docker
sudo systemctl daemon-reload
sudo systemctl enable docker --now
# 验证安装
docker version
docker info | grep -A5 "Registry Mirrors"

3.2 Harbor v2.10 安装与核心配置

从Harbor官网下载离线安装包(harbor-offline-installer-v2.10.x.tgz)。

tar -xzvf harbor-offline-installer-v2.10.x.tgz
cd harbor

编辑配置文件harbor.yml。以下是最精简但满足生产基础需求的配置:

# 主机名或IP地址,客户端将用它来访问Harbor
hostname: harbor.yourcompany.com # 或直接使用IP,如192.168.1.200

# HTTP协议(生产环境强烈建议配置HTTPS,此处为简化先使用HTTP)
http:
  port: 80

# HTTPS协议(注释掉则禁用)
# https:
#   port: 443
#   certificate: /your/certificate/path
#   private_key: /your/private/key/path

# Harbor管理员密码
harbor_admin_password: Harbor12345 # 首次登录后务必修改!

# Harbor数据库密码
database:
  password: root123
  max_idle_conns: 50
  max_open_conns: 100

# 数据持久化目录
data_volume: /data/harbor

# 日志配置
log:
  level: info
  local:
    rotate_count: 50
    rotate_size: 200M
    location: /var/log/harbor

# 外部数据库和Redis(如需高可用,可配置外部实例)
# external_database:
#   harbor:
#     host: harbor_db_host
#     port: 5432
#     db_name: harbor
#     username: postgres
#     password: password
# external_redis:
#   host: redis_host
#   port: 6379
#   password: 

安全加固配置(在harbor.yml中):

# 启用内容信任(Notary),确保镜像来源可信
notary:
  enabled: true

# 漏洞扫描器(Trivy或Clair),集成安全扫描
trivy:
  enabled: true
  ignore_unfixed: false
  skip_update: false
  offline_scan: false
  security_check: vuln

# 设置项目配额,防止资源滥用
project_creation_restriction: adminonly # 仅管理员可创建项目

执行安装脚本:

sudo ./install.sh --with-notary --with-trivy

安装成功后,访问 http://harbor.yourcompany.com,使用admin和你在配置文件中设置的密码登录。

3.3 集成Kubernetes与Harbor

要让K8s集群能从私有Harbor拉取镜像,需要在集群中创建镜像拉取密钥(ImagePullSecret)。

  1. 在Harbor上创建项目,例如prod
  2. 创建机器人账户(Robot Account),赋予其对prod项目的拉取权限。这比直接使用管理员账户更安全。
  3. 在Kubernetes中生成Secret
    kubectl create secret docker-registry harbor-registry-secret \
      --namespace=default \
      --docker-server=harbor.yourcompany.com \
      --docker-username=robot$your-robot-account-name \
      --docker-password=your-robot-account-token
    
  4. 在Pod或Deployment中引用该Secret
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-app
    spec:
      template:
        spec:
          imagePullSecrets:
          - name: harbor-registry-secret
          containers:
          - name: app
            image: harbor.yourcompany.com/prod/my-app:v1.0
    

4. 生产环境运维、排错与优化实践

集群和仓库跑起来只是开始,如何让它稳定、高效地运行才是真正的挑战。

4.1 关键配置参数解析与调优

回顾我们使用的config-sample.yaml,理解几个关键参数对排错和优化至关重要:

  • etcddataDir:确保该目录挂载在性能较好的SSD磁盘上,并监控其磁盘使用率(超过80%需告警)。可以定期备份。
  • kubernetes.network.calico.vethMTU:如果集群节点间网络存在隧道(如云厂商的VPC网络),需要根据底层网络的MTU值调整此参数,通常设置为底层MTU - 50。设置不当会导致网络性能急剧下降或不通。
  • controlPlaneEndpoint:务必确保所有节点(包括计算节点)都能通过该地址(域名或IP)解析并访问到HAProxy。这是集群通信的基石。

4.2 常见故障排查场景

场景一:Pod状态一直Pending

# 查看Pod的详细事件,通常能直接定位问题,如资源不足、镜像拉取失败
kubectl describe pod <pod-name> -n <namespace>

# 如果事件提示镜像拉取失败,检查:
# 1. 节点是否能解析Harbor域名
# 2. Harbor项目权限和机器人账户令牌是否正确
# 3. 节点上的Docker daemon配置的`insecure-registries`是否包含了Harbor地址(如果使用HTTP)

场景二:节点状态NotReady

# 登录到问题节点,检查关键服务
systemctl status kubelet
systemctl status docker
journalctl -u kubelet --since "1 hour ago" | tail -100

# 常见原因:磁盘空间不足、内存压力、网络插件(Calico)Pod异常
df -h
free -h
kubectl get pods -n calico-system

场景三:kubectl命令执行缓慢或超时。 这很可能指向控制平面或负载均衡器问题。

# 检查HAProxy状态和日志
# 假设HAProxy运行在192.168.1.100上
ssh root@192.168.1.100 "systemctl status haproxy"

# 分别直接访问三个管理节点的API Server健康端点,检查是否都正常
curl -k https://192.168.1.101:6443/healthz
curl -k https://192.168.1.102:6443/healthz
curl -k https://192.168.1.103:6443/healthz
# 如果某个节点失败,登录该节点检查`kube-apiserver`容器日志

4.3 日常运维建议

  • 监控与日志:尽快部署集群监控(如Prometheus + Grafana),监控节点资源、Pod状态、etcd性能指标。集中收集所有组件和应用的日志(如EFK栈)。
  • etcd备份:使用etcdctl定期对etcd数据进行快照备份,并将备份文件传输到异地存储。KubeKey生成的集群,可以编写cronjob来执行备份。
    # 示例备份命令(需在etcd节点上,且有证书)
    etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/ssl/etcd/ssl/ca.pem --cert=/etc/ssl/etcd/ssl/node.pem --key=/etc/ssl/etcd/ssl/node-key.pem snapshot save /backup/etcd-snapshot-$(date +%Y%m%d).db
    
  • Harbor维护:定期清理不再使用的镜像层(通过Harbor UI的垃圾回收功能)。配置Harbor与外部用户目录(如LDAP/AD)集成,统一身份认证。为关键项目设置Webhook,当有新的漏洞扫描结果时通知安全团队。
  • 节点管理:对节点进行任何维护(如内核升级、重启)前,先使用kubectl drain <node-name>安全驱逐Pod。操作完成后,使用kubectl uncordon <node-name>将其重新加入调度。

这套从架构设计到部署、再到运维的完整流程,是我们团队在多个中小型生产环境中反复验证过的。它可能不是最豪华的配置,但在稳定性、可维护性和资源消耗之间取得了不错的平衡。记住,每一个生产集群都有自己的特性,最好的实践是在理解原理的基础上,根据实际的监控数据和故障反馈进行持续调优。刚开始可能会遇到一些坎,比如网络策略冲突、存储卷挂载失败,但每一次问题的解决都会让你对这套系统的掌控力更深一分。

更多推荐