2

前不久,Answer.dev 开发团队受到华东师范大学 CS4ALL 研究中心邀请,为在读硕士的同学们进行了一次分享,以 Answer.dev 项目开发过程为例,与同学们探讨了项目研发管理、开发流程、DevOps 等相关话题。以下为 Answer.dev 两位核心开发者 @Joyqi 和 @明城 在本次课程上的分享实录。今天是我们的第四次 DevOps 学习班,大家知道在 2022 年 10 月 24 日, SegmentFault 思否团队,正式对外开源了其问答社区软件“ Answer.dev”。 这几天,登上了 GitHub 的 Trending 总榜单和 Go 语言榜首的位置。

图片

那么,今天我们就非常荣幸的邀请到了Answer.dev 团队的老师们。祁宁和明城(吕峰军)老师来给大家介绍一下如何通过 Answer.dev 产品来构建 Q&A 社区以及 Answer.dev 研发、软件研发的管理和流程。

有关祁宁和明城老师的介绍,之前在 GitHub 的 issue 里面已经有详细的介绍,这里就不再这里多讲,那现在就把话筒交给 Answer.dev 团队的老师们,我们正式开始!


Hello 大家好,我是祁宁,我旁边是明城,今天由我和他来跟大家分享。我会先讲我们项目整个研发的情况,然后明城会具体介绍 Answer.dev 项目的技术细节及实施情况。

我先自我介绍一下,我是祁宁,我的社区 ID 是 @Joyqi,在社交网站及 GitHub 上都可以搜到我。我是 SegmentFault 思否的 CTO ,自己也做开源,且有很长时间了,大学期间就已经开始做开源项目。明城是在大学时就跟我一起合作做开源项目,我们很早就认识了,所以很早就开始进入开源的世界。

Answer.dev 这个项目是我们第一次以公司商业的实体来进行推进的开源项目,跟我们之前以个人兴趣为主去推进有所不同。之前的项目规划可能是以个人时间为主,但现在可能会以公司的一些关键节点为主。关于 Answer.dev 项目,大家如果想具体了解的话,可以登陆官方网站 answer.dev 查看详细,它最近在 GitHub 上很受关注,我们后面也会持续更新。

项目目标

我先来介绍一下 Answer.dev 项目的研发过程,项目在开发的时候就定下了一些目标。

图片

首先,最简单的一点就是该项目要非常易用我们的目标是让非专业人士或非程序员们也可以非常简单地在我们的指导下或在文档的帮助下把这个项目给运行起来。我们知道,目前市面上其实有很多社区软件或开源产品,但它们在运行的时候都需要一些很专业的知识,比如配置、技术名词等。但在 Answer.dev  项目中,我们想面向的是一个更广大的人群,所以在产品设计及文档设计之初,我们就会更多的考虑到了如果你是一个非专业人士,如何很好地上手这个项目。

第二,Answer.dev  是一款开源软件。我们之前做互联网产品的创业,可能只会发布一个最终的产品,直接给用户用,或发布给特定商业用户。而开源项目的话,就会把该项目的直接源代码给开放出来,让所有程序员都可以看到源代码,然后可以来参与到我们项目中。

第三,在设计之初就考虑到它是一个国际化的项目。大家如果访问过我们的官方网站或官方 GitHub 账户,你就能看到所有语言是全英文的,我们以国际化标准来开发这个项目,包括后续的文档以及在代码中的注释都是按照国际化的标准来进行,其目的是希望它的受众足够广,希望各个国家的程序员都可以以同样的标准参与到项目中来,而不是单单只面向中文的用户和开发者。

第四,我们需要这个项目在发布的时候是一个可用的状态,这也是我们发布的目标。刚刚主持人也说了,我们在 1024 的时候发布这个项目,发布时就是可用的状态,是可以 run 的、可执行程序,而非半成品代码。这是我们项目开发之初就定下的项目目标。

项目挑战

项目在开发之前,我们就把项目可能遇到了一些挑战给列了出来,让开发的团队心里有数,有些挑战是我们在开发中才总结出来的。

图片

第一个挑战,就是时间周期很短。其实之前讨论过很长时间要去做这个项目,但项目正式立项是在今年的 5 月份,然后 6 月初才启动。如果要在 1024 发布的话, 9 月底就必须得交付内部预览版,所以该项目的开发实际上只有三个月不到,时间其实是非常紧的。从 0 开发一个项目,会经历产品设计阶段、技术的选型以及一些磨合,其实过程非常复杂,所以时间是我们遇到的最大挑战。

后面我们也遇到了一些技术上的挑战,该项目是我们第一次用 Go 开发的大型的、开源的、Web 项目,所以对代码质量要求特别高的我们在开发过程中也遇到了一些挑战和困难,但都很好的解决了,当然现在还有一些没有解决的也在解决中,因为开源就是一个不断完善的过程。

第二,它是一个全新的交互环境,之前我们交付的内容都是用户端产品或给 B 端或商业用户用的产品,交付给让他们使用就可以了。但现在我们交互的是代码,代码本身也是我们产品的一部分,包括代码是否标准,接口是否完善,文档包括它的国际化等。在我们之前做项目的时候是不用考虑的,只需要考虑该项目是否可以 run ,用户用的时候没有bug ,这就可以了。但如果是开源项目的话,那代码的标准程度,它的测试,以及接口设置是否合理,命名是否规范,都特别有挑战性。跟我们之前很多开发者本身的编程习惯是相悖的。因此在这中间,我们也跟着项目建立了自己的很多编程标准,也建立起来一套我们自己的代码规范,也是随着这个开源项目开发不断完善。

第三,互联网产品的特性,即产品是随时调整的。以前在做互联网开发时,我们也经常遇到这个问题,开发时该产品的需求会有变化,要随时调整,所以与普通的软件项目交付有所不同。

项目开发流程

软件项目的开发流程通常是:我们需求讨论确定,然后写具体的产品说明书,之后就可以交付开发。按照该产品说明书的标准开发,最后交付时一条条校对,确保是否达到标准。但是对互联网产品而言,开发过程中可能会遇到产品调整,此时可能需要持续集成,需要不断交付新产品,这也是互联网开发的一个特点

图片

在这个项目中,我们就遇到了一些需要调整的问题,尽管并非频繁调整,但依旧调整了很多,有些增加,有些删掉,这是持续集成的过程。该项目流程是个比较普遍的流程,与一般产品相差无几,经过需求的设计讨论后会得出产品原型,之后再进行讨论,原型是否合理,如合理或拍板定型后,会给出相对固定的、正式的产品设计或详细说明。据以往的开发流程,此时研发队伍已可按照该产品说明做项目研发,一般先是交付测试,然后再交付就可以。但对我们来说的话,在研发的过程中会不断的修改,产品也在不断调整的过程,不以最后产品交付为主,而是中间设置很多节点持续交付节点。按照该特点,对产品的交付流程做改进

图片

首先,将功能模块全部按功能拆分,然后变成一个个子任务。右边可以看到我们的研发管理工具—— ONES ,通过该工具把项目做整理,提取其中一些功能模块,先拆功能模块,再将功能模块按任务拆分成子任务一项项落实,最后再监听其工时及完成情况。

我们会按周来设立里程碑——将周设为持续交付的节点,每个节点将这些功能模块交付,下一周就会有调整。如果本周功能模块最终验证完成,那这一周的任务就完成了,还可看交付的百分比进度。我们每周会做定期检视,会看这周交付的内容有哪些问题,是否需要调整,然后将其做调整,再交到下一周的任务中去,这可能是个持续迭代的过程。

当然,每周任务进行时,我们会有一个总目标,以保证如期完成。必须紧盯总目标,才不会在每周执行时逐渐迷失、将总目标丢失,或做成了另外的项目,这是不允许的。因此在任务排期或任务分配时,会以总目标为最高优先级来安排工作

图片

这是我们项目管理的整个预览,项目开发的启动为第一周,第二周是正式开始开发,每周都是一个节点。可以看到第 11 周的最终节点,1024 的前夜就是第 11 周,该任务开发阶段的任务即终结。后面会进入产品迭代的过程。

图片

DevOps 要求从开发到项目,从项目管理最开始到任务分配,从产品端到交互再到运维端,全程需要开发者掌控,因此需要一系列工具的支持,也得益于近些年这些工具的发展,才有了 DevOps 概念。如果没有这种工具,开发者接触 OPS 端会很难上手,因为可能需要训练 Linux 或服务器相关运维知识。但现在,有了这些工具,将工作都用代码抽象了出来。对开发者而言,只是编了另一段代码,再监控这些任务的运行状态,就可以完成工作。

我们在做全状态全链路管理时,用了这些工具。最开始是用 ONES 来做项目管理,我们所有代码管理放在 GitLab 上,即内部私有仓库,然后持续集成。这些代码的测试和打包、交付都放在 GitLab 本身的 CI/CD 工具,以上是我们的选择。

如果大家对此感兴趣,业界肯定会有类似的选择,比如使用 GitHub 来做代码管理,当然还可以用 drone 或 GitHub 的 Actions 来做持续集成。这是个自动化工具,它会有一些特殊的语法。由于现在 K8S 容器管理平台的出现,极大的方便了程序员最后的交付。以往要交付一个产品,部署之后会很麻烦,需要专业运维人员在不同环境配置、部署代码,需要很多专业知识。但现在有容器,后面还有 Docker、Docker 管理工具等,将交付或部署流程给代码化抽象了出来。现在,Developer 可以做很多 OPS 工作,这也是我们做 DevOps 的保证。

DevOps 的实施

因为有了这些前置条件,它保证了 DevOps 的实施可以顺利进行。之前提到,正如 Kubernetes 抽象了很多的硬件资源,然后 CI/CD 工具又将 OPS 的流程语义化。对开发者而言,写代码是一件很直观的事情,能把它抽象,就可以做 OPS 。

这对工程师来说也有一些改变,因为他们之前交付的结果可能仅仅是一个代码或测试完成的代码。但是现在工程师最终的交付结果直接是一个可以在线上运行的容器,或者你可以认为它是一个App,它可以监控这个交付的过程,最后是否成功。这样就可以把它最终交付的链路拉长,之前他无法介入的东西他现在也可以自己去调整,包括你的容器、需要的资源都可以自己去调配。

图片

右边是做 CI/CD 的工具流图形化展示,我们现在用 GitLab 来做 CI/CD,可将 CI/CD 流程以图形化的形式展现出来,先编码,然后流程化展现。这里可以看到,CI/CD 几个典型的工作流,比如在代码 push 到代码管理平台给 GitLab 后,它会做代码风格、单元测试并行检查,都通过后才会到下一步可以部署的阶段,此时就由开发者自己选择部署到哪个平台。

比如我们 SegmentFault 分了三个平台,一个是 test 平台,即测试平台,还有 product 正式线上发布的平台和老平台。开发者可以选择执行下一个操作,以 trigger 另一个持续集成的步骤,专门用来上线的地方就可以检测上线是否成功。如果不成功,会将原因告诉你;如果成功,也会很直观的显示出一个绿色的勾,这样开发者就可以知道从它的代码发布到最终上线,是否符合我们的平台的标准。

这是我们的 Answer.dev 项目,包括项目管理、以及 DevOps 实施的一些情况。现在我把它交给明城,他来介绍一下我们 Answer.dev 项目的一些具体情况

Answer.dev 是如何安装部署的

同学们大家好,我主要介绍一下 Answer.dev 是如何安装部署的,并从工程化及技术角度介绍该项目的一些基本情况。

图片

这是 Answer.dev 项目在部署之前需要的一些具体的系统需求,我大概列了三点:

1. Linux 环境,其实 Answer.dev 项目是用 Mac OS 开发的,本身就支持在 Linux 和 Mac 上都可运行,但在实际的生产环境里,会以 Linux 是为主。

  1. 对应多个环境就需要容器化,包括清理。刚才提到,我们有 K8S 环境都可以运行。如果需要编译,那可能会需要增加对应的开发环境,前后端都需要
  2. 有关数据库方面的支持,其实我们在开发之初我们就考虑到了多数据库的支持。因此 MySQL、SQLite、以及 Postgress 都是可以使用并被支持的,但是一般来说推荐同学们使用 MySQL 以及 SQLite,因为它们更加得通用。

图片

具体部署方面,有两种方式:一种是用 Docker ,这是我们比较熟悉的容器环境;另一种是裸机部署,直接通过命令行启动。

Answer.dev 项目采用的是前后端分离的方案,前端使用的是 React 技术栈,同时后端是使用 Golang 编写。同时,我们编译生成的 Golang 可执行程序中,嵌入了所有 React 框架生成的静态资源文件。但是,我们因为服务器环境不一致,可能会造成 Answer.dev 运行的用户权限不一样,有些是普通用户、有些是管理员,所以可能会造成资源访问的权限不同,例如能否读取和写入本地指定目录的权限等等。所以,从部署角度上讲,我们可以使用单个可执行文件即可运行起完整的 Answer.dev 项目。不过推荐使用容器化环境运行 Answer.dev 项目,这样子可以统一运行环境、以及实现程序和数据方面的隔离。

希望大家能够通过我们官网的一些文档及安装步骤,自己一步步 run 起来,这样对于大家而言会有更加直观的认识。

https://answer.dev/docs/quick... https://answer.dev/docs/Installation/binary https://answer.dev/docs/Insta...

图片

现在屏幕展示的是命令行窗口:如果我们通过 Docker 去部署的话,我们官方已经写好对应的 docker compose 文件。所以,我们很轻松得久可以使用一行命令启动和部署 answer 应用。下面,我们简单了解下 docker compose 其中的文件内容:answer-data 是 Docker 其中一个卷,也可以是本地目录,映射到容器里面做持久化。然后,默认的数据库配置可以是 SQLite 也可以是 MySQL,这里对应的启动了个 MySQL 的容易用于存储 Answer.dev 的数据和配置。(注:后期新版本的 answer 使用了 SQLite 作为默认的本地数据库)。然后,默认不用任何的操作,就可以 init 成功了,我们刷新一下浏览器,然后就可以看到界面 Answer.dev 项目就起来了。

以上,我们可以更直观的 了解到 Answer.dev 整个项目的构成以及它具体是怎么运行起来的。

编译和构建 Answer.dev

图片

Answer.dev 项目本身分成了两个比较大的项目——前端、后端。前端用 React 编写,后端用 Golang 编写,是比较典型的前后端分离的项目。

那么如何同时构建前后端两个项目?我们用了 Makefile ,这里打开一个脚本 Makefile,大家有兴趣的话可以上 GitHub 登陆我们 Answer.dev 主页,Makefile 就在我们主页的根目录。

简单说一下,不要求大家能看懂,了解我们是如何构建的。 简单的说,这边会有一个 npm 然后 install ,把前端的依赖包打完扔给后端、后端会把前端的产出,即静态的 CSS、HTML 文件转到 Golang 里,然后就编译完成了。此时,会有一个二进制的文件,从部署角度上讲是完整的,因为我们有一个可执行的二进制文件可以把它运行起来。

如同学们所见,我们多了一个文件叫 answer,此时我们直接运行起来,就这么简单。以前在课程里也都能用到,比如如何编译、如何打包程序,如何打成镜像,到各种各样的多容器环境或 Kubernetes 环境里,这里就要用到 Dockfile 了。

我们多个方案其实也跟 Makefile  相似,先调 node 打包前端,然后 stage 2 调 Golang ,用 Golang 的镜像去打包 Golang  的环境,然后再将 node 产生的 Answer.dev HTML 跟 GS 静态文件打到共创的二进制包里,再扔到容器的一个环节里去运行,同时设置入口即可。

正如刚才 @Joyqi 所说,我们可以通过 GitHub Action 或 GitLab CI/CD 执行自动化操作,开发者本身无需关心部署及打包过程,因为过程非常费时费力,且非常容易分心,开发者可以更加专注于自己开发的内容上。

https://answer.dev/
https://github.com/answerdev/...
https://twitter.com/AnswerDev

这是我们的官网主页,包括我们 GitHub 主页及我们在 Twitter 的官方账号,可以随时与我们互动。大家就有哪些疑问或问题可以直接提出来。


ApacheAnswer
101 声望39 粉丝

开源问答社区软件 Answer.dev 官方账号