ApeCloud
开源社区关于我们

微服务应用部署运维

本文深入分析了微服务架构在现代应用开发中的重要作用,探讨了微服务应用在 Day 1(初次部署)和 Day 2(持续运营)阶段面临的主要挑战,指出了数据存储组件在其中的影响,包括组件创建效率、数据基线准备和恢复、可观测性、可扩展性以及高可用性等问题。以开源即时通讯应用 OpenIM 为例,本文详细介绍了如何通过 KubeBlocks 在 Kubernetes 中实现微服务应用的高效部署和运维,提供了包括环境准备、KubeBlocks 安装、数据存储组件初始化、OpenIM 应用组件部署以及运行状态验证的详细步骤,为其它微服务应用的部署运维提供了一定的借鉴意义。

微服务架构的由来

应用架构的演进是一个持续适应业务需求变化的过程。在应用系统发展的早期阶段,单体架构以其简单直接的设计理念占据主导地位。这种架构将所有功能模块集中在同一部署单元内,共享统一的技术栈,具有开发门槛低、部署方法简单等优势,有效支撑了企业级软件的发展。然而,随着业务规模的快速扩张,单体架构在开发效率和扩展性方面的短板日益突出,迫使业界开始探索新的系统架构,并由此催生了面向服务架构(SOA)。面向服务架将应用拆分为多个独立服务,通过企业服务总线(ESB)实现服务间通信,在保持系统灵活性的同时保证了通信协议的标准化,一定程度上突破了单体架构的瓶颈,因此被广泛应用于银行账户管理、交易处理以及运营商计量计费等关键业务系统。

尽管面向服务架构取得了巨大的成功,但集中式企业服务总线逐渐开始暴露出性能瓶颈问题,服务之间的耦合性也限制了业务的进一步发展。在全球互联网业务大爆发的背景下,微服务架构应运而生。与面向服务架构相比,微服务架构采用更细粒度的服务拆分,每个服务只专注于提供单一业务能力,进一步降低了系统的耦合度。更重要的是,微服务架构彻底摒弃了企业服务总线等中心化组件,服务能够通过更轻量的机制直接通信,大大提升了系统的吞吐量。

微服务架构凭借其在大规模、高并发场景下的优越表现,已成为 Google、Meta、Amazon 等互联网巨头的架构首选。这种架构模式的核心优势体现在多个维度:

资源效率

微服务支持按需对特定服务进行精准扩容,避免了传统架构中的资源浪费

研发效率

各团队可根据服务特点自主选择技术栈和发布节奏,实现了真正的独立演进

系统稳定性

服务间的有效隔离确保局部故障不会引发连锁反应,显著提升了整体可用性

部署策略

独立部署机制为灰度发布、A/B 测试等精细化运营提供了技术基础。

这些特性共同构成了微服务架构应对复杂业务场景的核心竞争力。

微服务应用的运维挑战

微服务在带来诸多优势的同时,也引入了新的复杂性。分布式系统固有的挑战——比如服务间通信、数据一致性、分布式事务等——需要更精细的设计和管理。基础设施层面需要构建服务注册发现、配置中心、监控告警等完整的支撑体系。在众多变化之中,数据存储组件运维模式的挑战尤其值得关注。

Day 1 - 初次部署上线

开发测试环境的独特需求与挑战

微服务架构导致的复杂组件依赖与编排

初始数据准备的复杂性与挑战

以开发测试环境的 CI/CD 流程为例,现代微服务应用在初次部署时面临诸多挑战。开发测试环境具有独特的特点:需要频繁创建和销毁测试环境以支持快速迭代,多分支并行开发需要环境隔离以避免相互干扰,自动化测试需要快速反馈以提高开发效率。

微服务架构在这个阶段带来的困难首先体现在组件依赖的复杂性上。一个完整的应用可能包含 10-20 个微服务,同时依赖多种数据存储组件:比如 MySQL 用于存储用户数据,Redis 提供高速缓存,MongoDB 存储日志数据,Kafka 处理异步消息。每个组件都有特定的版本、配置、拓扑结构、启动顺序,需要复杂的编排逻辑和错误处理机制。

初始数据的准备也变得更加困难。每个微服务依赖的数据存储组件需要分别进行数据初始化,而且这些数据之间往往存在关联关系。敏感数据的脱敏处理需要在保持数据关系完整性的同时确保安全合规。测试环境间的数据隔离要求每个环境都有独立的数据集,这大大增加了存储成本和管理复杂度。

Day-2 - 持续运营优化

客户环境高度差异化与适配调优

可观测性不足导致的根因分析困难

数据存储组件的可扩展性与高可用保障困难

当应用进入生产环境后,长期运维的挑战更加严峻。以生产环境的商业应用为例,客户环境往往高度差异化,有些客户使用公有云,有些则坚持私有化部署。每种环境都有其特定的网络、存储类型,需要适配调优。同时,生产环境对稳定性和安全性的要求极高,需要提供 7×24 小时不间断的保障。

可观测性是生产环境运维最直观的挑战。根因分析需要跟踪一个用户请求在多个服务间的完整调用链,不同技术栈的组件产生了各种格式的指标和日志数据,需要被统一采集、处理、存储、检索。而应用组件和数据存储组件往往在数据的采集粒度、聚合展示等方面存在配合问题。

可扩展性在生产环境中体现出多个维度的挑战。数据存储组件的扩展尤其困难,数据库的读写分离需要考虑数据同步延迟,分片扩展需要处理数据搬迁和流量均衡策略。不同类型的数据存储组件需要不同的资源类型,有些是 CPU 密集型,有些是内存密集型,还有一些是 IO 密集型,需要针对性的扩展方案。成本优化要求系统能够根据实际负载动态调整资源配置,避免过度配置造成的资源浪费。

除了可观测性和可扩展性外,保障微服务应用的高可用也是一大挑战,而这种挑战在数据存储组件上尤为突出。微服务架构往往会使用多种数据存储组件,而它们可能使用了不同的持久化技术,具有特定的故障模式和恢复机制,使得故障检测和自动恢复变得极其复杂。更严峻的是,数据存储组件的故障往往会产生级联效应,比如数据库的短暂不可用可能会导致多个微服务陷入异常状态,进而影响整个系统的稳定性。此外,不同数据存储组件的故障恢复时间差异较大,这种不一致性使得系统的 RTO 和 RPO 保障变得困难重重。

OpenIM 如何应对运维挑战?

OpenIM 是什么?

OpenIM 是一款开源的即时通讯应用,为用户提供完整的实时通信能力,包括单聊、群聊、音视频通话、文件传输等功能。作为一个高性能、高可用、易扩展的通信平台,OpenIM 广泛应用于企业内部协作、客服系统集成、社交应用后端、在线教育等场景。OpenIM 采取了微服务架构,将复杂的即时通讯功能拆分为多个独立服务,其中:

API Gateway 作为统一接入层

User Service 管理用户认证和资料

Friend Service 和 Group Service 分别处理好友关系和群组管理

Message Service 负责消息的收发路由

Push Service 实现多渠道推送

File Service 管理文件存储

除了应用组件外,OpenIM 还使用了多种数据存储组件,其中:

MySQL 存储用户信息、好友关系、群组等结构化数据

Redis 提供高速缓存,维护在线状态和会话信息

MongoDB 存储聊天消息记录等非结构化数据

无论是在 CI/CD 流程中完整部署一套 OpenIM,还是在生产环境中对 OpenIM 的运行状态进行观测、优化,都具有较高的复杂度。因此,OpenIM 建议在 Kubernetes 环境中使用 KubeBlocks 来解决相关难题。

OpenIM + KubeBlocks 联合方案

运行环境要求

在开始部署 OpenIM 之前,需要确保 Kubernetes 集群满足以下基本要求:

Kubernetes 版本1.22 或更高版本
工作节点3 个
单节点配置至少 4 核 CPU,8GB 内存,50GB 存储空间
网络插件 (CNI) 正常运行 (推荐 Calico、Flannel 或 Cilium)
存储插件 (CSI) 正常运行 (推荐 OpenEBS 或云厂商云盘 CSI)
外部访问 (可选)LoadBalancer 或 Ingress Controller 可用

以上环境将用于创建以下组件:

MySQL 集群副本配置:2 核 CPU,4GB 内存,20GB 存储
拓扑结构:1 主 + 1 从,具备高可用能力
Redis 集群副本配置:1 核 CPU,2GB 内存,10GB 存储
拓扑结构:3 节点集群
MongoDB 集群副本配置:2 核 CPU,4GB 内存,30GB 存储
拓扑结构:3 节点副本集
OpenIM 应用组件API Gateway:1 核 CPU,1GB 内存,3 副本
其它组件:每个服务 0.5 核 CPU,512MB 内存,2 副本

安装 KubeBlocks

推荐使用 Helm 安装 KubeBlocks,这种方式比较灵活且便于管理:

  1. 安装 Helm(如果未安装):
# 在 Linux/macOS 上安装 Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 验证 Helm 安装
helm version
  1. 添加 KubeBlocks Helm 仓库:
# 添加 KubeBlocks 官方 Helm 仓库
helm repo add kubeblocks https://apecloud.github.io/helm-charts

# 更新 Helm 仓库索引
helm repo update

# 查看可用版本
helm search repo kubeblocks/kubeblocks
  1. 安装 KubeBlocks:
# 安装 CRD
kubectl create -f https://github.com/apecloud/kubeblocks/releases/download/v1.0.0/kubeblocks_crds.yaml

# 创建专用命名空间并安装 KubeBlocks
helm install kubeblocks kubeblocks/kubeblocks \
  --namespace kb-system \
  --create-namespace \
  --wait

# 如果需要指定特定版本
helm install kubeblocks kubeblocks/kubeblocks \
  --namespace kb-system \
  --create-namespace \
  --version=1.0.0 \
  --wait
  1. 安装 kbcli 命令行工具:
# 安装 kbcli
curl -fsSL https://kubeblocks.io/installer/install_cli.sh | bash

# 将 kbcli 添加到 PATH(根据安装输出调整路径)
export PATH="$PATH:/usr/local/bin"

# 验证 kbcli 安装
kbcli version
  1. 检查 KubeBlocks 运行状态:
# 检查 KubeBlocks 总体状态
kbcli kubeblocks status

# 查看 kb-system 命名空间中的 Pod
kubectl get pods -n kb-system

# 检查 KubeBlocks Operator 日志
kubectl logs -n kb-system deployment/kubeblocks -f
  1. 检查内置插件(Addons):
# 查看所有可用插件
kbcli addon list
  1. 验证存储和网络:
# 检查 StorageClass
kubectl get storageclass

# 验证默认 StorageClass
kubectl get storageclass -o jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}'

# 检查网络连通性(创建测试 Pod)
kubectl run test-pod --image=busybox --rm -it --restart=Never -- nslookup kubernetes.default

初始化数据存储组件

  1. 创建 MySQL 集群:
# 创建 MySQL 主从集群
kbcli cluster create mysql mysql-cluster \
  --version 8.0.39 \
  --termination-policy WipeOut
  1. 创建 Redis 集群:
# 创建 Redis 集群
kbcli cluster create redis redis-cluster \
  --version 7.2.7 \
  --mode replication \
  --replicas 2 \
  --termination-policy WipeOut
  1. 创建 MongoDB 副本集:
# 创建 MongoDB 副本集
kbcli cluster create mongodb mongodb-cluster \
  --version 6.0.22 \
  --mode replicaset \
  --replicas 3 \
  --termination-policy WipeOut
  1. 创建 MongoDB 数据库和用户:
# 创建 MongoDB 数据库和用户
kubectl exec -it pods/mongodb-cluster-mongodb-0 -- /bin/bash
root@mongodb-cluster-mongodb-0:/# mongosh "mongodb://$MONGODB_USER:$MONGODB_ROOT_PASSWORD@mongodb-cluster-mongodb-mongodb:27017/admin"
mongodb-cluster-mongodb [direct: primary] admin> use openim_v3
mongodb-cluster-mongodb [direct: primary] openim_v3> db.createUser({
  user: 'openim',
  pwd: 'openimPassword123',
  roles: [{ role: 'readWrite', db: 'openim_v3' }]
});

部署 OpenIM 应用组件

  1. 创建 OpenIM 配置文件:
# openim-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: openim-config
  namespace: default
data:
  config.yaml: |
    mysql:
      address: mysql-cluster-mysql.default.svc.cluster.local:3306
      username: root
      password: "$(MYSQL_ROOT_PASSWORD)"
      database: openim_v3
      maxOpenConn: 100
      maxIdleConn: 10
      maxLifeTime: 5
    redis:
      address: redis-cluster-redis.default.svc.cluster.local:6379
      password: ""
    mongo:
      uri: mongodb://openim:openimPassword123@mongodb-cluster-mongodb.default.svc.cluster.local:27017/openim_v3?authSource=openim_v3
      address: mongodb-cluster-mongodb.default.svc.cluster.local:27017
      database: openim_v3
      username: openim
      password: openimPassword123
    api:
      openImApiPort: [ 10002 ]
    rpcport:
      openImUserPort: [ 10110 ]
      openImFriendPort: [ 10120 ]
      openImMessagePort: [ 10130 ]
      openImGroupPort: [ 10150 ]
      openImAuthPort: [ 10160 ]
      openImPushPort: [ 10170 ]
      openImConversationPort: [ 10180 ]
      openImRtcPort: [ 10190 ]
  1. 获取数据库密码并创建 Secret:
# 获取 MySQL root 密码
MYSQL_ROOT_PASSWORD=$(kubectl get secret mysql-cluster-conn-credential -o jsonpath='{.data.password}' | base64 -d)
# 创建包含数据库密码的 Secret
kubectl create secret generic openim-secret \
  --from-literal=mysql-root-password="$MYSQL_ROOT_PASSWORD"
# 应用配置文件
kubectl apply -f openim-config.yaml
  1. 部署 OpenIM 应用组件:
# openim-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: openim-api
  labels:
    app: openim-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: openim-api
  template:
    metadata:
      labels:
        app: openim-api
    spec:
      containers:
        - name: openim-api
          image: openim/openim-server:v3.5.0
          command: ['/openim/bin/openim-api']
          ports:
            - containerPort: 10002
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: openim-secret
                  key: mysql-root-password
          volumeMounts:
            - name: config
              mountPath: /openim/config
              readOnly: true
          resources:
            requests:
              memory: '512Mi'
              cpu: '500m'
            limits:
              memory: '1Gi'
              cpu: '1000m'
      volumes:
        - name: config
          configMap:
            name: openim-config
---
apiVersion: v1
kind: Service
metadata:
  name: openim-api-service
spec:
  selector:
    app: openim-api
  ports:
    - port: 10002
      targetPort: 10002
  type: ClusterIP
  1. 部署其他 OpenIM 组件:
# 应用 OpenIM 部署配置
kubectl apply -f openim-deployment.yaml

# 监控 Pod 启动状态
kubectl get pods -l app=openim-api -w

# 检查服务状态
kubectl get svc openim-api-service

验证 OpenIM 运行状态

  1. 检查所有组件状态:
# 检查数据库集群状态
echo "=== Database Clusters Status ==="
kbcli cluster list

# 检查 OpenIM 应用状态
echo "=== OpenIM Application Status ==="
kubectl get pods -l app.kubernetes.io/name=openim
kubectl get svc -l app.kubernetes.io/name=openim
  1. 验证应用功能:
# 检查 OpenIM API 健康状态
kubectl exec -it deployment/openim-api -- curl -f http://localhost:10002/healthz
# 查看应用日志
kubectl logs -l app=openim-api --tail=50

# 端口转发进行本地测试
kubectl port-forward service/openim-api-service 10002:10002 &

# 测试 API 接口
curl http://localhost:10002/healthz

通过以上验证步骤,确保 OpenIM 及其依赖的数据库服务都正常运行,具备处理实际业务请求的能力。

解决方案总结

KubeBlocks 微服务应用部署运维方案帮助 OpenIM 解决了容器化部署的核心挑战。在 Day 1 阶段,KubeBlocks 通过声明式 API 和命令行工具简化了高可用集群的部署难度,并且内置了各种数据存储组件的最佳实践配置,大幅降低了学习成本和出错概率。其生命周期管理管理功能和备份恢复机制可与 CI/CD 流程深度集成,支持数据基线的制作、更新,以及基于某个数据基线的快速恢复和释放。在 Day 2 阶段,KubeBlocks 为每种数据存储组件提供了专业的监控指标和告警规则,与应用组件的监控指标形成完整的可观测体系,让跨组件的故障排查更加高效。KubeBlocks 支持细粒度的弹性伸缩策略,可以动态调整 MySQL、Redis和 MongoDB 的拓扑结构以及副本数量,实现按需扩展。在高可用保障方面,KubeBlocks 提供了多可用区部署选项,显著提升了数据存储组件的容灾等级。

KubeBlocks 微服务应用部署运维方案正在支持更多类型的数据存储组件,进一步扩展其应用场景。除了 MySQL、Redis、MongoDB 等流行组件外,目前已经包括 InfluxDB 时序数据库、ZooKeeper 配置管理、RabbitMQ 和 RocketMQ 消息队列等关键组件。这使得 KubeBlocks 能够为物联网数据采集、金融交易处理、电商推荐系统、实时数据分析等更多微服务应用场景提供完整的部署运维能力支撑。