我在现公司接手维护了一套传统架构运行的toB类型中台系统,后端是java的spring boot框架开发的,直接运行的腾讯云的虚拟机上面。由于之前一直是外包团队在做的,有些东西可以说是一次性的解决方式,可维护性极地。考虑到后续需要不断的增加业务功能,相关的模块也需要不断扩大,为了便于维护,我们开始了容器化的改造
前言 - 现有架构存在的痛点
- 发布无损问题,在发布的时候业务不能中断,平滑更新。如果还是按照部署在云主机上的架构来实现的话,可以实现,但能预见到的方案,都需要比较高的开发成本和维护成本。例如你要用nginx来控制两台机器的流量调度,那么jenkins在发布脚本中需要控制nginx进行切换,这个开发成本和危险性都是比较高的,而且这种方案感觉特别别扭,没有这么干的,业务流量的控制逻辑不能和发布系统耦合!
- 随着业务功能不断增加,从无到有上线一个新服务,变得复杂,或者说,我根本无法忍受这种无意义的重复劳动。需要购买服务器,对服务器初始化,安装java环境,配置jenkins,将服务发布上去,挂载到nginx下面。可以看到,这是一套非常传统架构下的流程。
- 发布系统按照环境区分,test环境有一套独立jenkins,prod有一套独立jenkins,这个对于运维的容忍程度,不用多说了吧?首先那个账号我就没空维护两套
- 主机名、代码仓库、分支命名、域名等常见规范,标准缺失,自动化的前提是标准化、流程化。需要拥抱更高的自动化,这些基本的规范标准一定要约定好
新老架构图对比
老的架构
容器化架构
实施过程
按照环境维度,逐一实施,开发环境除没有依赖腾讯云能力外,其他架构保持一致
标准先行
- 分支标准(开发将代码推到对应环境分支上,发布系统也只拉去对应分支的代码)
分支名称 | 发布系统拉取分支 | 环境 |
---|---|---|
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中添加一个域名配置。即可访问
访问逻辑图
统一管理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自带的模版库实现集中化管理
实施过程
-
dev环境
-
test环境同上
-
prod环境同上
遇到问题
- 例如测试只需要关注测试环境有没有被变更过,更pm只关注生产环境是否被变更,那么发布的通知消息,怎么通知?
按照环境进行区分,开发环境一个接收群,测试和生产各一个,zadig支持以工作流的维度创建通知钩子,正好可以满足这一点,而且分群,消息不会显得特别臃肿
- 构建时间过长
每发布一次代码,研发需要等待较长时间,严重影响迭代效率。我们使用了zadig自带的缓存构建,以项目纬度进行缓存,下次的构建将直接在缓存的目录中进行。其次像java构建对maven的使用cpu核数进行调优,npm的构建使用淘宝的npm库。经过优化后端和前端的单次发布,均可控制在3分钟左右