0


前端项目中的CI/CD实践(自动化部署)

前言

前置知识

  • Linux
  • Docker
  • Nginx
  • Github

可以干嘛

作为一套面向开发和运维团队的解决方案,CI/CD 主要解决集成新代码和向用户频繁交付应用的问题。

更直接地说,就是可以解放开发人员的双手,将时间和精力专注于代码本身。

CI/CD是什么

CI/CD(Continuous Intergration/Continuous Delpoy),持续集成/持续部署,或者持续集成/持续交付(Continuous Delivery),是一种在开发阶段引入自动化来频繁交付应用的方法。从前端的角度看,CICD的流程中涉及:

  • CI:代码push到托管平台之后的lint测试单元测试
  • CD:将build后的项目丢到远端 Nginx 的静态资源目录下

构建/部署

前后端分离的开发模式中,前端项目经常会使用框架进行开发,经由 Webpack(或者其他构建工具) 打包后的SPA应用(代码),本质上都是静态资源,只需要把它们都放到 Nginx的静态资源目录下,配好相关的路径,即可完成部署。

前端项目的构建、部署、上线流程,从 简陋疏散完善严谨 ,大致经历了以下几个阶段:

手动挡

#mermaid-svg-F5IbSPZaGA9fZE47 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-F5IbSPZaGA9fZE47 .error-icon{fill:#552222;}#mermaid-svg-F5IbSPZaGA9fZE47 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-F5IbSPZaGA9fZE47 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-F5IbSPZaGA9fZE47 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-F5IbSPZaGA9fZE47 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-F5IbSPZaGA9fZE47 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-F5IbSPZaGA9fZE47 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-F5IbSPZaGA9fZE47 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-F5IbSPZaGA9fZE47 .marker.cross{stroke:#333333;}#mermaid-svg-F5IbSPZaGA9fZE47 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-F5IbSPZaGA9fZE47 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-F5IbSPZaGA9fZE47 .cluster-label text{fill:#333;}#mermaid-svg-F5IbSPZaGA9fZE47 .cluster-label span{color:#333;}#mermaid-svg-F5IbSPZaGA9fZE47 .label text,#mermaid-svg-F5IbSPZaGA9fZE47 span{fill:#333;color:#333;}#mermaid-svg-F5IbSPZaGA9fZE47 .node rect,#mermaid-svg-F5IbSPZaGA9fZE47 .node circle,#mermaid-svg-F5IbSPZaGA9fZE47 .node ellipse,#mermaid-svg-F5IbSPZaGA9fZE47 .node polygon,#mermaid-svg-F5IbSPZaGA9fZE47 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-F5IbSPZaGA9fZE47 .node .label{text-align:center;}#mermaid-svg-F5IbSPZaGA9fZE47 .node.clickable{cursor:pointer;}#mermaid-svg-F5IbSPZaGA9fZE47 .arrowheadPath{fill:#333333;}#mermaid-svg-F5IbSPZaGA9fZE47 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-F5IbSPZaGA9fZE47 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-F5IbSPZaGA9fZE47 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-F5IbSPZaGA9fZE47 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-F5IbSPZaGA9fZE47 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-F5IbSPZaGA9fZE47 .cluster text{fill:#333;}#mermaid-svg-F5IbSPZaGA9fZE47 .cluster span{color:#333;}#mermaid-svg-F5IbSPZaGA9fZE47 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-F5IbSPZaGA9fZE47 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

      本地build项目
     

      sftp上传远程服务器
     

      配置nginx访问路径
     
  1. 本地执行 yarn build构建项目
  2. 使用 transmit 或其他支持 sftp的软件上传打包后的项目(当然也有其他方式)
  3. 修改 Nginx 的 nginx.conf 文件,配置项目的访问路径

手动部署操作起来很简单,但缺点也很明显,每次构建完都要人为地进行部署的动作,一方面减少了实际敲代码的时间,另一方面,人工操作免不了会有疏忽出错的时候。

自动挡

随着工程化的发展和工具链的成熟,项目部署不再像以前简单粗暴。前端代码的健壮性可靠性越来越被重视,项目发布前往往需要 代码约束代码测试 ,校验通过后服务器拉取最新的代码,进行 build 和 nginx 配置后才算完成整个部署的过程。

#mermaid-svg-zEaoFFn8VK5op9FE {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-zEaoFFn8VK5op9FE .error-icon{fill:#552222;}#mermaid-svg-zEaoFFn8VK5op9FE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zEaoFFn8VK5op9FE .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-zEaoFFn8VK5op9FE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zEaoFFn8VK5op9FE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zEaoFFn8VK5op9FE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zEaoFFn8VK5op9FE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zEaoFFn8VK5op9FE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zEaoFFn8VK5op9FE .marker.cross{stroke:#333333;}#mermaid-svg-zEaoFFn8VK5op9FE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zEaoFFn8VK5op9FE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zEaoFFn8VK5op9FE .cluster-label text{fill:#333;}#mermaid-svg-zEaoFFn8VK5op9FE .cluster-label span{color:#333;}#mermaid-svg-zEaoFFn8VK5op9FE .label text,#mermaid-svg-zEaoFFn8VK5op9FE span{fill:#333;color:#333;}#mermaid-svg-zEaoFFn8VK5op9FE .node rect,#mermaid-svg-zEaoFFn8VK5op9FE .node circle,#mermaid-svg-zEaoFFn8VK5op9FE .node ellipse,#mermaid-svg-zEaoFFn8VK5op9FE .node polygon,#mermaid-svg-zEaoFFn8VK5op9FE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zEaoFFn8VK5op9FE .node .label{text-align:center;}#mermaid-svg-zEaoFFn8VK5op9FE .node.clickable{cursor:pointer;}#mermaid-svg-zEaoFFn8VK5op9FE .arrowheadPath{fill:#333333;}#mermaid-svg-zEaoFFn8VK5op9FE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zEaoFFn8VK5op9FE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zEaoFFn8VK5op9FE .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-zEaoFFn8VK5op9FE .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-zEaoFFn8VK5op9FE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zEaoFFn8VK5op9FE .cluster text{fill:#333;}#mermaid-svg-zEaoFFn8VK5op9FE .cluster span{color:#333;}#mermaid-svg-zEaoFFn8VK5op9FE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zEaoFFn8VK5op9FE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

      lint校验
     

      单元测试
     

      push远端仓库
     

      服务器拉取最新代码
     

      build构建项目
     

      配置nginx
     
  1. 代码扫描 yarn lint检查代码是否规范
  2. yarn unit进行单元测试
  3. git push提交更改到远端仓库
  4. 登录服务器,git pull拉取最新代码
  5. yarn build构建项目
  6. 配置 nginx 访问路径

这个阶段,我们借助一些工具,能够减少代码不规范或隐藏bug的问题。但所有的操作还是得一行一行命令去敲,项目真正的部署也还是需要手动去操作服务器。

其实完全可以将上面的操作细节都集成到一个 shell 脚本里,通知执行 shell 也能减少很多重复的工作。

CI/CD

上面提到,借助shell也能使得一部分操作自动化,但无论是代码扫描、单元测试还是项目的构建,都还是在本地的开发机上进行(或者说跟开发强耦合),有没有办法将这些附属的操作抽离出来,放到另外的专有环境下进行呢?

现在很流行的 DevOps 理念中,CI/CD的那一环就能很好地实现。

DevOps是一种思想理念,强调软件开发测试运维的一体化,目标是减少各个部门之间的沟通成本,从而实现软件的快速高质量的发布。CI/CD是一套实践方案,实现软件的构建测试部署的自动化。

CI/CD实践 —— 前端项目自动化部署

流程架构

想要达到的效果

远程主分支代码发生改变,拉取主分支代码进行构建,完成后通过 ssh 上传到测试/生产服务器。

Github + Jenkins 的实现链路

#mermaid-svg-kYrig4bhz9C5FZZN {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-kYrig4bhz9C5FZZN .error-icon{fill:#552222;}#mermaid-svg-kYrig4bhz9C5FZZN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kYrig4bhz9C5FZZN .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-kYrig4bhz9C5FZZN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kYrig4bhz9C5FZZN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kYrig4bhz9C5FZZN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kYrig4bhz9C5FZZN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kYrig4bhz9C5FZZN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kYrig4bhz9C5FZZN .marker.cross{stroke:#333333;}#mermaid-svg-kYrig4bhz9C5FZZN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kYrig4bhz9C5FZZN .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-kYrig4bhz9C5FZZN text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-kYrig4bhz9C5FZZN .actor-line{stroke:grey;}#mermaid-svg-kYrig4bhz9C5FZZN .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-kYrig4bhz9C5FZZN .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-kYrig4bhz9C5FZZN #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-kYrig4bhz9C5FZZN .sequenceNumber{fill:white;}#mermaid-svg-kYrig4bhz9C5FZZN #sequencenumber{fill:#333;}#mermaid-svg-kYrig4bhz9C5FZZN #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-kYrig4bhz9C5FZZN .messageText{fill:#333;stroke:#333;}#mermaid-svg-kYrig4bhz9C5FZZN .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-kYrig4bhz9C5FZZN .labelText,#mermaid-svg-kYrig4bhz9C5FZZN .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-kYrig4bhz9C5FZZN .loopText,#mermaid-svg-kYrig4bhz9C5FZZN .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-kYrig4bhz9C5FZZN .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-kYrig4bhz9C5FZZN .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-kYrig4bhz9C5FZZN .noteText,#mermaid-svg-kYrig4bhz9C5FZZN .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-kYrig4bhz9C5FZZN .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-kYrig4bhz9C5FZZN .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-kYrig4bhz9C5FZZN .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-kYrig4bhz9C5FZZN .actorPopupMenu{position:absolute;}#mermaid-svg-kYrig4bhz9C5FZZN .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-kYrig4bhz9C5FZZN .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-kYrig4bhz9C5FZZN .actor-man circle,#mermaid-svg-kYrig4bhz9C5FZZN line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-kYrig4bhz9C5FZZN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
VSCode

  Github
 
  Jenkins
 
  服务器
 
  浏览器
 

提交代码

合并到master

通知

 执行任务

 拉取代码

构建项目

推送到服务器

 配置nginx访问路径

访问项目部署地址

 VSCode

 Github

 Jenkins

 服务器

 浏览器

前端自动化部署

Github Actions 的实现链路

#mermaid-svg-xgIkMtvgpPkQFN6p {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-xgIkMtvgpPkQFN6p .error-icon{fill:#552222;}#mermaid-svg-xgIkMtvgpPkQFN6p .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xgIkMtvgpPkQFN6p .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-xgIkMtvgpPkQFN6p .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xgIkMtvgpPkQFN6p .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xgIkMtvgpPkQFN6p .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xgIkMtvgpPkQFN6p .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xgIkMtvgpPkQFN6p .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xgIkMtvgpPkQFN6p .marker.cross{stroke:#333333;}#mermaid-svg-xgIkMtvgpPkQFN6p svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xgIkMtvgpPkQFN6p .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-xgIkMtvgpPkQFN6p text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-xgIkMtvgpPkQFN6p .actor-line{stroke:grey;}#mermaid-svg-xgIkMtvgpPkQFN6p .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-xgIkMtvgpPkQFN6p .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-xgIkMtvgpPkQFN6p #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-xgIkMtvgpPkQFN6p .sequenceNumber{fill:white;}#mermaid-svg-xgIkMtvgpPkQFN6p #sequencenumber{fill:#333;}#mermaid-svg-xgIkMtvgpPkQFN6p #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-xgIkMtvgpPkQFN6p .messageText{fill:#333;stroke:#333;}#mermaid-svg-xgIkMtvgpPkQFN6p .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-xgIkMtvgpPkQFN6p .labelText,#mermaid-svg-xgIkMtvgpPkQFN6p .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-xgIkMtvgpPkQFN6p .loopText,#mermaid-svg-xgIkMtvgpPkQFN6p .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-xgIkMtvgpPkQFN6p .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-xgIkMtvgpPkQFN6p .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-xgIkMtvgpPkQFN6p .noteText,#mermaid-svg-xgIkMtvgpPkQFN6p .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-xgIkMtvgpPkQFN6p .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-xgIkMtvgpPkQFN6p .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-xgIkMtvgpPkQFN6p .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-xgIkMtvgpPkQFN6p .actorPopupMenu{position:absolute;}#mermaid-svg-xgIkMtvgpPkQFN6p .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-xgIkMtvgpPkQFN6p .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-xgIkMtvgpPkQFN6p .actor-man circle,#mermaid-svg-xgIkMtvgpPkQFN6p line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-xgIkMtvgpPkQFN6p :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
VSCode

  Github
 
  服务器
 
  浏览器
 

提交代码

合并到master

触发钩子

 执行 build 任务

推送到服务器

 配置nginx访问路径

访问项目部署地址

 VSCode

 Github

 服务器

 浏览器

前端自动化部署

搭建过程

Github + Jenkins

docker环境的搭建
  1. 安装 docker# 安装 docker 的依赖库,-y 选项表示所有的 Is this OK[y/d/N],都会自动选择yyum install -y yum-utils device-mapper-persistent-data lvm2 # 添加 docker cd 软件源信息sudo yum-config-manager --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo# 安装 docker ce sudo yum install docker-ce
  2. 启动 dockersudo systemctl enable docker # 设置开机自启sudo systemctl start docker /# 启动docker

docker centos 安装指南

安装docker-compose

docker-compose 用于定义和运行多容器 docker 应用程序,使用 yml 文件配置应用所需的所有服务。

  1. 安装 docker-composesudocurl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  2. 提升权限sudochmod +x /usr/local/bin/docker-compos

docker-compose 安装指南

创建 docker-compose 应用

这里为了方便, nginx 通过容器的方式去启动(不会影响到我目前的 nginx ),jenkins 就还是放在根项目部署的服务器上(方便后续直接通过 shell 复制构建好的项目)

(拉取nginx镜像,编写目录数据卷映射)

  1. 拉取 nginx 镜像docker pull nginxdocker images # 查看安装的镜像
  2. 创建数据卷目录,以便挂载到容器里+ compose # docker-compose 配置目录 - docker-compose.yml + nginx + conf # nginx 配置 - nginx.conf + html # nginx 静态资源 - index.html
  3. 编写 docker-compose.ymlversion: '3'services: cicd_nginx: restart: always image: nginx container_name: nginx ports: - 3300:80 - 3301:433 volumes: - ../nginx/html:/usr/share/nginx/html - ../nginx/conf/nginx.conf:/etc/nginx/nginx.conf - ../nginx/log:/var/log/nginx - ../nginx/localtime:/etc/localtime:ro
  4. 启动docker-compose up -ddocker-compose stop //停止nginx和jenkins
  5. 公网查看 nginx

image-20220122154400721

image-20220122154557051

Jenkins基本配置
  1. 前往 jenkins 容器挂载的数据卷中获得初始密码cat /home/cicd_demo/jenkins/jenkins_home/secrets/initialAdminPassword > 这个密码只会显示一次,之后如果忘记密码需要重置
  2. 输入密码进入页面之后,选择推荐安装image-20220122155307819可以看到,jenkins 会自动帮我们安装很多插件,比如最常用的 gitimage-20220122155629224
  3. 新建账户image-20220122155900060
  4. 进入到主页后,先前往 Manage Jenkins - Manage Plugins 安装需要用到的插件,目前就只需要安装 NodeJSimage-20220122172232223
  5. 前往全局工具配置,安装需要的不同版本的 node 环境image-20220122222048344
  6. 配置 github在配置之前,我们先要到 GitHub 生成 Personal access token头像 - Settings - Developer settings - Personal access tokens - Generate new token,按下图勾选需要的权限image-20220122222951817 还记得我们要实现的效果吗?当主分支有新的代码提交,就要通知 jenkins 去拉取代码并进行构建。既然是通知,那么肯定就需要用到 Webhook。这里并不需要手动创建 Webhock,jenkins提供的插件会帮我们创建。接下来继续配置插件,**Manage Jenkisn - Config System - **,找到 Github 配置的部分

image-20220122223754425
点击添加凭证,选择 Jenkins,点击后会弹出一个添加凭据的窗口,Type 选择为 Secret text,将我们刚才生成的 Personal access token 复制到 Secret 一栏中,点击添加
image-20220122223948772
添加后在 Credentials 一栏选中 Secret text,勾选 Manage Hook,点击 Test connection,如果正确显示了GitHub 用户名,就说明配置成功了。

经过上面几步后,就完成了两件事情,Node 环境的配置和 Github Webhock 的添加,下面就可以开始新建任务了。

新建一个Item
  1. 回到首页,新建一个自由风格的任务image-20220122225529611
  2. 勾选 GitHub project,输入项目地址。将下面的 Source Code Management 选中为 Git,将你要构建部署的项目的 clone 地址填到 Repository URL 一栏中。image-20220122225920767image-20220122230320553如果是公开的仓库,Credentials可以选择无。这里我准备的是一个私有的仓库,还需要添加一个可以访问访问 Github账户 的凭证,添加方法类似上面配置 Github Webhock 。这里选择 ssh private key的方式image-20220122231214377
  3. 设置构建触发器和构建环境image-20220122231805390
  4. 编写构建shellimage-20220123000138842

经过上面的步骤,就算完成一个 Item了,当 Github主分支有新的代码提交,就会触发构建:

image-20220123002304395

Github Actions

Github Actions 是 Github 提供的持续集成服务,可以使我们的 repo 获得一些自动化的能力。

举例来说:

  • 每次 repo 有新的提交或 pr 就自动执行 build
  • 在 repo 中定时执行自定义的脚本
  • 将代码打成镜像,自动提交到镜像仓库中
一些概念
  • workflow:一次执行过程,每个 workflow 使用一个配置文件维护
  • jobworkflow 的分解,可串行存在依赖,也可并行执行
  • stepjob 的分解,即具体执行的步骤
  • action:执行过程的封装,可以自定义,也可以使用 Github 社区定义好的 action
  • artifactworkflow 运行时产生的中间文件,包括日志、测试结果等
  • event:触发 workflow 的事件,也可以理解为生命周期钩子
如何配置

配置 CI/CD 任务的过程本质上是向 runner 描述如下内容:

  • 什么时候执行
  • 执行什么操作

这里的 workflow 配置文件就是用来做这个工作的

workflow 的触发

每个 workflow 的配置文件都需要定于

on

字段,用以描述在何种情况下(

event

)下触发

job

的执行

event

可以分为 3 类:

  • 定时事件:由定时任务触发的事件
  • 手动触发事件:在 actions 页面中手动触发的时间
  • Webhook 事件:Github 自身的钩子函数触发的事件,通常伴随着 git 操作

在这里,我们只会用到最后一种,来描述 git 操作触发的 CI/CD 行为

自动化部署的 workflow

下面是我在项目中经常使用的部署模板,我给它们加上了详细的注释

name: build and deploy # workflow 名称on:push:# push 事件触发branches:[ dev ]# 只在 dev 分支有新的 push 情况下触发jobs:build:# job 名称runs-on: ubuntu-latest # 执行 workflow 所需的操作系统环境steps:-name: checkout
        uses: actions/checkout@v2 # 使用切换分支的 action 操作-name: build
        run: yarn && yarn build # 构建命令-name: deploy
        uses: easingthemes/ssh-deploy@main # 使用 ssh 上传文件的 action 操作env:SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}# ssh 密钥对中的私钥ARGS:"-rltgoDzvO"SOURCE:"dist"# 要进行上传的文件目录REMOTE_HOST: ${{ secrets.REMOTE_HOST  }}# 服务器主机 ipREMOTE_USER: ${{ secrets.REMOTE_USER }}# 服务器用户名TARGET: ${{ secrets.REMOTE_TARGET }}# 要进行部署的生产环境目录-name: print env
        run: printenv # 打印环境变量-name: build success
        if: ${{ success() }}# ${{ }} 可以使用上下文参数,success() 表示当上一步执行成功时返回 trueuses: chf007/action-wechat-work@master # 使用发送企业微信消息的 actionenv:WECHAT_WORK_BOT_WEBHOOK: ${{secrets.WX_WEBHOOK}}# github token,需要自己在 repo 的 settings 中生成with:msgtype: news
          articles:'[{"title":"💯👨‍💻 Success Deploy ! 🎉🎉🎉","description":"click here to visit the test site ~","url":"http://xxxx:8080/","picurl":"https://xxxx.com/xxxx/figure-bed/raw/master/images/202203101823814.jpeg"}]'mentioned_list:'[@all"]'-name: build failure
        if: ${{ failure() }}uses: chf007/action-wechat-work@master
        env:WECHAT_WORK_BOT_WEBHOOK: ${{secrets.WX_WEBHOOK}}with:msgtype: markdown
          content:|
            # 💤🤷‍♀️ Deploy Failure 🙅‍♂️💣
            > (⋟﹏⋞)  from github action messagementioned_list:'[@all"]'

注:上面 ssh 部署的方式使用了 rsa 秘钥对中的私钥,不知道怎么生成的话请参考服务器上的-Git-生成-SSH-公钥

pr 合并消息提醒的 workflow
name: pull request

on:pull_request:branches:[ master, dev ]jobs:pr:runs-on: ubuntu-latest
    steps:-name: checkout
        uses: actions/checkout@v2

      # 获取 pr 信息,添加到环境变量-name: set pr info
        run:|
          echo PR_NUMBER=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }') >> $GITHUB_ENV
          echo PR_FROM=$(echo $GITHUB_HEAD_REF ) >> $GITHUB_ENV
          echo PR_TO=$(echo $GITHUB_B_REF ) >> $GITHUB_ENV
          echo PR_TITLE=$(jq --raw-output .pull_request.title "$GITHUB_EVENT_PATH") >> $GITHUB_ENV
          echo PR_URL=$(jq --raw-output .pull_request.html_url "$GITHUB_EVENT_PATH") >> $GITHUB_ENV
          echo PR_USER=$(jq --raw-output .pull_request.user.login "$GITHUB_EVENT_PATH") >> $GITHUB_ENV
          echo PR_COMMITS_NUM=$(jq --raw-output .pull_request.commits "$GITHUB_EVENT_PATH") >> $GITHUB_ENV-name: print env
        run: printenv

      -name: pull request
        uses: chf007/action-wechat-work@master
        env:WECHAT_WORK_BOT_WEBHOOK: ${{secrets.WX_WEBHOOK}}with:msgtype: markdown
          content:|
            # 😍 Pull Request 🤤 ! (^-^)V
            > [${{ env.PR_TITLE }} #${{ env.PR_NUMBER }}](${{ env.PR_URL }})
            > ${{ env.PR_USER }} wants to merge ${{ env.PR_COMMITS_NUM }} commits
            > into <font color=#2F8CDB>${{ env.PR_TO }}</font> from <font color=#008000>${{ env.PR_FROM }}</font>
代码 push 并发起 pr,触发 workflow

尝试将本地的代码推送到远端,可以看到确实触发了部署的操作
image-20220415134754666
发起一个从开发分支到主分支的合并,同样的,也能触发对应的 workflow
image-20220415144404314

总结

经过以上的步骤,也就实现了一个最小化自动化部署的实践,但这仅仅只是 CI/CD 庞杂管道流程中的一环,很多时候还会结合 docker、k8s、sentry、gitlab等实现多平台协同。上面用到的 Jenkins、Github Actions ,也只是工具中的两种,类似的还有国人开发的 Gitea、Onedev等各类集成了 CI/CD 的代码自建托管平台;企业中,也很有可能会自建一套完整的系统去满足内部的要求。

上面两种方案虽然使用起来很方便,但其内部的实现,想必还是十分复杂的,后面有时间也会继续学习的。

参考

使用GithubActions自动化工作流

花半天时间,轻松打造前端CI/CD工作流

从零搭建docker+jenkins+node.js自动化部署环境

标签: 前端 jenkins github

本文转载自: https://blog.csdn.net/marshmallow_/article/details/124194274
版权归原作者 棉花糖还是不甜的好吃 所有, 如有侵权,请联系我们删除。

“前端项目中的CI/CD实践(自动化部署)”的评论:

还没有评论