白话 Github Action(一)

2,434 阅读11分钟

其实我相信很多同学刚开始接触 github action 的时候对于网上很多教程都是:能看完,但是记不住的状态。特别是那些上来就把各种常用属性列举一遍,然后下面直接放例子的。我要是能直接记住这些属性配置项,那我直接去看官方文档他不香么。

本系列文章将会以大白话的形式来介绍 github action,非常适合零基础的同学阅读。不仅会告诉你 github action 里的知识,还会介绍其背后的目的,以及告诉你如何去完成那些自己想要但是网上又找不到例子的 action。总之一句话:通俗易懂的让你了解 github action,并让你拥有一定的主观能动性,而不是只会 ctrl CV。

这个系列分为三篇文章,将以 nodejs 项目为例介绍 github 里最常用的四个功能:pr 合并校验、github page 发布、npm 发布、github release 发布虽然这些例子网上已经有很多教程了,但是本文会更深入的进行探讨,让你以这些例子为钥匙去进行理解,而不是直接拿去用。

本篇文章则是对于 github action 里最最核心的一些概念的介绍,先给以后的文章打个基础。ok,废话少说,咱们现在开始!

image.png

简单介绍 CI/CD

在开始实践之前呢,我们要先了解一下 github action 的主要用途:CI/CD。

在很久很久之前,一些中小型项目的部署和发布都是很简单的,后台打包好扔到 tomcat,前台打包好扔到 nginx 里。能跑就跑,不能跑再看 log 找问题。这种流程比较简单,一般都是开发人员顺手就搞定了,所以也没什么人说。

但是随着对可靠性要求的逐渐提高,部署平台的日渐升级。导致这个流程越来越复杂,你先记得跑个单测,没问题再跑个集测,有问题自己录一下。没问题在上平台(上服务器),建好版本,灰度发布一下.....得得打住,这种流程你让我临时走一遍还可以,难不成要让我每次发布都来一遍?

image.png

那怎么办呢,写脚本呗,程序员最擅长的就是把没脑子的活交给机器干了。于是各种自动化工具应运而生,比如 java 的 Gradle、js 的 grunt,自动化构建 慢慢出现了,自动化集成让程序员免于重复的执行各种繁琐的代码构建工作,完成了跑测试、构建打包之类的重复性劳动。

后面我们给构建换了个更高端的名字:集成。

解决了一个问题还剩另一个,怎么无脑的部署服务呢?当然还是写脚本,从很久之前的打包复制到服务器,再到容器化,再到 docker swarm 和 k8s,shell 脚本一直默默的发挥着自己的光和热。搞部署的人没几个传家宝 shell 都不好意思说自己部署过服务。

后面我们也给部署换了个更高端的名字:交付。

这种自动化手段完美了承担了程序员的工作量,让大家把注意力重新放回到堆屎山上。但是用着用着就发现...好像还是有点小问题:

  • 复用性问题:相同技术栈的集成和交付流程都是几乎没有区别的,无非就是部署到的地方不一样、有权限的人不一样。但是用上面这种自动化的方式,其脚本都是直接存放在代码仓库和对应的服务器上的。我搞个新项目就要复制一份,如果有问题的话还没办法统一改,搞多了确实有点烦。

  • 一致性问题:针对于代码构建,如何让不同的机器上打包出来的代码表现相同一直是个令无数人头疼的问题。而这种自动化集成一般都是在本地机器上执行命令完成的,称最终结果千人千面也毫不为过。因此也出现了各种新人跑来问老人为啥我电脑上打包跑不通的恼人问题。换个方面说,就算打包跑通了,你怎么就放心里边没有藏着几个小问题,上线之后冷不丁给你一肘子?

  • 安全性问题:针对于部署上线,通过 shell 完成的脚本一般都是只要你能找到脚本,那么对应的平台部署密钥之类的也就不远了。万一有人保存下来,离职的时候给你跑个定时炸弹那就好玩了。如何把这些敏感信息隔离出来,让能执行部署的人能一键干活的同时也不会悄咪咪的拿着这些密钥搞事情呢。

  • 我还是懒:虽然都做成一键自动执行了,但是我还是得本地执行个命令构建,再登陆服务器,再执行个命令部署,你能不搞成,我把代码一提交,啥活都干好了,开发者什么都不用关心,岂不美哉?

小问题越想越大,这可不行,越想越吃不下去饭,那来吧开整。

  • 针对复用性问题,我们进行一些设计,让这些自动化流程变成一个个“函数”然后发布出去,你要想用直接调用就行。

  • 针对一致性问题,我们可以单独搞一台机器,你执行的命令会发给这个机器,让他去完成这个构建任务,这样我们只要保证这个机器的纯洁性。编译出来的结果我就不信还会有什么花活。

  • 针对安全性问题,我们可以设置一层“代理”,这个代理上有很多按钮,对应不同的部署任务,你想发布按按钮就完了,直接把敏感信息给你屏蔽掉。

  • 针对懒的问题:你都说了想提交代码之后自动跑任务,那我跟代码托管平台联动一下呗。

于是乎,这些需求慢慢成长,最终汇总成一个平台,这个平台负责 代码写好之后到发布给用户中间的所有不用动脑子的事情。例如基于 java 的 jenkins、第三方的 Travis CI / CircleCI、整合进软件开发平台的 gitlab CI、atlassian CI/CD,以及我们今天要聊的 github action。

由于这些操作完全自动化了,所以我们干脆把这一套流程 持续化,只要有代码修改,我们就可以针对其跑出对应的结果并发布到对应的环境,这样不仅方便管理,对于回滚之类的操作也更友好。于是乎,我们就把这个不断重复的过程起名为 持续集成、持续交付(Continuous Integration, Continuous Delivery),也就是所谓的 CI / CD。

image.png

设计一个简单的 CI/CD!

好了,知道了什么是 CI/CD,那我们就来更进一步,假如我们是一个程序员,现在要实现一个平台来处理 CICD,那我们应该如何设计来满足上面的这几个需求呢?

首先,既然要做一些事,那最主要的自然是经典的三 W 问题:谁来做?啥时候做?做什么? 好,大笔一挥,我们掏出了下面的流程设计图:

image.png

但是仔细想想,好像有可以优化的地方。比如执行测试,我们有可能需要用到多台机器分别跑一下,来测试不同环境下的运行情况。那么上面这种只指定一个运行机器的方法就不对了。好,我们再次大笔一挥,新的设计出来了:

image.png

emmmmm,好像还可以优化,这里对于具体任务来说,我们没必要完全是线性执行,如果两个任务之前没有依赖关系的话,我们完全可以让他们并行执行啊

哦好像不是所有的任务都能并行执行。这样的话,我们就要给任务上添加一个可选项,来说明这个任务和其他任务之间的依赖关系,比如说构建任务肯定要在所有的测试任务完成之后才能执行。ok,脑子里刚想好,新的设计就已经完成了:

image.png

现在流程貌似没啥问题了,也不是很复杂嘛。欸等等,我们刚才好像还要解决复用性问题来着。不想动脑子了,就按照函数那样来吧,接受一些参数,黑箱执行一些操作,返回执行结果,我看很合适嘛。而且我们完全可以把这种函数当成最小的逻辑单元来用。每个函数就是一个步骤,几个步骤可以组合成一个更大的步骤,通过这种层层组合,最终完成一个任务,真不错!

于是乎,加上最小复用单位“步骤”,我们的 gayhub action v1.0 就设计完成了!

image.png

简单介绍 github action

看到这里,咱们其实已经了解了 github action 的整体架构设计,而上图里的最小单位 “步骤”,就是所谓的 Action。这个概念非常重要,以至于 github 的 CI/CD 就叫做 github action。接下来,我们就带着上面这张图,来了解下 github action。

github action 里的整体流程和上图一模一样,我们接下来要做的事情,其实就是把上面的中文名字换成对应的英文关键字。

首先,我们来看一下 github action 的官方教程给出的介绍图:

image.png

左侧的 event 就是我们的“什么时候做”,而 job 则是我们的“任务”,每个 job 包含多个 step(“步骤”),而一个 step 就对应了一个 action。但是,这里看感觉 step 和 action 是包含关系啊?实际上确实如此,每个 step 上还会有一些自定义属性,比如名字啊、环境变量啊、传递给 action 的参数之类的。


好,现在再来看官方教程给的第二张图片:

image.png

也很通俗易懂对吧,job(任务)是并行的,每个任务都会启动一个 runner 机器来执行。所以,只要带着上面我们辛辛苦苦花了好久才搞出来的设计图,就不会被 github 里种类繁多的关键字弄晕,更不用去记那些规则,什么 job 是异步的 step 是同步的,回想一下上面的图,这些规则自然而然的就能自己推理出来。


流程对应上了,那具体的流程到底怎么写呢?总不能嘴里含根内存条脑子里直接出画面吧。相信不少同学都已经知道了,写 yaml 文件。几乎所有的 CI/CD 平台都支持用 yaml 来配置流程,github action 也不例外。那么,这个 yaml 文件写到哪呢?答案是:自己的代码仓库里。你可能会想:害,这不还是得复制粘贴么。

是也不完全是。

github 提供了两个层级的复用,第一个就是我们刚才提到的 action。如果是 单个项目内的复用 的话,我们可以把对应的 action 逻辑单独写在一个文件里,然后在流程里直接相对路径引用就行。或者如果是想 跨项目引用 的话,我们也可以把 action 放在单独一个代码仓库里,然后在流程里也可以用 actions/xxxx 引用,这时 github 就会自动去搜索对应的代码仓库并运行。

而这里的第二种方式则更为流行,在 github 里数量众多的 action 组成了一个庞大的市场,被称为 GitHub Marketplace · Actions,你想要的绝大多数操作,官方的私人的,都可以在这里被找到,在后面的文章里我们也会介绍几个常用的 action。

image.png

除此之外,为了解决每新建一个项目就要复制粘贴一份 CICD 配置文件的问题。github 还提供了组织级别的复用。你可以在一个组织里创建名为 .github 的仓库,然后在里边开发一些“模板”流程,这样其他同组织的仓库在新建流程的时候就可以直接使用这些模板,具体可以看 与组织共享工作流程 - GitHub Docs

写在最后

到这里差不多就要结束了。本文主要讲了 github action 的基础设计,方便大家理解后续的文章。其中 action 的概念非常重要,github 通过 action 将原本命令式的流程配置封装、分层,形成了一个开放、灵活的工具库。让大家可以轻易的复用,极大的降低了开发成本。

下一篇文章(摸鱼中)里,我们将会用三个示例 pr 合并校验、github page 发布、npm 发布 来讲解如何用 github action 提高编程幸福感。