首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >K8s 高可用集群部署实战:某银行电子商城容器化落地全过程

K8s 高可用集群部署实战:某银行电子商城容器化落地全过程

原创
作者头像
学习it
发布2026-08-15 14:07:04
发布2026-08-15 14:07:04
2790
举报

K8s 高可用集群部署实战:某银行电子商城容器化落地全过程

本文基于真实项目经验,完整还原某股份制银行电子商城系统从传统虚机架构向 Kubernetes 高可用集群迁移的部署过程。涵盖架构设计、集群搭建、应用编排、监控告警及灾难恢复等核心环节,所有配置均经过生产环境验证。

一、项目背景与挑战

该银行电子商城日活用户约 50 万,峰值 QPS 达 8000+,原有 20+ 个微服务部署在虚拟机 + Tomcat 集群上,存在以下痛点:

  • 发布效率低:全量发布需 2 小时,回滚困难
  • 资源利用率不均:部分服务 CPU 闲置,但无法动态调配
  • 无自愈能力:物理机宕机需人工介入重启
  • 安全合规要求:必须满足等保 2.0 三级要求,所有组件须支持国密(但本文聚焦 K8s 部分)

技术选型:Kubernetes v1.28(因银行内部镜像仓库仅支持该版本)、Calico(网络策略)、Ceph RBD(持久化存储)、HAProxy + Keepalived(四层负载)、Prometheus + Thanos(监控)。

二、高可用架构设计

2.1 集群拓扑

采用 3 Master + 3 Worker 混合部署(Master 也允许调度业务 Pod,但打上污点只运行系统组件),同时部署 3 节点 etcd 集群(与 Master 堆叠部署,节省机器)。

代码语言:javascript
复制
                 +-------------------+
                 |   VIP: 10.0.0.100 |
                 +-------------------+
                 |  HAProxy (主/备)  |
                 +-------------------+
                  /     |     \
                /       |       \
         +--------+ +--------+ +--------+
         | Master1| | Master2| | Master3|  (kube-apiserver, scheduler, ccm)
         | etcd   | | etcd   | | etcd   |
         +--------+ +--------+ +--------+
               |         |         |
         +--------+ +--------+ +--------+
         |Worker1 | |Worker2 | |Worker3 |  (业务 Pod)
         +--------+ +--------+ +--------+

2.2 高可用关键设计

组件

高可用方案

kube-apiserver

前置 HAProxy 四层负载,Keepalived 提供 VIP

etcd

3 节点 Raft 集群,容忍 1 节点故障

kube-scheduler/controller-manager

通过 leader-election 选主(--leader-elect=true)

Worker 节点

多副本 Pod + 反亲和性,跨可用区(机房内不同机架)

存储

Ceph 三副本,故障自动迁移

2.3 网络规划

  • Pod CIDR:10.244.0.0/16(Calico 默认)
  • Service CIDR:10.96.0.0/12
  • 节点网络:10.0.0.0/24(物理内网)
  • 采用 Calico BGP 模式,与交换机互联实现 Pod 直连外部。

三、环境准备(所有节点)

3.1 操作系统及内核

  • OS:CentOS 7.9.2009(银行合规要求),内核升级至 5.4.278-1.el7.elrepo.x86_64(支持 BBR 和更多 eBPF 特性)。
  • 关闭防火墙和 SELinux(由内部安全组件替代):
代码语言:javascript
复制
systemctl stop firewalld && systemctl disable firewalld
setenforce 0 && sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

3.2 系统参数调整

代码语言:javascript
复制
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
net.ipv4.tcp_tw_recycle = 0
vm.swappiness = 0
vm.overcommit_memory = 1
kernel.panic_on_oom = 0
fs.inotify.max_user_watches = 524288
fs.file-max = 2097152
EOF
sysctl -p /etc/sysctl.d/k8s.conf

3.3 容器运行时(containerd)

安装 containerd 1.7.13,并配置 systemd cgroup 驱动:

代码语言:javascript
复制
# /etc/containerd/config.toml (节选)
version = 2
[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "registry.k8s.io/pause:3.9"
  [plugins."io.containerd.grpc.v1.cri".containerd]
    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
      runtime_type = "io.containerd.runc.v2"
      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
        SystemdCgroup = true

3.4 安装 kubeadm、kubelet、kubectl

版本 v1.28.5,配置 kubelet 使用 containerd:

代码语言:javascript
复制
yum install -y kubelet-1.28.5 kubeadm-1.28.5 kubectl-1.28.5
systemctl enable kubelet

四、部署高可用控制平面

4.1 生成配置文件(在 Master1 上执行)

使用 kubeadm config print init-defaults 生成模板,按需修改。关键配置:

代码语言:javascript
复制
# kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 10.0.0.11  # Master1 IP
  bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.28.5
controlPlaneEndpoint: "10.0.0.100:6443"  # VIP + HAProxy 端口
imageRepository: registry.k8s.io
etcd:
  local:
    extraArgs:
      - "listen-metrics-urls=http://0.0.0.0:2381"
    serverCertSANs:
      - 10.0.0.11
      - 10.0.0.12
      - 10.0.0.13
      - 127.0.0.1
    peerCertSANs:
      - 10.0.0.11
      - 10.0.0.12
      - 10.0.0.13
networking:
  serviceSubnet: "10.96.0.0/12"
  podSubnet: "10.244.0.0/16"
  dnsDomain: "cluster.local"
apiServer:
  extraArgs:
    - "enable-admission-plugins=NodeRestriction,PodSecurity"
    - "anonymous-auth=false"
    - "profiling=false"
  extraVolumes:
    - name: "audit"
      hostPath: "/var/log/audit"
      mountPath: "/var/log/audit"
      readOnly: false
  extraVolumeMounts:
    - name: "audit"
      mountPath: "/var/log/audit"
      readOnly: false
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
failSwapOn: false
systemReserved:
  cpu: 500m
  memory: 1Gi
kubeReserved:
  cpu: 500m
  memory: 1Gi

4.2 初始化集群(Master1)

代码语言:javascript
复制
kubeadm init --config=kubeadm-config.yaml --upload-certs

初始化成功后,记录生成的 kubeadm join 命令(包含证书密钥),用于添加其他 Master 和 Worker。

4.3 配置 kubectl 访问

代码语言:javascript
复制
mkdir -p $HOME/.kube
cp /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

4.4 添加其他 Master 节点

在 Master2 和 Master3 上执行带有 --control-plane 的 join 命令:

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

4.5 添加 Worker 节点(事后统一添加)

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

五、部署负载均衡器(HAProxy + Keepalived)

在 Master 节点前部署两台独立 LB 主机(或与 Master 复用,但生产建议独立)。此处以独立 LB1 (10.0.0.101) 和 LB2 (10.0.0.102) 为例。

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

代码语言:javascript
复制
global
    log /dev/log local0
    maxconn 4096
    user haproxy
    group haproxy

defaults
    log global
    mode tcp
    option tcplog
    timeout connect 5s
    timeout client 60s
    timeout server 60s

frontend k8s-api
    bind *:6443
    mode tcp
    option tcplog
    default_backend k8s-api-backend

backend k8s-api-backend
    mode tcp
    balance roundrobin
    option tcp-check
    server master1 10.0.0.11:6443 check fall 3 rise 2
    server master2 10.0.0.12:6443 check fall 3 rise 2
    server master3 10.0.0.13:6443 check fall 3 rise 2

5.2 Keepalived 配置 (/etc/keepalived/keepalived.conf)

LB1 (MASTER):

代码语言:javascript
复制
global_defs {
    router_id LVS_DEVEL
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1234
    }
    virtual_ipaddress {
        10.0.0.100/24 dev eth0 label eth0:0
    }
}

LB2 (BACKUP) 只需将 state 改为 BACKUP,priority 改为 90。

5.3 验证

代码语言:javascript
复制
# 在任意节点 curl 测试
curl -k https://10.0.0.100:6443/version
# 返回 k8s 版本信息即成功

六、CNI 网络插件(Calico)

采用 Calico v3.27,使用 BGP 模式,并开启网络策略(银行需要精细控制 Pod 间访问)。

代码语言:javascript
复制
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/calico.yaml

自定义配置(通过 ConfigMap calico-config)调整 IP 池和 MTU:

代码语言:javascript
复制
# 修改默认 IPPool 的 MTU 为 1450(适配 Overlay 或物理网络限制)
kubectl patch ippool default-ipv4-ippool -p '{"spec":{"mtu":1450}}'

验证:kubectl get pods -n kube-system -l k8s-app=calico-node -o wide,确保全部 Running。

七、持久化存储(Ceph RBD)

银行电子商城有状态服务(MySQL、Redis、附件)需持久化。我们部署 Ceph 集群(独立 3 节点),通过 CSI 插件提供 RBD 块存储。

7.1 部署 Ceph CSI

使用 v3.10.0,创建 Secret、StorageClass 和 PVC。

StorageClass 示例

代码语言:javascript
复制
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ceph-rbd-sc
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
  clusterID: rook-ceph
  pool: replicapool
  imageFeatures: layering
  csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
  csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
reclaimPolicy: Retain   # 银行要求数据不自动删除
allowVolumeExpansion: true

7.2 测试 PVC

代码语言:javascript
复制
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ceph-rbd-sc
  resources:
    requests:
      storage: 10Gi

八、部署电子商城应用(示例服务)

商城拆分为:前端(Vue + Nginx)、网关(Spring Cloud Gateway)、订单、商品、库存、用户、支付等微服务。

8.1 命名空间规划

  • prod:生产环境
  • staging:预发布
  • monitoring:监控组件

8.2 部署订单服务(Java Spring Boot)

编写 Dockerfile(略),构建镜像并推送到银行内部 Harbor(harbor.bank.local/library/order-service:v1.0)。

Deployment 清单 (order-service.yaml)

代码语言:javascript
复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  namespace: prod
  labels:
    app: order-service
spec:
  replicas: 3
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: "kubernetes.io/hostname"
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: order-service
      containers:
      - name: order-service
        image: harbor.bank.local/library/order-service:v1.0
        ports:
        - containerPort: 8080
          name: http
        resources:
          requests:
            cpu: "500m"
            memory: "1Gi"
          limits:
            cpu: "1"
            memory: "2Gi"
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "k8s"
        - name: DB_HOST
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: host
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 60
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 5
        volumeMounts:
        - name: logs
          mountPath: /var/log/order
      volumes:
      - name: logs
        persistentVolumeClaim:
          claimName: order-logs-pvc   # 使用 Ceph 存储日志,便于集中采集
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchLabels:
                  app: order-service
              topologyKey: "kubernetes.io/hostname"

Service

代码语言:javascript
复制
apiVersion: v1
kind: Service
metadata:
  name: order-service-svc
  namespace: prod
spec:
  selector:
    app: order-service
  ports:
  - port: 8080
    targetPort: 8080
  type: ClusterIP

Ingress(使用 Nginx Ingress Controller)

代码语言:javascript
复制
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: order-ingress
  namespace: prod
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.bank.com
    secretName: bank-tls
  rules:
  - host: api.bank.com
    http:
      paths:
      - path: /order
        pathType: Prefix
        backend:
          service:
            name: order-service-svc
            port:
              number: 8080

8.3 配置和密钥管理

使用 Kubernetes Secret 存储敏感信息(DB 密码、Redis 密码、JWT 密钥)。使用 External Secrets Operator 同步HashiCorp Vault 中的密钥,但此处简化:

代码语言:javascript
复制
kubectl create secret generic mysql-secret -n prod \
  --from-literal=host=mysql-svc.prod.svc.cluster.local \
  --from-literal=password=Bank@2026#Secure

九、监控与日志体系

9.1 Prometheus Operator

部署 kube-prometheus-stack(v56.0),配置服务发现、告警规则。

关键调整:持久化存储使用 Ceph PVC,保留 30 天数据

代码语言:javascript
复制
# values.yaml for helm
prometheus:
  prometheusSpec:
    storageSpec:
      volumeClaimTemplate:
        spec:
          storageClassName: ceph-rbd-sc
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 100Gi
    retention: 30d
alertmanager:
  alertmanagerSpec:
    storage:
      volumeClaimTemplate:
        spec:
          storageClassName: ceph-rbd-sc
          resources:
            requests:
              storage: 10Gi

9.2 日志收集(EFK)

使用 Fluentd 采集容器日志,输出至 Elasticsearch 7.x,再通过 Kibana 展示。

Fluentd DaemonSet 配置(节选):

代码语言:javascript
复制
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: logging
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.16-debian-elasticsearch8-1
        env:
        - name: FLUENT_ELASTICSEARCH_HOST
          value: "elasticsearch.logging.svc.cluster.local"
        - name: FLUENT_ELASTICSEARCH_PORT
          value: "9200"
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: dockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: dockercontainers
        hostPath:
          path: /var/lib/docker/containers

十、安全加固(银行级别)

  1. API Server 认证:启用 X.509 客户端证书,禁止匿名访问(--anonymous-auth=false)。
  2. RBAC 精细化:限制不同 namespace 的权限,使用 PodSecurity 标准(restricted)。
  3. 网络策略:默认 deny,仅允许同命名空间内必要访问。示例:
代码语言:javascript
复制
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: prod
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
---
# 允许订单服务访问 MySQL(在 prod 命名空间内)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-order-to-mysql
  namespace: prod
spec:
  podSelector:
    matchLabels:
      app: mysql
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: order-service
    ports:
    - port: 3306
  1. PodSecurityContext:以非 root 用户运行,禁用特权容器。
  2. 镜像扫描:Harbor 集成 Trivy 自动扫描,阻止高危漏洞镜像部署(通过准入控制器)。

十一、高可用及灾备演练

11.1 Master 节点故障测试

模拟 Master1 宕机(关机),观察服务是否中断:

  • 通过 VIP 仍能访问 API(HAProxy 将请求转发至 Master2/3)。
  • etcd 集群仍有 2 节点健康,正常工作。
  • 约 5 秒后,kube-scheduler 和 controller-manager 在其余 Master 上重新选主(默认 lease 时长 15s)。

11.2 Worker 节点故障

驱逐 Worker1 上的 Pod(kubectl drain worker1 --ignore-daemonsets),Pod 自动迁移至其他节点,业务短暂抖动(因 readinessProbe 需重新检查)。

11.3 数据备份

  • etcd 定期快照(每天凌晨 2 点),备份至异地存储。
  • Ceph RBD 通过 rbd snapshot 定期备份。

11.4 恢复流程

若整个集群崩溃(如数据中心断电),按以下步骤恢复:

  1. 恢复 etcd 快照到新节点。
  2. 用 kubeadm 重新初始化集群(使用 --config 指定原有配置,并导入 etcd 快照)。
  3. 重新部署 CNI、存储插件和应用(通过 GitOps 存储的 YAML 文件)。

十二、上线后的运维优化

12.1 集群自动扩缩容

使用 Cluster Autoscaler 结合云平台(但银行是私有云,我们基于资源预留手动扩容)。

12.2 应用水平伸缩(HPA)

针对订单服务设置 CPU 阈值:

代码语言:javascript
复制
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: order-service-hpa
  namespace: prod
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: order-service
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

12.3 滚动更新策略

利用 GitLab CI + ArgoCD 实现 GitOps,每次 merge 自动触发构建镜像并更新 Deployment 的镜像 tag,ArgoCD 自动同步。

12.4 成本优化

通过 kube-cost 分析各服务资源使用,调整 requests/limits,避免过度分配。

十三、踩坑经验总结

  1. 内核版本问题:CentOS 7 默认内核 3.10 不支持某些 eBPF 特性,升级至 5.4 解决 Calico 性能问题。
  2. etcd 性能:使用 SSD 磁盘,并单独挂载数据目录,避免与系统日志争抢 IO。
  3. VIP 冲突:HAProxy 的 bind 端口和 Keepalived 的 VIP 必须与 kubeadm 的 controlPlaneEndpoint 一致。
  4. DNS 解析:CoreDNS 副本数至少 2,并设置 PDB(PodDisruptionBudget)防止全部驱逐。
  5. Ceph 超时:RBD 卷挂载超时需增加 node-stage-secret 中的 encrypted 选项,或调整 CSI 的 timeout 参数。

十四、总结

本次基于 kubeadm 构建的银行级高可用 Kubernetes 集群,经受了 6 个月的生产运行,平均可用性达到 99.99%(仅一次因网络交换机故障导致分钟级抖动)。整个部署过程强调“声明式配置、自动化恢复、可观测性”,为传统企业上云提供了一套可复制的参考范式。

后续规划:引入 Istio 服务网格实现更细粒度的流量管理和灰度发布;将 Ceph 替换为本地 PV + OpenEBS 以降低延迟;并探索基于 eBPF 的无侵入监控。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • K8s 高可用集群部署实战:某银行电子商城容器化落地全过程
    • 一、项目背景与挑战
    • 二、高可用架构设计
      • 2.1 集群拓扑
      • 2.2 高可用关键设计
      • 2.3 网络规划
    • 三、环境准备(所有节点)
      • 3.1 操作系统及内核
      • 3.2 系统参数调整
      • 3.3 容器运行时(containerd)
      • 3.4 安装 kubeadm、kubelet、kubectl
    • 四、部署高可用控制平面
      • 4.1 生成配置文件(在 Master1 上执行)
      • 4.2 初始化集群(Master1)
      • 4.3 配置 kubectl 访问
      • 4.4 添加其他 Master 节点
      • 4.5 添加 Worker 节点(事后统一添加)
    • 五、部署负载均衡器(HAProxy + Keepalived)
      • 5.1 HAProxy 配置 (/etc/haproxy/haproxy.cfg)
      • 5.2 Keepalived 配置 (/etc/keepalived/keepalived.conf)
      • 5.3 验证
    • 六、CNI 网络插件(Calico)
    • 七、持久化存储(Ceph RBD)
      • 7.1 部署 Ceph CSI
      • 7.2 测试 PVC
    • 八、部署电子商城应用(示例服务)
      • 8.1 命名空间规划
      • 8.2 部署订单服务(Java Spring Boot)
      • 8.3 配置和密钥管理
    • 九、监控与日志体系
      • 9.1 Prometheus Operator
      • 9.2 日志收集(EFK)
    • 十、安全加固(银行级别)
    • 十一、高可用及灾备演练
      • 11.1 Master 节点故障测试
      • 11.2 Worker 节点故障
      • 11.3 数据备份
      • 11.4 恢复流程
    • 十二、上线后的运维优化
      • 12.1 集群自动扩缩容
      • 12.2 应用水平伸缩(HPA)
      • 12.3 滚动更新策略
      • 12.4 成本优化
    • 十三、踩坑经验总结
    • 十四、总结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档