我在现公司接手维护了一套传统架构运行的toB类型中台系统,后端是java的spring boot框架开发的,直接运行的腾讯云的虚拟机上面。由于之前一直是外包团队在做的,有些东西可以说是一次性的解决方式,可维护性极地。考虑到后续需要不断的增加业务功能,相关的模块也需要不断扩大,为了便于维护,我们开始了容器化的改造

前言 - 现有架构存在的痛点

  1. 发布无损问题,在发布的时候业务不能中断,平滑更新。如果还是按照部署在云主机上的架构来实现的话,可以实现,但能预见到的方案,都需要比较高的开发成本和维护成本。例如你要用nginx来控制两台机器的流量调度,那么jenkins在发布脚本中需要控制nginx进行切换,这个开发成本和危险性都是比较高的,而且这种方案感觉特别别扭,没有这么干的,业务流量的控制逻辑不能和发布系统耦合!
  2. 随着业务功能不断增加,从无到有上线一个新服务,变得复杂,或者说,我根本无法忍受这种无意义的重复劳动。需要购买服务器,对服务器初始化,安装java环境,配置jenkins,将服务发布上去,挂载到nginx下面。可以看到,这是一套非常传统架构下的流程。
  3. 发布系统按照环境区分,test环境有一套独立jenkins,prod有一套独立jenkins,这个对于运维的容忍程度,不用多说了吧?首先那个账号我就没空维护两套
  4. 主机名、代码仓库、分支命名、域名等常见规范,标准缺失,自动化的前提是标准化、流程化。需要拥抱更高的自动化,这些基本的规范标准一定要约定好

新老架构图对比

老的架构

image.png

容器化架构

image.png

实施过程

按照环境维度,逐一实施,开发环境除没有依赖腾讯云能力外,其他架构保持一致

标准先行

  • 分支标准(开发将代码推到对应环境分支上,发布系统也只拉去对应分支的代码)
分支名称 发布系统拉取分支 环境
dev dev 开发环境
test test 测试环境
pre pre 预发环境
prod prod 线上环境
  • 服务启动指定环境变量(配置走nacos的服务忽略)
启动参数 环境
-Dspring.profiles.active=dev 开发环境
-Dspring.profiles.active=test 测试环境
-Dspring.profiles.active=pre 预发环境
-Dspring.profiles.active=prod 线上环境
  • 域名
应用名 域名 环境
admin admin.dev.xxx.com 开发环境
admin admin.dev.xxx.com 测试环境
admin admin.pre.xxx.com 预发环境
admin admin.xxx.com 线上环境
  • 名称空间划分(所有环境均保持一致)
namespace 名称 描述
business-middle 业务中台 置放业务所有前后端应用服务
data-middle 数据中台 置放所有数据平台相关的应用服务
technology-middle 技术中台 置放所有中间件类,开源平台类,运维类的服务

统一网关

老的架构是使用nginx来进行代理的,k8s中,我们选择了apisix来作为统一的网关服务器,因为更加便于配置和管理。同时,域名解析上,会使用通配符的规则,这样,新增域名,只需要在服务发布完成后,在apisix中添加一个域名配置。即可访问

image.png image.png 访问逻辑图 image.png

统一管理yaml和dockerFile

k8s Yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: $T-Service$
  name: $T-Service$
  namespace: $T-Project$
spec:
  replicas: 1
  selector:
    matchLabels:
      app: $T-Service$
  template:
    metadata:
      labels:
        app: $T-Service$
    spec:
      containers:
      - image: nj-image.xxx.com/$T-Project$/$T-Service$
        imagePullPolicy: IfNotPresent
        name: $T-Service$
        resources:
          limits:
            memory: 50Mi
            cpu: 50m
---
apiVersion: v1
kind: Service
metadata:
  name: $T-Service$
  namespace: $T-Project$
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 80
  selector:
    app: $T-Service$

DockerFile

FROM node:12-slim AS build

WORKDIR /app

COPY . .

RUN npm config set registry https://registry.npm.taobao.org/
RUN npm install
RUN npm run build:sit

FROM nginx:1.23
RUN ls -l 
COPY --from=build /app/dist /usr/share/nginx/html

利用zadig自带的模版库实现集中化管理 image.png

实施过程

  • dev环境 image.png

  • test环境同上

  • prod环境同上

遇到问题

  1. 例如测试只需要关注测试环境有没有被变更过,更pm只关注生产环境是否被变更,那么发布的通知消息,怎么通知?

按照环境进行区分,开发环境一个接收群,测试和生产各一个,zadig支持以工作流的维度创建通知钩子,正好可以满足这一点,而且分群,消息不会显得特别臃肿

  1. 构建时间过长 image.png

每发布一次代码,研发需要等待较长时间,严重影响迭代效率。我们使用了zadig自带的缓存构建,以项目纬度进行缓存,下次的构建将直接在缓存的目录中进行。其次像java构建对maven的使用cpu核数进行调优,npm的构建使用淘宝的npm库。经过优化后端和前端的单次发布,均可控制在3分钟左右

成果展示

持续交付系统的数据看板

image.png

构建效能

image.png

部署效能

image.png

结果通知

image.png