手摸手实战前端项目CI CD

由于图片和格式解析问题,为了更好阅读体验可前往 阅读原文

CI/CD 是 持续集成(Continuous Integration) 和 持续交付/部署(Continuous Delivery/Continuous Deployment) 的缩写,是现代软件开发中的一种自动化方法论,用于加速代码交付和部署的流程,同时保证代码质量和稳定性

大家工作中应该也都接触到了它的方便,如:提交MR、自动打包、自动部署等等,让开发者大大省去了大量的部署时间,从而专注于需求的开发(纯牛马)

那么时间久了你是否对这种方法有过思考,如:这一系列是如何运作的、自己如何搭建尝试呢?对于每位开发者来说都有必要尝试去搭建完整的体系,这样自己对软件落地的整体体系会有更明确的认知。本篇文章将手把手带你完成前端项目从开发到部署的整个过程

小贴士:🎁 文章中涉及到的代码示例你都可以从 这里查看 ,若对你有用还望点赞支持;本篇不适合0️⃣基础小白,需要掌握docker、linux、gitlab、k8s、node等相关知识,如果你对这方面的内容还是空白,可以参考我的往期文章

项目准备

首先在代码管理仓库创建一个项目用来存放项目代码(这里以Gitlab为例),创建fe-cicd

接着创建工程项目,并简单写2个页面;这里本人用CLI助手直接用已有的项目模板来作为演示项目,读者也可以直接使用:执行以下命令很快就会创建好空壳项目模板

# 初始化项目
➜ hengshuai create fe-cicd
HengShuai CLI v0.0.13
? 请选择要创建的模板👇  create a vue project
? 请选择模板类型👀  vue3 admin skeleton with nestjs
? 是否需要自动安装依赖❓ No
🎉 Successfully created project fe-cicd.
👉 Get started with the following commands:➜ cd fe-cicd
➜ pnpm install

将本地项目推送到代码仓库

git add .
git cm -m '初始化'
git remote add gitlab http://192.168.10.10/learn/fe-cicd.git
git push origin dev

以上步骤比较简单,我们搞完后就可以在仓库里看到项目代码了:

打包测试

对于一个新项目在真正部署前一般我们都会在本地执行打包脚本先验证下是否可以跑的通,执行以下命令:

pnpm run build
pnpm run start

查看运行结果:项目正常运行了

CI准备

跑流水线最重要的还是ci的配置脚本,通过ci脚本我们可以精确控制流水线如何执行,因此配置好ci是关键

注册Runner

在写ci配置前要确保已经准备好了gitlab runner,它主要来执行ci的,如果你对runner还是很陌生话请先参考我的往期文章;这里在项目中已经启用了准备好的runner,使用标签是testing;runner的标签名在注册时就可以确定,建议使用有意义的命名规则

一个项目可以使用的多个runner,在ci中体现就是:每个阶段都可以使用不同的runner,或者同阶段的并行任务使用不同runner也可以加速流程,各位视机器配置自行决定

编写gitlab ci

本次项目使用Gitlab CI 进行来执行流水线工作,因此我们在项目根目录下创建新建.gitlab-ci.yml

::: warning 温馨提示
如果你对gitlab ci的配置文件不是很熟悉,可以参考我的往期文章并结合官方文档,本篇以主要流程为主不做很详细的配置介绍
:::

这里我们将流水线分4个阶段:

  • install:安装依赖
  • build:项目构建
  • deploy:项目部署
  • notice:消息通知,消息通知又分为成功和失败

根据以上划分可以简单写出下面这些内容:

image: node:18-alpinevariables:IMAGE_TAG: $CI_PROJECT_NAME:$CI_COMMIT_REF_NAMEstages:- install_deps- build- deploy- noticeinstall_dependencies:stage: install_depsonly:- devtags:- testingcache:key:files:- pnpm-lock.yamlpaths:- node_modulesartifacts:expire_in: "30" #30spaths:- node_modulesscript:- echo "Installing dependencies..."- sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories- apk update && apk add git && apk add openssh-client- npm config set registry https://registry.npmmirror.com/- npm install -g pnpm- pnpm install- echo "Dependencies installed successfully!"build_project:stage: buildonly:- devtags:- testingartifacts:expire_in: "30"paths:- distneeds:- install_dependenciesscript:- echo "Building project..."- pnpm builddeploy_project:stage: deployonly:- devtags:- testingneeds:- build_projectscript:- echo "Deploying project..."- echo "success"# 流水线成功消息
notice_success:stage: noticeonly:- devtags:- testingneeds:- deploy_projectwhen: on_successscript:- echo "success"# 流水线失败消息
notice_failure:stage: noticeonly:- devtags:- testingneeds:- deploy_projectwhen: on_failurescript:- echo "failure"

以上流水线管道在GitLab上的可视化效果如下:

按分支执行

通常项目开发会分为好几个环节如:beta、testing、prod等等,不同环境的可能会有不同的权限,不同环境的runner可能也不一样,因此在ci脚本中就可以真不同环境来区分哪些阶段的流程

假设以下的消息通知,让它只在dev、testing环境下执行,那么就可以通过only关键字来明确指出:

notice_success:stage: noticeonly:- dev- testingtags:- testingscript:- echo "success"

自动化测试

团队中一般对于基建项目会很严格,出一点错误可能就会影响到成百上千的项目。所以通常都会在发布前做相关的自动化测试保证最基本的测试用例不会受到影响,只有这样才能把握住代码的质量;而在ci中我们也可以把它集成进来,在流水线时通过跑自动化测试根据结果来决定是否可以继续执行下去了

本次通过Vitest来演示单元测试,你可以通过其他的工具(如:Jest、Cypress)附加测试功能;先创建一个简单的测试用例:

// __test__/unit/demo.spec.ts
import { describe, expect, it } from "vitest";describe("Test Demo", () => {it("should pass", () => {expect(true).toBe(true);});
});

新增测试npm脚本:

{"scripts": {"test:unit": "vitest run"}
}

读者先在本地运行看能否跑通,避免在ci中增加未知问题

增加测试脚本后,我们需要把它集成到ci中;在ci中增加一个testing阶段用来跑测试用例

stages:- testing # 新增测试阶段testing_project:stage: testingtags:- testingneeds:- install_dependenciesscript:- echo "Testing project..."- pnpm run test:unit

以上只是简单的将测试放入了ci管道,如果你对测试数据比较感兴趣,如:代码覆盖率、代码质量等等,可以参考Test coverage文档、Code quality文档

打包镜像

以上我们就对流水线的上半部分的工作就基本做完了,接下来就是打包应用并发布了,这也是很关键的一个步骤;本篇只做云原生应用的部署,如果你还没有涉及到容器相关的技术,这里不做相关的介绍

容器最关键的就是镜像,对于应用来说可以通过Dockerfile来创建镜像文件,下面是简单的一个例子:

FROM node:18.19.0-alpine3.19WORKDIR /app# 直接从ci打包阶段拿到产物
COPY dist dist
COPY node_modules node_modules
COPY ecosystem.config.js ecosystem.config.jsRUN npm install pm2 -g --registry=https://registry.npmmirror.com/ENTRYPOINT ["pm2-runtime", "start", "ecosystem.config.js", "--env", "production"]

你可以能对上面的docker镜像文件有疑问❓可能觉得他太少了,最基本的项目打包脚本都没有哪来的构建产物;这里我们可以理解为在流水线的流程中在打包阶段将产物保存,然后在构建镜像时直接用就行而不需要在docker中再次构建,这样就省去了大量的时间(更过可以参考gitlab官方文档)

当然docker最终跑的脚本是通过pm2来维护的,我们还需要编写个pm2的配置文件:

// https://pm2.keymetrics.io/docs/usage/quick-start/
module.exports = {apps: [{name: "fe-cicd",script: "dist/server/main.js",watch: false,instance: 2,autorestart: true,max_memory_restart: "1G",env: {NODE_ENV: "development",},env_production: {NODE_ENV: "production",},},],
}

这里使用kaniko来构建镜像:

build_image:stage: buildneeds:- build_projectimage:name: gcr.io/kaniko-project/executor:debugentrypoint: [""]only:- devtags:- testingscript:- echo "Deploying project..."- for var in ${PROJECT_ENV_VARIABLE// / }; do echo $var >> .env;done- mkdir -p /kaniko/.docker- echo "{\"auths\":{\"${DOCKER_REPO}\":{\"username\":\"${DOCKER_REGISTRY_USER}\",\"password\":\"${DOCKER_REGISTRY_PASSWORD}\"}}}" > /kaniko/.docker/config.json- /kaniko/executor--context "${CI_PROJECT_DIR}"--dockerfile "${CI_PROJECT_DIR}/Dockerfile"--destination "$DOCKER_REPO/$IMAGE_TAG"rules:- if: $CI_COMMIT_TAG

以上构建镜像后会把它推送到容器的仓库中心,细心的读者已经发现我们在,我们在build阶段新增了镜像的构建,因此以下为整体的流程呈现效果

部署应用

在流水线中docker镜像构建好后,就可以把镜像推到镜像仓库了(通常公司都会有自己的私有仓库),然后通过k8s拉取最新镜像自动部署了,这就是部署的基本流程

deploy_to_k8s:stage: deployimage: bitnami/kubectl:latestonly:- devtags:- testingneeds:- build_imagebefore_script:- echo "Setting up kubectl"- mkdir -p ~/.kube- echo "$KUBE_CONFIG" > ~/.kube/configscript:- echo "Updating Kubernetes deployment"- kubectl set image deployment/$K8S_DEPLOYMENT_NAME $K8S_CONTAINER_NAME=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA --namespace=$K8S_NAMESPACE- kubectl rollout status deployment/$K8S_DEPLOYMENT_NAME --namespace=$K8S_NAMESPACE

消息通知

等k8s镜像部署阶段完成后代表整个流程就结束了,因此我们可以在流水线的尾部在增加一个通知阶段,通过发送具体的消息来来告知我们的开发人员,当然流水线的执行状态有成功失败2中状态,根据不同的状态来告知

你可以通过HTTP请求将信息发送到消息服务中心,消息中心可以集成到公司用到的应用,这样就会一触即达

消息通知阶段的流水线以上已经展示过了,这里就不再写了,稍微补充下用到的基础镜像:

notice_success:# 通过curl来发送消息image: curlimages/curl:7.80.0# 以下内容自行发挥

执行机制

通常流水线的执行时机都是通过固定的事件触发的,如:分支合并、分支push等等,而对于重要的环境往往需要手动来降低风险,或者说可以更好的决定执行时机;对于一个复杂应用的发布,可能会涉及到很多基础服务的发布,那么对于自动化发布来说会很麻烦,这里简单提一下如何修改执行时机

deploy-job:stage: deployscript:- echo "Deploying the application"when: manual   # 配置为手动触发

在往期的文章中都有关于执行时机的介绍,这里只是提醒下如何更好的实践

心跳检测

大多数的应用都会面对很多问题,如:负载、故障等等;而稳定的应用都会有很多监控措施,对于镜像如何检测它是否正常运行呢,最简单的就是通过写一个检测接口,通过一定的频率来调用,根据响应来判断是否正常,这样在镜像拉胯时,可以重新部署

下面我们用NodeJS简单写了一个接口/common/health-check

@Controller("/common")
export class CommonController {// 心跳检测@Get("/health-check")healthCheck() {return "ok";}
}

接着在k8s pod配置文件中添加心跳检测

apiVersion: v1
kind: Pod
metadata:labels:test: livenessname: liveness-http
spec:containers:- name: livenessimage: registry.k8s.io/e2e-test-images/agnhost:2.40args:- livenesslivenessProbe:httpGet:path: /common/health-checkport: 8080initialDelaySeconds: 3periodSeconds: 3

更多玩法请参考探针检测

其他

纯静态前端项目,大部分会配合nginx使用,这里不做演示

线上的应用运行效果如何(内存、负载、响应等等),通常都会在相关的监控后台查看,可以参考k8s可视化资源监控,也可以根据api自行设计监控后台

由于图片和格式解析问题,为了更好阅读体验可前往 阅读原文

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/2618.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【EI 会议征稿通知】第七届机器人与智能制造技术国际会议 (ISRIMT 2025)

第七届机器人与智能制造技术国际会议 (ISRIMT 2025) 2025 7th International Symposium on Robotics & Intelligent Manufacturing Technology 会议主要围绕“机器人”、“智能制造技术” 等研究领域展开讨论,旨在为机器人与智能制造技术等领域的专家学者、工…

【Linux】信号

目录 一、信号的概念二、信号的产生2.1 通过键盘进行信号的产生2.2 通过系统调用进行信号的产生2.2.1 kill函数2.2.2 raise函数2.2.3 abort函数 2.3 通过异常的方式进行信号的产生2.4 通过软件条件的方式进行信号的产生2.4.1 关闭管道读端2.4.2 alarm函数 2.5 Core Dump&#x…

基于go语言的驾考系统设计与实现

在Internet时代,Internet信息技术已广泛应用于各个领域。 对人们的生活以及学习产生了较大的影响。通过信息技术建立的驾照考试管理系统,利用系统对驾照考试进行统一的管理,能够提驾照考试管理的工作效率,具有重要的现实意义。 本…

鸿蒙打包发布

HarmonyOS应用/元服务发布(打包发布) https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-publish-app-V13?catalogVersionV13 密钥:包含非对称加密中使用的公钥和私钥,存储在密钥库文件中,格式…

基于Linux系统指令使用详细解析

一 Linux系统常用操作命令编辑快捷 1.1终端快捷键: Ctrl a/Home 切换到命令行开始 Ctrl e/End 切换到命令行末尾 Ctrl l 清除屏幕内容,效果等同于 clear Ctrl u 清除剪切光标之前的内容 Ctrl k 剪切清除光标之后的内容 Ctrl y 粘贴刚才所删…

深度学习-87-大模型训练之预训练和微调所用的数据样式

文章目录 1 大模型训练的阶段1.1 预训练1.1.1 全量预训练1.1.2 二次预训练1.2 微调2 预训练需要的数据2.1 清洗成的文本文档2.2 如何从文本文档学习2.3 常见预训练中文语料库3 微调需要的数据3.1 微调例子一:电商客服场景3.2 微调例子二:行政咨询场景3.3 微调数据长什么样3.3…

基于 STM32 的多功能时间管理器项目

引言 在快节奏的生活中,时间管理显得尤为重要。本项目旨在通过 STM32 开发一个多功能时间管理器,功能包括计时器、闹钟和日历。用户可以方便地设置不同的提醒和计时任务,以更好地管理日常生活和工作。 项目名称 多功能时间管理器 环境准备 …

麦田物语学习笔记:代码链接UI实现时间日期对应转换

基本流程 时间系统UI如下 本篇文章将UI和TimeManager里的数据联系在一起, 1.代码思路 (1)新建TimeUI.cs挂载在GameTime物体上,然后获取它的子物体这些组件来改变里面的数值,所以需要获得Day & Night的子物体Image中的Rect Transform,用于旋转季节的图标;获得Clock每个子物…

HTML文章翻页功能

效果展示&#xff1a; 效果原理&#xff1a; 1、引入CDN 2、绘制文章翻页样式&#xff0c;以及自动分段 3、获取窗口宽高&#xff0c;计算出当前文章总分段&#xff0c;并实现分页 4、完整代码 <!DOCTYPE html> <html><head><meta charset"utf-8&qu…

深度学习电影推荐-CNN算法

文章目录 前言视频演示效果1.数据集环境配置安装教程与资源说明1.1 ML-1M 数据集概述1.1.1数据集内容1.1.2. 数据集规模1.1.3. 数据特点1.1.4. 文件格式1.1.5. 应用场景 2.模型架构3.推荐实现3.1 用户数据3.2 电影数据3.3 评分数据3.4 数据预处理3.5实现数据预处理3.6 加载数据…

代理模式实现

一、概念&#xff1a;代理模式属于结构型设计模式。客户端不能直接访问一个对象&#xff0c;可以通过代理的第三者来间接访问该对象&#xff0c;代理对象控制着对于原对象的访问&#xff0c;并允许在客户端访问对象的前后进行一些扩展和处理&#xff1b;这种设置模式称为代理模…

2024年11月架构设计师综合知识真题回顾,附参考答案、解析及所涉知识点(一)

软考高级系统架构设计师考试包含三个科目&#xff1a;信息系统综合知识、系统架构设计案例分析和系统架构设计论文。考试形式为机考。本文主要回顾2024年下半年(2024-11-10)系统架构设计师考试上午综合知识科目的选择题&#xff0c;同时附带参考答案、解析和所涉知识点。 由于机…

【Kafka】Linux+KRaft集群部署指南

【Kafka】LinuxKRaft集群部署指南 摘要本地环境说明官网准备工作快速开始修改config/kraft/server.properties初始化数据存储目录 新节点加入集群启动停止测试创建topic创建生产者创建消费者 摘要 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在…

【GIS操作】使用ArcGIS Pro进行海图的地理配准(附:墨卡托投影对比解析)

文章目录 一、应用场景二、墨卡托投影1、知识点2、Arcgis中的坐标系选择 三、操作步骤1、数据转换2、数据加载3、栅格投影4、地理配准 一、应用场景 地理配准是数字化之前必须进行的一项工作。扫描得到的地图数据通常不包含空间参考信息&#xff0c;需要通过具有较高位置精度的…

计算机网络 (45)动态主机配置协议DHCP

前言 计算机网络中的动态主机配置协议&#xff08;DHCP&#xff0c;Dynamic Host Configuration Protocol&#xff09;是一种网络管理协议&#xff0c;主要用于自动分配IP地址和其他网络配置参数给连接到网络的设备。 一、基本概念 定义&#xff1a;DHCP是一种网络协议&#xf…

自动驾驶3D目标检测综述(八)

在介绍完前九章的内容后&#xff0c;咱们已经基本完成了综述主题内容的解读。剩下只有第十章分析和展望以及第十一章总结的部分。本篇为自动驾驶3D目标检测综述的第八篇也将是最后一篇。 目录 1、研究趋势 1.1 数据选择的趋势 1.2 推理时间的趋势 1.3 基于激光雷达方法的趋…

Web3 时代,区块链与物联网的融合创新前景

随着Web3时代的到来&#xff0c;区块链技术和物联网&#xff08;IoT&#xff09;的融合成为科技领域的一个热点话题。Web3以去中心化为核心理念&#xff0c;而区块链正是这一理念的技术支撑。物联网则通过智能设备和传感器将现实世界的数据数字化&#xff0c;连接成一个庞大的网…

【JavaEE进阶】SpringMVC 响应

目录 &#x1f38d;前言 &#x1f333; 返回静态页面 &#x1f332;RestController 与 Controller 的关联和区别 &#x1f334;返回数据 ResponseBody &#x1f38b;返回HTML代码片段 &#x1f343;返回JSON &#x1f340;设置状态码 &#x1f384;设置Header &#x…

RV1126+FFMPEG推流项目(7)AI音频模块编码流程

一、AI 模块和外设麦克风的关系 AI 模块是 RV1126 芯片的一个重要组成部分。它的主要功能是将外部接入的麦克风采集到的模拟信号通过内置的驱动程序转换为数字信号。这意味着麦克风作为外设&#xff0c;提供音频输入信号&#xff0c;AI 模块通过其硬件和软件的结合&#xff0c…

4.Proto 3 语法详解

目录 proto 3 语法详解字段规则消息类型的定义与使用创建通讯录2.0版本enum类型升级通讯录至2.1版本Any类型升级通讯录至2.2版本oneof类型升级通讯录至2.3版本map类型升级通讯录至2.4版本默认值更新消息保留字段reserved创建通讯录3.0版本未知字段升级通讯录3.1版本前后兼容性选…