背景
博卡软件于2004年在上海成立,是一家专注于为本地美丽生活相关行业提供软件服务的SaaS软件提供商。主要产品是门店运营所需要的,管理软件,智能硬件以及营销小程序等。
作为一个不足30人的研发团队,并且没有真正专职的运维人员,面对快速增长的客户以及越来越多的需求,拥有20多个微服务,几十个前端应用(web,小程序,app等),传统的开发和部署的方式已经逐渐成为了我们研发团队的瓶颈,为了能高效的完成交付,我们开始了DevOps转型之路。
因为我们的SaaS应用完全部署在阿里云上,通过一个偶然的机会接触到云效后,我们开始了使用云效+阿里云ACK替代我们现有的Gitlab+Jenkins+ECS的CI/CD来实现DevOps。
为什么做持续交付?
因为我们服务的客户都是小商户为主,通常有需求或者遇到问题都不愿意等待一周或者几天时间,大多数时候都需要我们快速解决,并且因为我们客户量比较大,使得我们必须快速反应,做到持续交付,交付周期可能是一天一次,甚至一天几次。
源码管理
在对比了经典的Git Flow,Github Flow,以及Gitlab Flow之后,我们最终选择了更适合我们团队的Gitlab Flow来作为我们的Git工作流。
每个代码库的master分支通过webhook触发绑定测试环境的流水线构建,release分支绑定生产环境的流水线构建。同时设置master分支和release分支的保护规则,除了管理员外开发者不能直接push到master分支,需要通过评审后才能合并到master分支并触发测试环境构建,release分支只能通过合并请求的方式来push代码触发构建。
云效的代码管理Codeup的内置评审功能,能高效的完成Code Review。
内置的代码检测开箱即用,促进编码规范执行。
流水线
通过Flow流水线可以很简单的实现持续交付。Flow流水线比起Jenkins来最大的好处就是简单易用。
支持RAM子账号权限管理,可以统一账号体系,不用独立管理账号体系。在没有专门运维人员的情况下,针对不同的开发人员配置不同权限,可以方便安全的让所有开发人员去看构建失败原因,控制只有管理员或者指定人员触发人工卡点等各种操作,安全使用流水线。
内置多种语言的流水线模板,基本上主流的CI/CD模式都可以开箱即用。并且通过通用变量组可以配置不同环境的变量组来区别不同环境的集成和部署。
测试环境或生产环境通过通用变量组以及镜像名前缀区分。
生产环境可以增加人工卡点提前构建生成镜像,再选择合适的时间通过卡点以控制发布时间,或者实现了零停机部署的话可以直接部署。
单页面前端项目流水线则简单不少,只需要编写npm脚本,实现webpack打包并生成html产物,然后自动上传静态资源到cdn,最后把html产物上传到OSS中,即可完成。
容器化部署
阿里云上最优选择
部署的最佳选择,自然是Flow流水线的最佳搭档ACK。容器服务Kubernetes版(ACK)是简化了集群的搭建和扩容等工作,整合了阿里云虚拟化、存储、网络和安全能力,开箱即用的阿里云上最佳Kubernetes 容器化应用运行环境。其最大的优势就是低门槛,上手简单,运维简单。对于我们这种没有真正专职的运维人员的团队来说,是一大福音。因为Kubernetes本身较高的学习成本,一开始直接劝退了我们这种小团队。直到后面看到阿里云ACK后,因其免费使用,我们抱着试一试的心态尝试了一下,短时间就完成了demo的部署。经过一系列的测试和尝试后,我们决定把我们当时部署在ECS上的整套微服务,在ACK上通过Flow流水线部署一套克隆环境,最后通过Ingress的灰度能力逐步把流量切换到ACK上,顺利完成了ECS上自建的Tengine + Spring Cloud微服务应用的零停机的无缝迁移。上线ACK后,我们切实感受到了Kubernetes的强大。自动化的运维,包括自动故障迁移,自动资源调度,环境隔离,动态存储,负载均衡,零停机部署,自动扩容,以及故障时自动重启等各种强大的功能。通过简单配置甚至默认配置,即可享受这些功能。使用ACK后,我们的最大收益,主要是以下3点。
1. 节约成本。因为我们使用的微服务架构,有较多的微服务,部署的时候都做高可用,一个服务至少2个实例来做负载均衡。在使用ACK之前,主要是自己来根据经验等预判一个服务需要的cpu资源和内存资源,然后通过cgroup限制单个实例的cpu使用上限,并且通过jvm的配置来限制最大内存使用。按照这种方式来决定一台ECS可以部署多少实例。且不说手动配置cgroup有一定的运维知识,自行规划一般比较难做到非常高的资源利用率,而且如果有的实例发生问题甚至可能影响整个ECS上的其他应用。使用ACK的话,可以直接配置每个Pod的cpu和内存资源需求,然后交由Kubernetes来自己调度,配合上HPA的动态扩容,可以做到资源的最大化利用,同时也保证了应用的稳定性,使得硬件成本大幅下降的同时也没有牺牲稳定性。
2. 故障自动重启。通过Pod的健康监测和就绪监测,再加上应用暴露一个健康监测接口(比如SpringBoot的Actuator的health)即可简单实现故障自动重启,在应用初期问题较多的时候,或者发生突发问题的时候,自动重启大多数都能立马缓解问题,虽然不能根本解决,但是至少解决了小公司没有24*7快速响应运维人员的问题,可以做到自动化最高效的缓解问题。
3. 自动扩容。如果某些应用可能出现某个时间点非常高的流量或者应用突然需要很大的计算量,可以直接配置HPA自动扩容,设置规则后Kubernetes会根据条件自动扩容以保证应用的稳定性。
回滚
小团队持续交付,频繁发布,自然更容易出现问题,所以这就意味着我们需要时刻准备着滚回到上一个版本,或者说之前某一次更可靠的版本。通过Flow流水线可以回滚基本上所有部署方式。如果选择了阿里云ACK这种Flow的最佳搭档,则可以实现快速零停机回滚任意版本(通过健康监测以及重启策略确保启动的容器必然是可运行版本,如果出现无法启动或者启动异常的版本,则因为就绪监测无法通过是无法接收流量的,所以可以完成零停机或回滚),并且因为ACK是基于Docker镜像的升级,回滚的版本不会出现环境变化等各种其他因素造成的意外导致回滚失败。
效果
使用云效+ACK后的明显带来了以下提升:
对比内容 | 使用云效前 | 使用云效后 |
发布时长 | 10分钟 | 3分钟 |
代码评审 | 很少 | 合并主分支强制要求 |
构建通知 | 不通知 | 自动钉钉通知 |
版本回滚时长 | 1小时 | 3分钟 |
日常和生产环境区分 | 代码中配置文件区分,存在开发人员误修改影响部署环境配置的风险 | 自动注入环境变量来区分,最大程度防止代码库的配置文件影响部署环境配置 |
代码扫描 | IDE中插件自己扫描,比较随意 | 提交后自动扫描,清晰提示扫描结果 |
定时部署 | 人工等待到时间进行操作 | 设置定时发布 |
交付质量 | 依靠开发人员个人水平以及随机检查保证 | 通过各种检测插件进行质量检测,阻止异常构建或者部署 |
对比项 | 使用ACK前 | 使用ACK后 |
零停机部署 | 不支持 | 支持 |
应用异常自动修复 | 不支持 | 支持 |
扩容耗时 | 1小时 | 1分钟 |
扩容方式 | 手动修改nginx配置 | 自动扩容 |
敏感信息安全 | 代码库保存,存在泄露风险 服务器配置文件,管理成本高以及有丢失风险 不容易复用 | 配置项,以及保密字典存储,简单复用以及保密性高,不容易暴露 |
新应用部署 | 半天 | 10分钟 |
生产环境稳定性 | 出现问题客户发现或者监控发现后,手动回滚再修复问题重新发布,影响时间长 | 通过健康监测等手段阻止异常容器接收流量,以保证线上应用的基本质量 |
结语
SaaS公司要在竞争中拔得头筹,就需要快速响应客户需求,同时保持较高的稳定性。同时要快速占领市场,就需要不断推出新产品不断创新,这个时候开发的交付效率以及低成本试错就尤为重要。经过我们的不断尝试,最终找到了一套适合我们公司的高效流程和工具,那就是云效配合ACK来实现DevOps。
在DevOps上我们也是摸着石头过河,上面分享的方法只是我们团队当下寻找到的最佳方案,当然其中也有很多不足,我们也在不断的摸索和改进,这篇文章分享我们的DevOps转型过程就是希望可以跟大家多交流,共同探讨和摸索适合自己团队的模式。
作者介绍
韦嵩,2013年加入上海博卡软件科技有限公司,从事研发管理以及架构设计,现任职研发中心经理。先后主导了公司的架构演进:前后端分离,SaaS化转型,后端微服务改造,Kubernetes部署及应用,以及使用云效配合ACK实现DevOps转型。
本文内容非阿里云官方提供,如您发现本文档存在侵权内容或其他问题,请提供相应证明材料并在本页面内提交反馈信息,阿里云会协调或通知相关作者进行处理。