11、架构:CI/CD 设计

本章内容是基于 DevOps 体系的精简版本,如果有阅读过之前 DevOps 小册的同学,可以快速掠过。

开局先放一张镇楼图,上图我在行云集团做的通用型 CI/CD 解决方案 ALL IN DOCKER,所有的操作构建与发布过程都在 Docker 中操作。

但很多公司和团队都有自己的基础设施和规范,包括使用不同的构建集成工具和仓库管理工具,比如使用 JenkinsDroneGitLab CIGithub Action 等等三方工具,不同的仓库管理工具如 GitLabGitHubGitee 等。

我们产品的需求开发中会涉及到私有化部署以及个性化定制,所以需要设计一个通用性的 CICD 方案,不能让用户有新的学习成本与额外的使用维护负担,同时我们的发布不仅仅只有前端资源还可以包含服务端。

所以基于 Docker 的通用型方案,依然是我推荐的首选之一。

在这个方案中,我们会尽可能的减少三方构建工具的使用。尽量降低学习与使用的成本,但是 Docker 相关的一些内容还是需要补充的。

一个通用型的 Devops 方案中,需要包含流程管理、持续构建、持续部署等

基于 GitFlow 的流程设计


GitFlow 的核心是通过在项目的不同阶段对 branch 的不同操作包括但不限于 createmargerebase 等来实现一个完整的高效率的工作流程。

  • Production: 这个分支包含最近发布到生产环境的代码,最近发布的 Release,并且只能从其他分支合并,不能在这个分支直接修改,一般将 Matser 作为 Production 分支;
  • Develop: 包含所有要发布到下一个 Release 的代码,这个主要合并于其他分支,比如 Feature 分支;
  • Feature:用来开发一个新的功能,一旦开发完成,合并回 Develop 分支,并进入下一个 Release
  • Release:当需要发布一个新 Release 的时候,基于 Develop 分支创建一个 Release 分支,完成 Release 后,合并到 Master 和 Develop 分支;
  • Hotfix: 当在线上环节发现新的 Bug 时候,需要创建一个 Hotfix 分支, 完成修复后,合并回 Master 和 Develop 分支,所以 Hotfix 的改动会进入下一个 Release

整体的分支管理流程如下图所示

通过服务端来控制整个 GitFlow 流程图如下所示:

服务端需要做的分支管理功能主要如下:

  1. 控制每个分支的版本号;
  2. 处理多分支集成发布的情况;
  3. 防止生产环节发布缺失功能;
  4. 锁定发布分支与发布环境,防止功能冲突。

基于 Docker 的 CICD


Docker 的优势

第一优势跨平台,由于 Docker 的镜像能够提供除了系统内核之外完成的运行环境,所以能在任何系统中都能提供一致的运行环境,这样就不需要考虑不同系统中间兼容性的问题,也就不存在虚拟机在各系统中间的配置不同的情况。

第二优势:就是借助于跨平台的特性,Docker 可以将很多配置复杂的服务端中间件打包成基础镜像提供给开发使用。这样无疑能够大大降低配置成本,开发只需要知道常规的 Docker 相关的命令或者直接运行提供的容器编排脚本就可以搭建出需要使用的服务端环境。同时公共的镜像仓库上已经有很多这种基础镜像,例如 MysqlRedisNode 等等,按需提取即可。

第三优势:这点对于运维同学比较好操作,Docker 能提供快速迁移以及配合 k8s,能够快速的伸缩副本,减少运维的工作成本与负担。

这里简单介绍一下 Docker 相关的内容,学起来其实比想象中简单很多,不用过于抵触,更多的 Docker 相关的细节请移步《工程化专栏》,里面会有比较多关于 Docker 方面的介绍,小册里面就不过多介绍了。

持续构建与部署

为了完成持续构建与部署的功能,我们需要设计一个通用性的构建镜像:

  1. 基础镜像:选择一个适合前端项目的基础镜像,例如 Alpine LinuxLinux 等;
  2. 安装必要的软件:在基础镜像上安装必要的软件,例如构建工具、依赖管理工具、图片服务、上传工具等;
  3. 添加缓存和代理:为了加速构建过程,可以添加缓存和代理。例如使用 npm 的缓存,以避免重复下载相同的软件包,以及借助 Docker 的文件联合系统架构,避免重复构建相同的层,提高构建效率;
  4. 清理冗余文件:构建完成后需要清理不必要的文件,以确保镜像的大小尽可能小。例如安装软件包时下载的缓存文件、日志文件、临时文件等等。

在通用性的构建镜像之上,我们还需要针对各个不同的体系定制不同的业务构建镜像提供给不同的业务使用,所以在设计构建触发的时候需要有使用不同镜像构建的功能。

具体的 Dockerfile 脚本以及其他设计的内容都会放在对应的实战篇进行详细解说。

基于 NestJS 的任务队列与调度

文章最开始的时候提过到了,在这套方案里面我们会尽可能的减少对于三方工具的依赖,在之前的 ALL IN DOCKER 的方案中,是借助了 Jenkins 的任务队列来下发各个构建任务。

当我们不再依赖于 Jenkins 的时候就需要自己来开发任务队列的模块了。

  • 任务队列

bull 是一个基于 Redis 的高性能队列库,用于实现队列功能。@nestjs/bull 是 NestJS 对 bull 的封装,提供了更加便捷的使用方式。

可以使用 @nestjs/bull 中的 @InjectQueue 装饰器来注入队列服务。如下所示:

import { Injectable } from '@nestjs/common';
import { InjectQueue } from '@nestjs/bull';
import { Queue } from 'bull';

@Injectable()
export class EventQueue {
  constructor(@InjectQueue('event') private readonly queue: Queue) {}

  async addJob(jobData: any) {
    await this.queue.add(jobData);
  }

  async processJob(jobHandler: (jobData: any) => void) {
    this.queue.process(async (job) => {
      jobHandler(job.data);
    });
  }

  async getJobCounts() {
    const counts = await this.queue.getJobCounts();
    return {
      waiting: counts.waiting || 0,
      active: counts.active || 0,
      completed: counts.completed || 0,
      failed: counts.failed || 0,
    };
  }
}
  • 任务调度

在低代码产品中我们需要提供定时发布、上下架的功能,而 NestJS 也提供了这样的能力 NestJS Schedule

  1. 创建任务调度器:可以使用 NestJS Schedule 中的 @Cron 装饰器来定义一个任务调度器。如下代码所示,创建了一个每分钟调用一次的任务调度器:
import { Injectable } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';

@Injectable()
export class TaskScheduler {
  @Cron(CronExpression.EVERY_MINUTE)
  handleCron() {
    console.log('Called every minute');
  }
}
  1. 注册任务调度器:使用任务调度器,需要使用 ScheduleModule.forRoot() 方法注册 NestJS Schedule 模块:
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { TaskScheduler } from './schedulers/task.scheduler';

@Module({
  imports: [ScheduleModule.forRoot()],
  providers: [TaskScheduler],
})
export class AppModule {}

在上述的代码中,我们在 providers 数组中添加了 TaskScheduler,并在 imports 数组中注册了 NestJS Schedule 模块。

这里的具体设计细节后续会在对应的服务端开发中展开讲解,因为是设计篇,所以不想放一些示例的内容,这样没有上下文联系,学起来会比较分散。

写在最后


本章主要是介绍了 CI/CD 相关的设计,无论是工程化的专栏还是 Devops 的小册,都对相关的设计做了很多的介绍,所以本章的内容就不做过多介绍,感兴趣的同学可以多看一下,拓展一下相关的知识体系。

但与之前不同的是,这次我们并不打算借助三方工具来减少成本,而是全部自己开发来减少用户的学习与使用成本。

如果你有什么疑问或者更好的建议,欢迎在评论区提出。 👏

11 架构:CI/CD 设计

后续有空的话,会在工程化的专栏里面继续添加一些 Docker 相关的内容,可以随手关注于一下。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

J2EE自定义mvc【框架配置及功能】

目录 一、配置步骤 二、配置框架前三步 导入相应的jar 导入相应的Class 导入xml文件 三、优化基本操作(增删改) 1、基础优化 编写实体类 编写BookDao类 优化BookDao JUnit测试 2、后台优化 3、前端优化 一、配置步骤 将框架打成jar包&…

IDEA使用教程 安装教程

16. Codota 插件 Codota 插件可以根据使用频率优先显示较常用的类和方法。然而,是否使用该插件取决于个人的偏好。有时工具只能作为参考,仍然需要依靠个人记忆来确保准确性。 17. 快速查看类和字段的注释 按下 F2 键可以快速查看某个类或字段的文档注…

从JDK源码级别剖析JVM类加载机制

1 什么是Java虚拟机 一个可执行java字节码的虚拟机进程;跨平台的是java程序,而不是java虚拟机,java虚拟机在各个操作系统是不兼容的,例如windows、linux、mac都需要安装各自版本的虚拟机,java虚拟机通过jdk实现功能。…

【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 文章目录 系列文章目录前言一、所有权(Ownership)1.1.、所有权(Ow…

【MySQL】不就是子查询

前言 今天我们来学习多表查询的下一个模块——子查询,子查询包括了标量子查询、列子查询、行子查询、表子查询,话不多说我们开始学习。 目录 前言 目录 一、子查询 1. 子查询的概念 2. 子查询语法格式 2.1 根据子查询结果不同可以分为:…

flutter聊天界面-Text富文本表情emoji、url、号码展示

flutter聊天界面-Text富文本表情emoji、url、号码展示 Text富文本表情emoji展示,主要通过实现Text.rich展示文本、emoji、自定义表情、URL等 一、Text及TextSpan Text用于显示简单样式文本 TextSpan它代表文本的一个“片段”,不同“片段”可按照不同的…

Matlab画等构造图

clc;clear;close all; data xlsread(TOPBRENT等T0构造.xlsx); x data(:,1) xmax max(x); xmin min(x); y data(:,2) ymax max(y); ymin min(y); z data(:,3); N 45; …

IDEA使用插件绘制UML类图+PlantUML语法讲解

安装 IDEA安装插件 安装完插件记得重启一下IDEA 安装Graphviz(亲测win11可以使用) 安装完插件之后,还需要安装Graphviz才可以渲染图形。 Graphviz安装包下载地址 安装过程很简单,直接双击或者管理员身份运行即可,注…

Docker中部署Redis集群与部署微服务项目的详细过程

目录 一、使用Docker部署的好处二、Docker 与 Kubernetes 对比三、Redis集群部署实战四、Spring Boot项目 打包镜像?小结 一、使用Docker部署的好处 Docker的好处在于:在不同实例上运行相同的容器 Docker的五大优点: 持续部署与测试、多云服务平台支…

微信小程序开发与应用——字体样式设置

要求:设置字体样式。 1、打开微信开发者工具,创建一个小程序,如下: 2、设置小程序的项目名称和路径,并选择开发语言为JavaScript,如下: 3、小程序的主体部分由三个文件组成,且都要…

VS2019+Qt5.15 在线显示百度地图

1.Qt5.15编译程序需要选择mscv2019 Release版本 2.需要到百度地图开发平台注册并获取到开发者key 3.显示地图是JS与Qt的交互过程&#xff0c;显示地图的html文件&#xff1a; <!DOCTYPE html> <html><head> <meta name"viewport" content&q…

基于ubuntu的驱动开发

一般的linux驱动开发都是基于交叉编译来进行的&#xff0c;本文尝试着从另一个角度&#xff1a;基于ubuntu的本地驱动开发来学习一下驱动的开发 一、驱动的开发与编译 1.1、编写驱动文件 #include <linux/init.h> #include <linux/module.h> static int hello_i…

深入理解Linux网络——内核是如何接收到网络包的

文章目录 一、相关实际问题二、数据是如何从网卡到协议栈的1、Linux网络收包总览2、Linux启动1&#xff09;创建ksotfirqd内核线程2&#xff09;网络子系统初始化3&#xff09;协议栈注册4&#xff09;网卡驱动初始化5&#xff09;网卡启动 3、迎接数据的到来1&#xff09;硬中…

Gradio库中的Model3D模块:实时上传和展示3D模型

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

结合具体场景举例说明chatgpt预训练模型中Tokenization的原理

假设我们有一个场景&#xff0c;Alice想向Chatbot询问一部电影的推荐。她发送了一条消息&#xff1a;“你好&#xff0c;能给我推荐一部好看的电影吗&#xff1f;” 在这个场景中&#xff0c;Chatbot使用了ChatGPT预训练模型。首先&#xff0c;Chatbot需要对Alice的消息进行Tok…

OpenCV读取一张8位无符号三通道图像并显示

#include <iostream> #include <opencv2/imgcodecs.hpp> #include <opencv2/opencv.hpp> #include

c++编写网络爬虫

c爬虫项目 实现图形化界面UI 安装easyX&#xff08;需要用的graphisc.h&#xff09; 我之前的文章详细写到过如何安装。是这篇文章提到的&#xff1a;传送门 easyx官网 创建图形化界面 #define WINDOW_WIDTH 482 #define WINDOW_HEIGHT 300 void initUI() {initgraph(WINDO…

SwiftUI的优缺点

2019年WWDC大会上&#xff0c;苹果在压轴环节向大众宣布了基于Swift语言构建的全新UI框架——SwiftUI&#xff0c;开发者可通过它快速为所有的Apple平台创建美观、动态的应用程序。推荐大量使用struct代替类。 SwiftUI 就是⼀种声明式的构建界面的用户接口工具包。 SwiftUI使用…

机器学习与深度学习——自定义函数进行线性回归模型

机器学习与深度学习——自定义函数进行线性回归模型 目的与要求 1、通过自定义函数进行线性回归模型对boston数据集前两个维度的数据进行模型训练并画出SSE和Epoch曲线图&#xff0c;画出真实值和预测值的散点图&#xff0c;最后进行二维和三维度可视化展示数据区域。 2、通过…

SpringBoot + Vue前后端分离项目实战 || 五:用户管理功能后续

系列文章&#xff1a; SpringBoot Vue前后端分离项目实战 || 一&#xff1a;Vue前端设计 SpringBoot Vue前后端分离项目实战 || 二&#xff1a;Spring Boot后端与数据库连接 SpringBoot Vue前后端分离项目实战 || 三&#xff1a;Spring Boot后端与Vue前端连接 SpringBoot V…