原创

基于DevOps平台构建自己博客:2-整体架构设计

温馨提示:
本文最后更新于 2022年11月15日,已超过 490 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

上一篇介绍了需求和技术选型,这一篇我们会介绍具体的架构设计。这里给大家说明一下,当前这个项目相关的课程,都是按照真实的项目实施顺序进行,在实际的工作当中,虽然会复杂许多,但是技术相关的环节是基本一样的。同时涉及到的工具、工作方法、解决问题的思路,都是这么多年本人工作经验的总结。相信对大家会有一定的帮助。

先回顾我们的需求和技术选型:基于DevOps平台构建自己博客:1-开篇

我们先从博客系统开始,从这个开始的主要原因是我们已经有确定的系统,这样,我们只需要理解其技术栈、编译方式、配置方式、部署方式、运行方式以及系统所需要中间件,就可以知道其基础环境所必须的那些东西。当然,对于一个全新的系统,在目标系统尚未设计开发的情况下,我们的架构设计也依然需要明确这些,至少我们的目标系统的运行环境、技术栈及各方面的限制,如网络、硬件、磁盘、应用系统技术框架(前后端框架)、缓存、MQ、文件系统、数据库、以及其他三方系统等等。

一般来讲,系统架构设计到目标系统的各个方面,能够收集到的信息尽可能的完整且准确。但设计的时候,尽量使用通用的、成熟的解决方案,针对特殊化的场景,在满足用户需求的同时,也需要考虑对应的弊端以及影响面的大小,同时,可以做多个方案的对比,以便更好的权衡其中的利弊。

废话不多说,现在开始我们的整体架构设计!

一、域的划分

一般而言,对于一个生产系统,我们需要对整体网络环境做域的划分,主要原因是出于安全的考虑,域的划分可以很好的制定各域之前的访问规则,这种规则是强制约束的,一般通过防火墙的策略配置及网络划分实现。虽然我只有一台云主机,并且无法配置防火墙的策略,但是,我仍然希望我的网站可以尽量趋近于这种设计。暂时先不管那么多,先设计了再说。如下是我的域划分:

从图中可以看出,我划分了四个域: DMZ域,APP域,DB域和Cache域。

DMZ域:该域支持INBOUND和OUTBOUND的流量,即可以访问外界互联网,也允许外界访问。

APP域:只允许来至DMZ域的INBOUND流量,即只允许DMZ域的访问。

DB域:只允许来至APP域的INBOUND流量,即只允许APP域的访问。

Cache域:只允许来至APP域的INBOUND流量,即只允许APP域的访问。

由域划分可知,整个网站的入口为DMZ域,而DMZ域之外是不可以访问我们的APP域、DB域以及Cache域的,应用层及以下均为内网环境。

域的划分是约定了我们网络的隔离策略,划定了网络区域间的关系,同时,也对区域内的组件提供了部署的依据。比如,后续我们继续增加web应用,就可以放到APP域中,这样,新增的应用就天然的满足本身需要的网络环境,而不必过多的考虑其他放通策略。

 

二、部署架构

基于一中的域划分,我们就可以考虑我们的部署架构具体的样子了。具体的思考方式就是我们最终要达成的目标是什么?有哪些问题?有哪些现有的资源?有什么样的限制?目标在第一篇的需求已经讲过了,这里再做一下细化,同时,补充一些具体的问题。

1. 中间件

    搭建一个可外网访问的博客,博客有自己的应用系统,依赖了中间件,具体中间件有Mysql、Redis。

2. 容器化

    由于我只有一台云服务器,所以,要做到更好的隔离,最简单的方式就是使用容器化技术,这里我仅使用了Docker。虽然业界采用K8S+Docker的方式更多,但是K8S本身就需要部署管理集群做支撑,在当前资源有限的情况下,对于一个个人网站,没有其他要求的情况下:如资源动态调度、滚动发布、微服务系统架构支撑、故障自主剔除与恢复等等。K8S本身对于我的需求来说,本身就过于厚重。但是Docker本身的轻量级容器特性,已经可以很好的满足了我的需求。所以,Docker还是需要保留的。

3. 限制及约束 

    选定容器化后,就会涉及到哪些组件需要做容器化部署,部署后会有哪些问题?最近简单的判别标准就是看我们的域是怎么划分的。通过域划分我们可以知道,Nginx、应用系统、Mysql、Redis都是需要的,这样才能做到隔离。但是容器化后,就会涉及到一些问题。比如:

(1)配置是写在固定的配置文件,还是在容器初始化时就设定好?

(2)需要长时间保留的数据,如Mysql的数据文件如果放到容器里面,则容器删除或重建就会丢失。

(3)应用系统运行时的日志、文章中上传的附件、文章中涉及到的图片等静态资源,如果只保留在容器内,则其他容器访问就相对困难。

(4)容器之间本身是隔离的,但是组件之间是有依赖关系的,所以,也就是容器之间的通讯是必然的,所以,容器间的网络放通也需要处理。

以上这些问题,会在后续的文章中详细告诉大家如何解决。当前,我们需要确定的就是,容器化后这些问题是否有解决方案,答案是有的。针对配置文件、数据文件、静态文件这些,我们只需要在创建容器的时候映射物理机文件系统或本地磁盘即可。针对容器间网络通讯问题,只需要通过link参数放通网络访问即可解决。

4. 宿主机

    对于一个涉及多个容器化部署,各种各样的配置的系统,我不希望改个代码就手动的编译或者替换class文件,再传到服务器上。我希望有一套流水线支撑我的编译、部署工作。流水线的问题我们在选型的时候已经说过,使用CODING平台的能力即可实现。部署也是一样,但需要注意的是,需要将我们的云主机授权给DevOps的管理,这个方式是通过平台的添加堡垒机实现的,也就是通过在宿主机上安装Agent,实现DevOps与宿主机的通信与命令执行。所以,我还要在我的云主机上安装一个平台的Agent。

以上这些就是我在做架构设计考虑的一些问题,确定可行性及解决方案之后,我的架构基本就可以形成了,具体参考如下:

由上图可知,我们的系统是部署在腾讯云上,网络接入层是由云厂商提供的能力,我们没有更多的操作空间。下层我们部署了5个Docker实例,分别是资源号:R1~R5,在真实的项目中,除了我们的资源编号,还会附带物理机/宿主机的信息,这样,才能知道,具体哪个组件部署在哪些物理机和哪些虚拟机中。即使是使用K8S管理云上资源,也是需要这些信息的,因为K8S的资源调度策略依然依赖他们。在容器服务群之外,物理机上会有文件存储的映射。由于资源有限,我们没有文件系统或者外挂盘,所以只能拿本地磁盘映射成外挂盘,作为文件系统使用。最后,由于我们想要通过流水线工具实现我们的自动化编译部署,所以,需要在物理机上部署对应的Agent,以便Coding平台的可以在我们的物理机上执行相应的命令。

 

三、资源清单

下面通过一个表格来梳理下我们的资源清单:

编号 名称 容量 所属域 说明
R1 nginx 共享主机配置(CPU:2C, MEMORY: 4G) DMZ 代理接收外部请求,统一配置入口、协议以及静态资源加速。
1. 指定端口请求转发到R2和R3
2. 加载宿主机配置文件
3. 加载宿主机证书文件
4. 应用静态资源文件配置
R2 app-web 共享主机配置(CPU:2C, MEMORY: 4G) APP 前端应用,需加载宿主机上指定配置文件。
R3 app-admin 共享主机配置(CPU:2C, MEMORY: 4G) APP 管理应用,需加载宿主机上指定配置文件。
R4 mysql 共享主机配置(CPU:2C, MEMORY: 4G, DISC: 30G) DB 数据库。数据文件需持久化到宿主机硬盘。
R5 Redis 共享主机配置(CPU:2C, MEMORY: 4G) Cache 缓存。仅允许R2和R3访问,不开放对外端口。

其实稍微大些的项目中,涉及的资源远比上面的多得多,资源清单的内容也更为详细,资源规模涉及到几个环境,类似DEV、SIT、UAT、PRD、LDR、RDR等等,这里只做简单的示范。资源清单对于项目启动初期,环境搭建起到了至关重要的作用,通过资源清单,项目组可用清楚的知道需要购买哪些资源,资源配置容量是多少,预算花费金额,结合部署架构和网络架构,就可以清楚理解系统搭建后的样子。

在资源清单确定以后,就可以计划购买资源,实施环境搭建,一般会先由DEV,SIT,UAT开始,PRD在最后,如果资源足够且费用不作为主要参考指标的情况,可以安排各个环境的部署架构完全一致,配置上做缩减。但是,大多数的项目并没有完美的资金预算,能够支撑的环境也有限,从资源的角度来讲,一方面可以缩减环境,比如测试环境仅保留UAT,而这个UAT环境承接了DEV和SIT的工作。生产环境仅保留PRD,不再要求系统支持switchover。同时,还可以通过资源共用的方式来节省成本。例如,数据库层面划分不同的DB给到不同的环境、Redis也使用不同DB、MQ使用不同的vhost等等。这些妥协在真实项目里十分常见,用户的资源总是有限,作架构的我们总是想尽量的保证我们的环境齐全、结构一致,这样才能更好的保证整体的统一、交付质量更高、系统整体的能力更强。这里就不再多说环境对于我们项目的重要性了,后续有机会再进行详细的讨论。

至此,我们的架构基本已经可以支撑后续的工作了,欢迎继续观看后续的文章!

正文到此结束
本文目录