在大中型企业,建设基础架构已经有一套完善的技术流程和处理方法,那为何我还要构建一个极简的基础架构呢?因为,中大企业的技术架构并不适用于个人或小团队,毕竟小团队在人力和财力上是无法和企业相提并论的。效率和成本是一切,减到不能再减,构建一个极简的满足个人和小团队的一套高效工具,也是很有价值的。
那么,我的现状和需求是怎样的呢?
现状是,我大概有10多个服务。有的提供web服务,有的API接口;使用不同语言(Golang和PHP,Java);用到了MySQL和搜索服务(比较老的xunsearch,现在大家用elasticSearch会比较多);多台Linux机器部署;
需求是,代码需要使用GIT;所有提供的接口都需要签名,防止外部非法调用;要能将服务部分自动化;要能在10分钟内能将服务部署到其他机器;要能10分钟内将服务迁移到新的服务器。数据库需要每天备份;
上面的,就是我的现状和需求。大家也可以看得出来,这些需求其实和具体的开发项目无关,更多的是怎么方便部署和运行项目,减少维护成本和资源成本,而且要做到高效率。
接下来,讲讲我是如何拆解这些需求的。
万丈高楼平地起,先选择一个合适的代码仓库。git是毋庸置疑的,那该选择哪个产商的?最少有几个选择,github、开源中国码云、阿里云codeup,个人建议选国内大公司,有速度和安全保证。我用的是阿里云codeup,用了起码有7年之多,安全上心里有底,而且私有仓库免费。
解决仓库问题,我们先从最大的块开始。数据库/搜索服务/缓存服务如何做?这个其实看具体的业务需求,如果有较好的资金支持,可以买云商的小规格服务,免去自己维护(日常维护、备份、优化等)。数据是重中之重,强调一万遍都不足为过。因为我的服务访问量不大,资金有限,所以我选择自建。MySQL自建很重要的是,将权限管理好,数据备份管理好,主要慢查询优化。缓存服务自己搭建不太合适,吃内存的服务,如果业务有一定的量级,也建议买小规格云商服务,还有一种混合型缓存服务,可以自建成本很小,这里不再深入。搜索服务,我选择的是xunsearch不具有可操作性(老项目维护用),这个服务吃资源较小,但是只有PHP的SDK,其他语言接入有点麻烦。
解决持久化数据需求后,随后最重要的就是微服务本身了,这里暂且不细说了,无非就是标准套件。如PHP要通过php-fpm运行或直接上swoole,java就单个命令启动即可,golang也可单个命令启动(编译时国内需要用proxy)。
有了代码,持久化的数据库,就可以让项目跑起来了。那如何进行对这些跑起来的服务,对外提供服务呢?
首先,第一个要说的是域名。域名是直接提供给用户的,我们要考虑的是,要将域名指定到哪些项目。在我们做架构的时候,会先将域名解析到公网入口。我现在的做法是,将域名托管到DNSPOD,再通过DNSPOD管理子域名。
那这里公网入口是什么呢?可以是SLB地址,也可以是具体的ECS机器公网地址。SLB是为了做负载均衡,提供7*24小时不间断服务,同时能提供对各种攻击的防御(这个视具体的服务商而不同)。我自己搭建的就是一个ECS机器,缺点是有点单问题。
其次,就是如何对API进行管理了(如签名,权限认证,统计等)。现在我们把这一块的管理全归纳到API网关上,让网关来专门解决这样的问题。市面上成熟的网关有很多,不管实现不一样,也有解决不同技术栈问题的,比如就有专门做容器化网关的。
很早之前,使用nginx来管理,是非常普遍的方案,现在还有很多网站在使用。nginx不便的地方是使用c语言开发的,扩展起来成本较高,所以大神章亦春将nginx和lua结合,做出了openresty,从而让nginx插件(一种扩展nginx功能的方式)开发效率大大提高。随后,就出现了基于openresty做的网关服务kong和apisix。kong和apisix目前都有很多的应用,是很成熟的API网关服务。
我自己的架构选择了Kong,一来商业应用成熟,是业内明星,二来自己熟悉原理和使用,插件丰富,使用成本小。其三,我想保持简单,毕竟很多服务是我个人在维护的。对于大家来说,国内的apisix也是个不错的选择,免费开源的,有众多开发者参与,性能比kong优秀,重要的是它对接了etcd服务发现机制(微服务的重要功能之一),内部使用radixtree作为路由调度,在未来apisix将会有不错的发展。
选定好了Kong之后,管理域名和API就比较方便了。
我将我的每个服务都定义成一个SERVICE,一般来说,就是对应的一个域名。
然后,给每个服务定义UPSTREAM,也就是后端服务集群。
每个upstream里定义的是targets,就是每个机器。这个看到的不是IP地址,是因为我的服务都容器化了。(这里没有用到服务发现机制,手动配置的服务地址。有了自动发现,就可以免去这个麻烦。)
如何将不同的域名或API地址分配到不同的服务?其实就是添加ROUTE。
那如何处理签名呢?
给指定的SERVICE或ROUTE添加plugin就可以了。签名逻辑可能每家公司都不太一样,可以直接基于lua写一个插件就能很容易实现。
好了。解决完API入口问题。我们继续后面的需求吧。
如何解决服务部署呢?这里重要的点是,如何10分钟内做到迁移服务,部署新服务,效率很重要。
如果使用常规方法,在机器上安装软件,是很难做到的。容器化,是一个可行的方法。
小团队或个人也搞一套容器化,会麻烦死的吧?实践证明,一点也不。做到后来,就是通用的模板,改改就能实现。
容器化,首先需要在你的项目里定义一个Dockerfile,写起来并不难也不麻烦。
那这个文件如何使用呢?我们需要一套脚本来把这个服务部署自动化。
这里我简单说一下实现的原理:
- 本地触发远程命令(ssh到目标机器的同时发送命令),也就是下面的 ,upload-aliyun-digital 命令
- 在远程执行拉取代码
- docker image 构建和重启
这个过程中,有个基础需要做,那就是本地和远程的ssh权限需要打通。服务器和git仓库的权限,需要打通。(不是必须的,减少输入密码的麻烦)
这里没有使用jenkins,也是为了节约成本,由于在本地执行,就不用远程服务了。
先看一下效果,截图发布的是一个golang项目。
发布完了,就能看到已经切到新的代码了。
这个命令就是触发整体执行流程的。
需求里的最后说一点,就是数据的备份。
备份使用的是阿里云OSS,不能把数据备份到本机,是因为数据还是有丢失的风险。(误删除或硬盘损坏或其他)。
将备份脚本放到git里,再通过自动化发布的方式发布到指定机器的crontab里,再定时将数据备份到OSS上,实现永久存储。
到此,整个需求都拆解完了,也是目前我的10几个项目管理方式,简单和高效是第一位的。
说说不足和改进吧。
整体是一个可运行的最小系统,虽然引入了docker可能使整体方案变得有点复杂,但是为了减少维护成本这点付出还是值得的。
整个过程中,权限方面没有说,其实我是有最大的权限,如果多人使用,在大家都很信任的情况下,也还是有安全风险的。(如果是团队,就还是用jenkins吧)
整体服务不具有7*24可用性,如果对这方面有要求,就需要不同的方案。公网入口负载均衡,网关负载均衡,故障机器自动摘除,还有服务发布时的可用性。
最后,就是监控和报警。这里也没有提到,如果在时间的工作中,这方面还是非常重要的。
好了,就到这里。欢迎一起交流。