Design and implement a simple automated deployment tool

Before I say it, put the address cycle.bucai.cc/ first , the development environment is running, it is a bit slow, please wait patiently for loading.

GitHub: github.com/notbucai/cb…

This is a record of my attempt to use a process-based approach to project development and implementation.

As for why the existing and perfect framework on the market is not applicable, it is because I haven't written a complete and meaningful thing for a long time, and of course I will still "learn" from some mature projects.

design

source of demand

Recently, I have been intermittently proud to upgrade and optimize the blog function points. The project is divided into the background nestjs project, the foreground nuxtjs, and the management system vue.js. The current deployment method uses Docker to compile the local image and push it to the private warehouse before entering the server. Restart after pull. There is also multi-person collaborative development. Everyone needs to install the server environment (Docker, etc.) locally to ensure environment consistency.

It is not difficult to find from the above description:

  1. The compilation methods cannot be unified due to differences in the templates, languages, and states (static, services) used by the project after deployment.
  2. Repetitive issues with the current manual deployment process.
  3. The server environment needs to be matched, and the local development computer configuration requirements are high.

target expectations

  1. Project deployment templates, and different templates can be selected for packaging according to different types.
  2. Transition manual deployments to automated deployments.
  3. Depends on branch monitoring, push automatically triggers deployment, and solves high local configuration requirements.

research

Because most people need this tool in their daily work, the survey is simply explained.

Research objectives: Netlify (foreign), Tencent Cloud Webify (domestic).

what problems do they solve

  1. Deploy the resource.
  2. CI/CD workflow.

their disadvantages (Forcibly increase the height of the current project

  1. Netlify abroad, dddd.
  2. Webify cloud manufacturers conduct operation and maintenance, and start to cut leeks when they are not guaranteed.

demand analysis

Through the above content, it is very intuitive to obtain the required function points of the project.

core analysis

The core function is to operate "task" as a unit, create tasks and manage tasks.

The so-called "task" means that the state needs to be transferred. At present, tasks are divided into in-progress, failed, and stopped.

Each trigger should generate a subtask, and if there is an ongoing subtask at the time of triggering, it should stop and start a new task.

进行中的任务包含子状态:编译中、编译成功、编译失败。 image20220316144709804.png 用户交互以及核心环节请看下方流程图。 image20220317135932109.png

功能设计

  1. 创建任务

    主要对某个仓库的分支进行webhook的注册,并将任务信息写入数据库。

  2. 管理任务

    主要对创建后的任务信息进行管理,删除、暂停、开始。

    1. 开始

      对暂停的任务继续进行。

    2. 暂停

      对正在进行中的任务进行。

    3. 删除

      删除此条数据,并删除webhook。

  3. 任务执行

    通过webhook触发执行,找到当前数据进行执行。

任务执行设计

如何不同配置进行不同的编译/运行方式?

所有编译都采用docker进行隔离编译,运行根据不同类型进行选择不同的方式。

目前区分两种类型,一种是静态、一种是动态:

  • 静态:采用采用docker编译后上传cdn方式,当然只是模拟暂只放nginx静态目录中。
  • 动态:使用docker编译后docker运行。
web service
无需端口 端口
nginx 转发资源 nginx 转发端口
可能需要编译 可能需要编译
不需要容器运行 需要容器运行
动作 spa项目 普通网页 Ts node 项目 普通node项目
构建
编译
运行

上方从资源类型和项目类型进行对比,直观的表达了任务的执行动作。

静态资源(web)容器构建后,通过docker cp 将镜像中dist数据copy到主机中,然后转移到nginx中。

服务资源(service)容器构建编译后,再运行起来,然后添加nginx将容器映射到机器端口上。

端口后续进行维护,容器内端口不做管理,靠nginx容器进行映射维护。

用户自己的任务容器之间可以相互通信,通过任务id即可访问,如果是静态资源需要访问后续通过配置将接口进行转发,同时用户可以绑定自己的域名到当前机器上。

页面设计

前端采用naive-ui作为前端布局样式组件。

其在交互上主要分为三步:

  1. 选择托管平台

    github、gitee等平台,选择的托管平台必须是授权登录过的。

  2. 输入信息

    输入任务所必须的数据字段

  3. 确认信息

    确认输入的是否符合要求

由于设计比较简单,直接以图片形式展示。

image20220316211446898.png

image20220316211843872.png

任务列表字段:任务名称/ID、托管平台、模版、状态、创建人、创建时间、更新时间、操作时间。

image20220316213030155.png

详情页

image202203171312011567493921.png

数据库设计

只展示核心表的设计

image20220317170217861.png

用户表

image20220317174654027.png

托管平台表

image20220317174750795.png

模版表

image20220317174838491.png

任务表

image20220317174930114.png

子任务表

image20220317174942131.png

接口设计

包含crud,直接查看接口文档:

www.apifox.cn/apidoc/proj…

技术选型

选择的方案的标准是 我会简单

目前选择egg + mysql + redis + vue架构,编码尽量ts化。其他框架也考虑过比如nestjs、koa,相对而言nest太大了,koa又太小了,选 vue 其实只是想试一下3.x的版本。

eggjs: 为企业级框架和应用而生。

vue: 懂得都懂。

项目架构

架构很简单,就是存储配合依赖进行触发。

image20220317202317492.png

服务器运维架构

image20220324224146093.png

独立当前应用,用户可共享自己的服务并独立运行(隔离),原则上每个用户都可以申请一些存储与其他资源(待定),不过仍然建议使用远程/第三方资源。

编译/部署 触发 流程

image20220324223949408.png

是否编译:有些node项目是不需要编译的步骤

是否运行:静态资源不需要运行,直接打到nginx中即可

实现

核心功能实现(暂时只做实现 github 相关业务,其他平台预留接口)。

项目进度查看

image20220319105154899.png

绑定托管平台

bg2014051203.png 引用阮一峰一图,一文,绑定流程基本上就是浏览器重定向,后返回code,拿到code换token,然后将token保存。

获取相关信息

通过以下api进行操作

用户储存库列表

获取分支列表

获取指定文件内容

创建任务

创建任务写入 webhook。

创建webhook

任务执行

等待webhook回调

docs.github.com/cn/develope…

任务执行相关模版每次触发都执行,使用ejs进行配置渲染生成。

// 注入内容
{
  user, // 数据库user model
  task, // 数据库task model
  taskChild, // 数据库task_child model
  template, // 数据库template
  path: {
    ...path, // 相关路径
    code: relativeCodePath // 代码与配置的相对位置
  }
}
复制代码
# dock er file
FROM node:12.18.2

LABEL maintainer="<%= user.id %><<%= user.email %>>"

ADD <%= path.code %> /app/

WORKDIR /app

RUN rm -rf node_modules

RUN rm -rf <%= path.build %>

RUN npm config set sharp_binary_host https://npm.taobao.org/mirrors/sharp

RUN npm config set sharp_libvips_binary_host https://npm.taobao.org/mirrors/sharp-libvips

RUN npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass

RUN npm install --registry https://registry.npm.taobao.org --max-old-space-size=4096

ENV NODE_ENV production

<% if (template.is_build) { %>
RUN npm run <%= task.build_script %>
<% } %>

<% if (template.is_run) { %>
EXPOSE <%= task.server_port %>

CMD  nohup sh -c 'npm run <%= task.run_script %>'
<% } %>
复制代码
# docker compose config
version: "3.7"

services:
  "<%= task.id %>":
    build: .
    image: <%= task.id %>:<%= taskChild.version || '0.0.1' %>
    container_name: <%= task.id %>
    restart: always
<% if (template.is_run) { %>
    networks:
      <%= user.id %>-network:
        ipv4_address: <%= task.ip %>

networks:
  <%= user.id %>-network:
    external: true
<% } %>
复制代码

构建/编译/运行 相关

node child_process exec 进行命令执行:

使用 exec('docker-compose build')进行镜像的构建。

Use exec(docker cp $(docker create --rm ${imageName}):/app/${buildPath} ./dist)to copy the data in the container to the host.

Use docker-compose downto stop an existing mirror image.

Use 'docker-compose restartthe restart of the image container.

Use docker-compose upthe boot-compiled image.

Guess you like

Origin juejin.im/post/7082661598132699144
Recommended