在 GitLab 中构建 CI/CD 工作流程(Node.js 示例)
目录
什么是管道
在计算领域,流水线是指填充了计算机处理器并行处理的所有指令的逻辑队列。它是存储和排队处理器以有组织的方式同时执行的任务和指令的过程。
这与计算机科学中常规的队列或堆栈数据结构不同。这些数据结构分别采用先进先出 (FIFO) 或后进先出 (LIFO) 方法。这意味着,无论处理元素、指令、文件还是任何其他可任意列出的项目,都遵循“先进先出”或“后进先出”原则。
DevOps 管道
DevOps 是一套将软件开发与 IT 运营相结合的实践。它旨在缩短系统开发生命周期,并提供高质量软件的持续交付。DevOps 与敏捷软件开发相辅相成;DevOps 的许多方面都源自敏捷方法。
因此,如果您计划打造一个“敏捷”的工作环境,就必须建立良好的软件基础和自动化流程,以实现快速的开发和成果。如果一切都手动完成,那么环境就会僵硬、僵化、缓慢,与敏捷截然相反。
什么是 CI/CD?
在软件工程中,CI/CD 或 CICD 是持续集成与持续交付或持续部署的结合实践。CI/CD 通过在应用程序的构建、测试和部署中强制自动化,弥合了开发和运维活动以及团队之间的差距。这最好能缩短开发人员在 IDE 中本地开发项目与在正常生产环境中发布项目之间的差距,无论是在面向客户的公共领域,还是在用于与产品开发生命周期的其他分支(后端/前端/设计/质量保证/测试人员等)一起进行预演的私有领域。
它在我的机器上运行良好 ¯\ (ツ) /¯
我们不仅缩短了开发环境与生产环境之间的差距,还引入了在生产环境中运行的保证。CI/CD 的核心在于我们在模拟生产的环境中运行安装/编译、构建和测试。因此,我们消除了“但它在我的机器上可以运行”这种可能性。
Gitlab 的 CI/CD 流程,其他软件大多采用类似的流程
使用什么 CI/CD 管道软件?
在软件开发生命周期中,有许多选项可用于提供持续交付和集成。一些最流行的 CI/CD 工具包括:
适合该工作的工具是个人偏好,取决于哪些工具适合您的项目、预算、要求、语言、技术等。
从现在开始,我们将重点关注GitLab 的管道。
我们为什么选择 GitLab?
其实,选择并不难。GitLab 是我们默认的版本控制系统 (VCS),它利用 Docker 技术为 CI/CD 流水线提供了丰富的功能。内部 CI/CD 与 VCS 集成的优点在于,流水线本身可以根据开发人员的各种事件触发。流水线本身可以配置为在各种情况下触发特定的代码块。例如,它可以在推送到某个分支时触发,或者通过在提交消息中提供某种特定的触发键来触发,它可以在合并请求时触发,也可以在合并成功时触发,等等。
这种方法允许 DevOps 工程师以其他软件工程师无需思考就能继续他们日常工作流程的方式配置流水线,而完全不关心后台发生的情况。这非常棒,因为现在你只需要一位优秀的工程师来配置和维护它,而团队/组织的其他成员则无需费心学习该技术才能使用它。
它除了作为我们的默认 VCS 并具有高度灵活性之外,还可以托管在本地。这样我们就不用使用 GitLab 的服务器(也称为运行器),而是使用我们自己的服务器。GitLab 的管道只会向您收取其服务器上计算时间的费用,因此我们节省了一些成本。不过,GitLab 确实拥有速度快且相对便宜的服务器(1000 分钟计算只需 10 美元)。对于大公司来说,这将是一个不错的选择,从长远来看,这比配置他们的运行器集群要便宜得多。
Docker技术
Docker 是一组“平台即服务”产品,它们使用操作系统级虚拟化技术,以名为容器的软件包形式交付软件。容器彼此隔离,并捆绑各自的软件、库和配置文件;它们可以通过明确定义的通道相互通信。Docker 容器镜像是一个轻量级、独立且可执行的软件包,其中包含运行应用程序所需的一切:代码、运行时、系统工具、系统库和设置。
Docker 和虚拟机之间的主要区别在于,docker 在其容器虚拟化引擎中运行,而虚拟机虚拟化整个客户操作系统。
本质上,docker 允许您通过预先复制生产环境,然后将其容器化并发布到hub.docker.com来模拟生产环境。需要考虑的重要一点是,您希望保持 docker 镜像尽可能简约,因为它会给使用它的机器带来沉重的负载。您只想容器化您需要使用和测试的服务,例如,对于我们的后端堆栈,我们必须在 Ubuntu 上容器化 PHP 8,并且我们已经将 node、npm 和 composer 添加到容器中。就是这样,瞧!现在您会认为将其他技术运送到同一个容器中是明智之举,例如,使用这个容器来测试前端服务将非常低效。
更好的方法是为每个需要的堆栈使用不同的镜像,否则,容器中就会有未使用的软件。
“是啊,我的电脑和服务器上也有,那怎么办?”
问题是,对于流水线中的每个作业,一旦启动,docker 就会启动一个新的容器并启动它。如果你想要更快,就需要尽可能精简。这意味着后端的镜像上只会包含后端软件,而前端只会启动 node.js 镜像,不包含 PHP 和 composer。将服务分离到不同的容器中将有助于整体加快流水线的速度。
启动时间是使用附加软件的最大开销,但前提是您使用自托管运行器。否则,如果您在 GitLab 服务器上运行流水线,则需要在流水线的每个步骤下载镜像(容器)。如果您的镜像很大,并且包含不需要的软件,则下载和启动的时间都会更长,而且 GitLab 会按处理时间的分钟数收费,这意味着您的效率会降低一倍。
GitLab-ci.yml 文件
使用 YAML 是因为它比 XML 或 JSON 等其他常见数据格式更易于人类读写。此外,大多数编程语言都提供了处理 YAML 的库。想要了解 YAML 文件的语法指南,Google 是最佳选择。
此文件是 GitLab 流水线的主要配置。每当您将此文件添加到项目中时,GitLab 都会在您对项目进行任何更改时检查该文件。在这里,您将定义流水线的流程、作业、阶段、执行内容、执行时间等。默认情况下,它将使用共享的 GitLab 运行器,您每月将获得400 分钟的免费使用时间。
YAML 文件包含各种关键字和控制结构,因此您可以定义执行的内容和时间。script
标签内的作业内容是将在包含应用程序的 Docker 容器内执行的命令。以下是一些最常见的控制结构:
image
- 定义哪个 docker 容器将为给定的作业/管道运行(从hub.docker.com获取)stages
- 定义可对作业进行分组的阶段。阶段按顺序运行(一个接一个),而同一阶段内的作业则并行运行only
- 定义作业何时运行(例如,仅在合并请求时)artifacts
- 定义哪些文件将在不同作业之间共享(因为新容器是按作业初始化的,因此除非使用工件指定,否则内容将丢失)cache
- 定义哪些文件将被保存到服务器以供回顾script
- 定义将在容器内执行的命令(操作系统级命令,例如echo
,,)apt-get install
composer install xy
这些是众多主要控制结构中的一部分,更多信息您可以查看文档。
管道生命周期示例
管道从.gitlab-ci.yml
文件开始。这里我们将分析一个简单的管道配置以及每个步骤的具体内容。我们将考虑以下用于前端项目的管道。
image: node:latest
stages:
- build
- run
# Job's name
first-job:
# Define stage
stage: build
# What to run on the job.
script:
- npm install
artifacts:
paths:
- node_modules
second-job:
stage: run
script:
- npm run start
- node test.js
artifacts:
paths:
- node_modules/
second-job-parallel:
stage: run
script:
- echo "I'm running at the same time as second-job!!!"
可以看到,我们有两个阶段。第一阶段安装模块,并且只有一个作业。如果第一阶段成功完成,第二阶段就会启动,并并行启动两个作业。
推送代码后,GitLab 首先会扫描.gitlab-ci.yml
。如果配置没有限制,则管道将在每次推送、合并请求和合并结果时运行。然后,GitLab 将联系“运行器”,也就是将执行管道的服务器。请注意,如果您只有一个 GitLab 运行器,它们将按照先进先出的原则排队。
一旦服务器响应,它将使用您指定的镜像启动 docker 执行器。在我们的例子中,它是node:latest。如果需要,您可以为每个作业指定不同的镜像。如果服务器已缓存该镜像,它将开始使用它,否则,它必须先下载它。
然后,一旦您的容器准备就绪并启动,您的项目将从您的代码库下载,一旦您被放置到项目根目录,它将开始执行您在scripts
列表中提供的命令。在我们的例子中,它将安装 Node 模块。作业完成后,工件将被上传,以便下一个作业可以将它们下载回容器中。然后清理工作开始,容器关闭。
第二个作业略有不同。它会在项目下载后立即下载工件,这样我们就为编写脚本做好了一切准备。此作业完成后,它会再次上传修改后的工件,以供后续使用。除此之外,它在结构上与第一个作业相同。但命令略有不同,这里以 test.js 为例,我们运行 test.js 来测试应用程序是否正常运行。以下是 test.js 的内容:
console.log('Hello from Node.js!')
console.log(new Date().toUTCString())
console.log('Exiting Node.js...')
这是第二项作业的输出:
最后一个作业与其他作业没有什么不同,它只是向我们证明了两个作业确实可以并行运行。
结论
总结一下这些流水线,我想说,任何一家正规的公司都必须将这些操作固定下来。这样可以避免人为错误,并将单调乏味的任务自动化。一个好的流水线还会将代码部署到临时服务器(公司内部服务器,用于测试、质量保证和协作);但最终所有生产部署都应该通过在文件中设置when
key来手动完成。流水线还可以完成很多其他的事情,例如对应用程序进行基准测试、压力测试等等。我可能会在下一篇博客中介绍这些内容,但在此之前,您认为哪些功能可以打造一个优秀的流水线呢?manual
.gitlab-ci.yml
劳埃德银行欢迎合作伙伴,并接受新项目。如果您想了解更多关于我们的信息,请点击此处。
也别忘了在Instagram和Facebook上关注我们!