浅谈gitlab-ci分离部署方案

3,513 阅读6分钟

前言

关于前端部署,相信不同的公司都有不同的方案。我先说说我所知道的几种(都是基于SPA应用的),最后聊一聊关于gitlab-ci来发布前端应用。

多样的部署方案

前端应用的部署可以简单的分为两个方面,一是静态资源文件的部署,二是html页面托管。

最传统的方式(简单粗暴型)

把打包好的文件(静态文件和html页面)全部丢给后端同学,由服务端提供渲染html的功能。

弊端:用户所有访问的文件都在服务器上,服务器的压力相对更大,一旦服务器挂了,直接访问出错,用户体验不太好。

好处:不需要额外的工具作为支撑,对于小公司而言,可能是最简单方便的部署方案。

cdn托管静态资源

由cdn托管静态资源,html文件放在后端服务进行渲染。把css,js文件部署在cdn,一方面可以降低服务器的压力,另一方面也能提升用户的访问速度。

大家都知道webpack打包后的文件默认都是带contenthash值的,如app.0d203f04c0cb433d9f67f9a4fa8cf74e.css,那么如果html放在后端服务的话,务必要根据前端打包后的html,再重新去更新html,这肯定不是我们想要的结果。因此我们修改webpack配置,把部分资源的contenthash值去掉,这样我们打包出来的css文件,js文件就没有这些hash值了,但是因为cdn有缓存,所以html文件中引入的静态资源文件还要在最后带上时间戳,这样可以保证访问正常。但是这又带来一个问题,如果时间戳是每次访问都刷新,那么用户每次访问都要请求cdn上的文件,也就相当于本地没有缓存,对于加载不是很好。所以就衍生出另一种机制,通过调用api去刷新时间戳,这样一来可以保证本地缓存正常,其次html也不用每次发布都重新更新了。但是,如果我们哪天要更新html的内容,比如产品经理说我们要加个google打点,那么我们需要在html上加一段js脚本,这时候我们并不涉及后端的改动,我们却要后端帮忙重新发布html文件,是不是不太友好呢。

半自动化发布

这种发布模式和第二种发布方式本质上是一样的,公司内部可能会提供一个发布平台,我们通过发布平台打包构建我们的应用,再由这个平台把打包好的文件发布到cdn上。与上一种方式相比,我们不需要再在本地打包了。

gitlab-ci发布部署

方案初衷

  • 解决未前后端分离带来的痛点。如:刷新时间戳(因不通项目刷新机制不通,麻烦),html更新不方便。
  • 规范化前端构建和发布流程
  • 自动化前端构建和发布流程
  • 扩展前端能力边界, 例如MPA、SSR等等

架构原理

准备条件

gitlab-runner

构建任务都会占用很多的系统资源 (譬如编译代码),而 GitLab CI 又是 GitLab 的一部分,如果由 GitLab CI 来运行构建任务的话,在执行构建任务的时候,GitLab 的性能会大幅下降。

GitLab CI 最大的作用是管理各个项目的构建状态,因此,运行构建任务这种浪费资源的事情就交给 GitLab Runner 来做啦。因为 GitLab Runner 可以安装到不同的机器上,所以在构建任务运行期间并不会影响到 GitLab 的性能。

Runner 的注册, 需要一台服务器 (官方说法是: 任何一个连接互联网且可以执行程序的机器或容器), 在需要执行工作流时, Gitlab 会将任务分配给合适的 runner 执行 (可以注册很多个不同分工的 runner).

注册一个 runner 又分两步:

  1. 在服务器上安装 gitlab-runner: docs.gitlab.com/runner/inst…
  2. 把这台服务器注册为一个项目的 runner: docs.gitlab.com/runner/regi…

(这里可能需要预备一些服务器相关的知识)

.gitlab-ci.yml

.gitlab-ci.yml 用来配置 CI 用你的项目中做哪些操作,这个文件位于仓库的根目录。

当有新内容push到仓库,或者有代码合并后,GitLab 会查找是否有 .gitlab-ci.yml 文件,如果文件存在,Runners 将会根据该文件的内容开始 build 本次 commit。

.gitlab-ci.yml 使用YAML语法,你需要格外注意缩进格式,要用空格来缩进,不能用tabs来缩进。

api规范

规范后端api,比如所有api都符合 /api/** 规则,有一定规则后,才方便做代理转发。

接入步骤

默认已经准备好一台服务器和响应的脚本(可能需要运维参与。如果是自己尝试玩儿,可以把本地的电脑当作跑runner的机器,写对应的脚本,配置好自己的服务器,即可把想要推的文件推送到服务器啦)

一、runner绑定

在已经安装好gitlab-runner的机器上注册一个runner。注册runner时需要绑定项目的token。

建议:绑定runner时,可以设置tag,推荐设置。

二、配置脚本(./deploy.sh)

目录结构

.
├── deploy.sh
├── build
├── src
├── package.json
├── index.html
├── ...
├── .gitlab-ci.yml
├── README.md
# 需要保证应用名称是唯一的
ENV=$3 # 环境区分
PROJECT_NAME=$2 # 应用名称
ASSETS_PUBLIC_PATH=$1 # 应用名称 + 分支名称 / dist
 
if [ $ENV = 'test' ]
then
 
rsync -rzav --delete $ASSETS_PUBLIC_PATH/*.html --rsync-path="mkdir -p ~/front-asserts/$PROJECT_NAME && rsync" roy@192.168.XXX.XXX:~/front-asserts/$PROJECT_NAME
sudo /opt/bin/rsync-to-cdn ./ $ASSETS_PUBLIC_PATH/static
 

elif [ $ENV = 'prd' ]
then
 
mkdir -p $PROJECT_NAME
mv $ASSETS_PUBLIC_PATH/*.html $PROJECT_NAME
sudo /opt/bin/rsync-to-prd ./ $PROJECT_NAME
sudo /opt/bin/rsync-to-cdn ./ $ASSETS_PUBLIC_PATH/static
 
fi
 
# 脚本使用说明:
# sudo /opt/bin/rsync-to-prd dir1 dir2
# dir1和dir2组合其实是用来定位当前资源路径的,而最终对外输出的路径依赖于dir2。
# example: sudo /opt/bin/rsync-to-cdn /var/xxx/yyy abc/version1/dist

这个脚本主要做了两件事情。一、把打包出来的html文件发送到托管页面的服务器。二、把dist目录推送到cdn上。 我们可以看到testprd环境的区别在于推送到托管页面的服务器的方式不一样。prd环境的服务器为了安全考虑是不暴露出来的,而是执行跑runner机器上的脚本。

三、配置.gitlab-ci.yml

.gitlab-ci.yml

# test 和 master分支默认支持线上部署
# cache 可根据实际情况加上,建议加上,有利于加快装包的速度
# tag 就是注册runner时填写的tag

stages:
  - build
  - deploy
 
variables:
  # 应用名称(必须保证应用名称的唯一性,否则有可能影响其他应用,注意与打包时的项目名保持一致)
  CI_PROJECT_NAME: projectName
  ASSETS_PUBLIC_PATH: $CI_PROJECT_NAME-$CI_COMMIT_REF_NAME/dist
 
# 安装依赖&&构建打包
build pack:
  stage: build
  cache:
    key: customSetting
    paths:
      - node_modules/
  only:
    - test
    - master
  tags:
    - test-tag
  script:
    - npm install
    - BRANCH=$CI_COMMIT_REF_NAME node build/build.js
    - mkdir -p $ASSETS_PUBLIC_PATH && mv dist/* $ASSETS_PUBLIC_PATH
  artifacts:
    expire_in: 10 min
    name: $CI_PROJECT_NAME
    paths:
      - $ASSETS_PUBLIC_PATH
 
# 测试分支部署到测试环境
deploy test:
  stage: deploy
  only:
    - test
  tags:
    - test-tag
  script:
    - chmod u+x ./bin/deploy.sh
    - ./bin/deploy.sh $ASSETS_PUBLIC_PATH $CI_PROJECT_NAME test
 
# 主分支部署到生产环境
deploy prodcution:
  stage: deploy
  only:
    - master
  tags:
    - test-tag
  script:
    - chmod u+x ./bin/deploy.sh
    - ./bin/deploy.sh $ASSETS_PUBLIC_PATH $CI_PROJECT_NAME prd

四、部署上线

通知运维,配置服务器的nginx。

一、在托管页面的服务器上,我们已经可以看到我们推送上来的文件了。我们需要配置一下nginx来托管这个html。

server {
    listen 8090;
    location / {
            add_header Cache-Control "no-cache";
            root  ~/xxx/xxx;  #该项目的入口页目录位置
            index  index.html;
            try_files $uri $uri/ /index.html;
    }
}

二、nginx反向代理配置

location /example/api/ {

    proxy_set_header   X-Real-IP $remote_addr;

    proxy_set_header   Host      $http_host;

    proxy_pass  http://ip:port; # 所在后端服务的地址

}

location /example/ {

    proxy_set_header   X-Real-IP $remote_addr;

    proxy_set_header   Host      $http_host;

    proxy_pass  http://ip:port; # 上个步骤配置的地址。

}

总结&心得

在一段时间的实践后,我觉得可以把这个过程简单的理解为,有一台机器在我们把代码push到代码仓库的时候,自动帮我们打包并把打包好的内容分发到它应该在的地方。

回过头来,再看一下这张架构图,希望有更深的体会。

gitlab-ci实现部署是一个比较灵活的方案。其中涉及到的内容也比较多。需要了解gitlab-ci相关的内容,服务器相关的一些内容。它可以做的其实远不止这些,我们可以还集成自动化测试、使用docker部署等,让整个流程更加规范,更加完善。