前端工程化之jenkins部署

前端 0 1065 0
发表于: 2022-05-01 02:42:38

简介: 极大提高构建部署效率

注意

本文内容涉及较多,主要是记录给自己备忘,其中交杂了不同时期的修改,可能有的内容会和图片对不上。

jenkins

一开始只有一个博客项目,因此没有很体会到统一部署的优势,随着项目逐渐多了起来后,发现如果还是用传统方式(即本地打包,然后把打包好的静态文件上传到线上的服务器)的话,虽然过程不难,但是重复的步骤非常繁琐,因此决定使用Jenkins进行同一的构建部署。

旧的流程

因为之前只有一个项目,因此需要考虑的东西很少,流程也很简单:

本地开发 —> 本地构建 —> 上传文件到服务器 —> ok

新的流程

如果项目一旦变多了,那么要考虑的东西就多了,首先,项目多了,如果每个项目注册一个不同的域名,显然会增加很多成本,因此这里采用子域名+子路径的做法,以我申请的域名hsslive.cn举个例子:

域名

博客作为主要的项目,放在了 www.hsslive.cn 这个里面。

而其他项目作为非主要项目,因此在域名解析里额外添加了 project.hsslive.cn 这条解析记录,其他的项目都放这里面。

nginx

server {
    listen 80;
    server_name www.hsslive.cn;

    location / {
        # 把当前域名的请求,跳转到新域名上,域名变化但路径不变,permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
        rewrite ^/(.*) https://www.hsslive.cn/$1 permanent;
    }

}
server {
    listen 80;
    server_name project.hsslive.cn;

    # 开启gzip,关闭用off
    gzip on;
    # 选择压缩的文件类型,其值可以在 mime.types 文件中找到。
    gzip_types text/plain text/css application/json application/javascript
    # 是否在http header中添加Vary: Accept-Encoding,建议开启
    gzip_vary on;
    # gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,推荐6
    gzip_comp_level 6;

    location / {
        # project.hsslive.cn/,会请求到服务器的/node/index.html
        root /node/;
        index index.html index.htm;
    }
  
    # 匹配/xxx/,注意,前后都有/才能匹配到,匹配不了/xxx
    location ~* ^\/([^\/]+)\/ {
        # 请求project.hsslive.cn/xxx/,会请求到服务器的/node/xxx/index.html
        root /node/;
        try_files $uri /$1/index.html; #在project.hsslive.cn/xxx/报404会重新匹配project.hsslive.cn/xxx/index.html
    }
}

nginx里的project.hsslive.cn匹配规则即:

http://project.hsslive.cn —> 访问:/node/index.html
http://project.hsslive.cn/billd-ui/ —> 访问:/node/billd-ui/index.html
http://project.hsslive.cn/react17-webpack5-template/ —> 访问:/node/react17-webpack5-template/index.html
http://project.hsslive.cn/vue3-webpack5-template/ —> 访问:/node/vue3-webpack5-template/index.html
http://project.hsslive.cn/overview/ —> 访问:/node/overview/index.html
http://project.hsslive.cn/netease-cloud-music/ —> 访问:/node/netease-cloud-music/index.html

jenkins

我们希望除了开发是在本地,其余所有操作都在线上进行,仅此,还需要一个git远程仓库,用于存放我们本地开发好的代码,这里我使用的是gitee(不用github是因为github经常443)。

既然使用了jenkins进行构建,那么就用它更好的服务我们吧,之前都是部署项目到线上地址就可以了,现在我们可以增加环境的概念,因为对于前端来说,我们最终访问的其实都是静态资源(单纯的客户端渲染),所以我们只需要把构建出不同环境的代码,放到不同的位置进行托管,这样就可以实现前端区分环境了。

修改nginx

server {
    listen 80;
    server_name www.hsslive.cn;

    location / {
        # 把当前域名的请求,跳转到新域名上,域名变化但路径不变,permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
        rewrite ^/(.*) https://www.hsslive.cn/$1 permanent;
    }

}
server {
    listen 80;
    server_name project.hsslive.cn;

    # 开启gzip,关闭用off
    gzip on;
    # 选择压缩的文件类型,其值可以在 mime.types 文件中找到。
    gzip_types text/plain text/css application/json application/javascript
    # 是否在http header中添加Vary: Accept-Encoding,建议开启
    gzip_vary on;
    # gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,推荐6
    gzip_comp_level 6;

    location / {
        # project.hsslive.cn/,会请求到服务器的/node/index.html
        root /node/;
        index index.html index.htm;
    }
  
    # 匹配/xxx/,注意,前后都有/才能匹配到,匹配不了/xxx
    # location ~* ^\/([^\/]+)\/ {
    #     # 请求localhost/xxx/,会请求到服务器的/node/xxx/index.html
    #     root /node/;
    #     try_files $uri /$1/index.html;
    # }
  
    # 匹配/xxx/ddd/,注意,前后都有/才能匹配到,匹配不了/xxx/ddd
    location ~* ^\/(.+)\/ {
        # 请求localhost/xxx/ddd/,会请求到服务器的/node/xxx/ddd/index.html
        root /node/;
        try_files $uri /$1/index.html;
    }
}

修改后的nginx里的project.hsslive.cn匹配规则,除了能实现之前的:http://project.hsslive.cn/billd-ui/ —> 访问:/node/billd-ui/index.html,还能实现:

http://project.hsslive.cn/multi-env-project/prod/ —> /multi-env-project/prod/index.html

http://project.hsslive.cn/multi-env-project/preview/ —> /multi-env-project/preview/index.html

http://project.hsslive.cn/multi-env-project/beta/ —> /multi-env-project/beta/index.html

安装jenkins

具体流程自行百度。

jenkins任务

安装完成后,启动jenkins,默认jenkins是运行在服务器的8080端口的,打开浏览器,地址栏输入服务器ip+:8080,即可访问jenkins,首次进入需要找到默认的密码,输入后选中安装常用的插件,然后创建用户登录即可:

jenkins1.png

jenkins2.png

jenkins3.png

登录进去后,首先新建一个item(任务):

jenkins4.png

输入一个任务名称,然后选中第一个风格,确定

jenkins5.png

填一下描述:

jenkins6.png

源码管理选则git,然后填上仓库地址,分支暂时保留默认的master(后面会根据分支实现区分环境~)

jenkins7.png

这里的用户名和密码填你的gitee登录用户名和登录密码,这里其实有个坑,举个例子:

  • 我的gitee主页是gitee.com/galaxy-s10 ,但是我gitee是叫shuisheng,jenkins的gitee用户名是gitee.com/galaxy-s10 里的galaxy-s10,而不是shuisheng
  • 我的github主页是github.com/galaxy-s10 ,但是我github是叫shuisheng,jenkins的github用户名就是shuisheng,而不是github.com/galaxy-s10 里的galaxy-s10…
  • 而且建议大家都用gitee,因为用github的话,拉代码太慢了,基本80%构建都是构建失败(拉代码卡住了导致的网络超时)

jenkins8.png

然后继续往下,构建 - 增加构建步骤,选择execute shell

jenkins9.png

echo 当前路径: $(pwd)

echo 远程 URL(GIT_URL): $GIT_URL

echo 被检出的提交哈希(GIT_COMMIT): $GIT_COMMIT

echo 远程分支名称(GIT_BRANCH): $GIT_BRANCH

echo 分支名(BRANCH_NAME): $BRANCH_NAME

echo 此构建的项目名称(JOB_NAME): $JOB_NAME

echo 当前项目工作空间的绝对路径(WORKSPACE): $WORKSPACE

echo 当前构建的分支: $BRANCH

echo 当前node版本:

node -v

echo 当前npm版本:

npm -v

echo 开始执行构建脚本:

sh ./build.sh $JOB_NAME null $WORKSPACE

echo 列出当前目录:

ls

ps: 这里面的$变量都是jenkins提供的环境变量~,然后关键是sh ./build.sh,这个命令执行了项目里面的构建脚本!

build.sh:

#!/usr/bin/env bash
###
# Author: shuisheng
# Email: 2274751790@qq.com
# Github: https://github.com/galaxy-s10
# Date: 2022-01-03 16:12:54
# LastEditTime: 2022-05-04 01:50:52
# Description:https://github.com/galaxy-s10
###

# 约定$1为任务名, $2为环境, $3为Jenkins工作区
JOBNAME=$1 # 注意: JOBNAME=$1,这个等号左右不能有空格!
ENV=$2
WORKSPACE=$3
PUBLICDIR=/node

echo 删除node_modules:
rm -rf node_modules

echo 查看npm版本:
npm -v

echo 设置npm淘宝镜像:
npm config set registry http://registry.npm.taobao.org/

echo 查看当前npm镜像:
npm get registry

if ! type yarn >/dev/null 2>&1; then
  echo 'yarn未安装,先全局安装yarn'
  npm i yarn -g
else
  echo 'yarn已安装'
fi

echo 查看yarn版本:
yarn -v

echo 设置yarn淘宝镜像:
yarn config set registry https://registry.npm.taobao.org

echo 查看当前yarn镜像:
yarn config get registry

echo 开始安装依赖:
yarn install

if [ $ENV = 'beta' ]; then
  echo 开始构建测试环境:
elif [ $ENV = 'preview' ]; then
  echo 开始构建预发布环境:
elif [ $ENV = 'prod' ]; then
  echo 开始构建正式环境:
else
  echo 开始构建$ENV环境:
fi

npx cross-env REACT_APP_RELEASE_PROJECT_NAME=$JOBNAME REACT_APP_RELEASE_PROJECT_ENV=$ENV webpack --config ./config/webpack.common.ts --env production

最后点击保存,就可以进行构建了!

jenkins10.png

点击Build Now,可以看到下面的有构建进度条,构建成功后,可在工作空间里面查看当前项目的文件

jenkins11.png

还可以点击构建的进度条,进去看控制台输出:

jenkins12.png

jenkins13.png

我们可以看到,毫无疑问,jenkins在拉完代码下来后,执行了项目里面的build.sh构建脚本,因此,在工作空间里面也看到了有打包后的dist这个目录。现在的dist是放在jenkins的工作目录里面的,我们不希望把它放到这里面,我们把jenkins里所有的前端项目都统一放到一个地方,这样方便维护,也好为后面的nginx做铺垫~,那么该咋办,怎样才能把构建的dist放到我希望的地方,而这个地方也不是随便的一个地方,如果是大公司的话,应该是构建完成后,把文件都放到cdn服务器上面托管起来的,我这没有cdn服务器,就把自己的服务器当做cdn服务器来模拟这个操作了哈哈哈~

模拟cdn服务器

首先,我们需要一个jenkins插件:Publish Over SSH,通过ssh连接到cdn服务器(我自己的服务器),直接到jenkins的插件管理里面下载完这个插件然后重启jenkins:

jenkins14.png

下载完成后,配置一下自己的ssh

jenkins15.png

配置完成后,再回到任务里面,点击配置,在构建里面再配置多一个Send build xxxxxx SSH:

jenkins16.png

选中刚刚配置的ssh,然后连上了ssh要干啥,又回到之前的问题,构建好的文件都要放哪里,我这里就定了一个规则:所有项目都放在服务器的/noode/目录里面,比如vueblog-admin,就放到/node/vueblog-admin里面,reactblog-admin就放在/node/reactblog-admin里面!那么现在构建好的文件放在哪里的问题定下来了,那么我要怎么按照我的规则把构建好的文件放到指定位置呢,没错,还得是shell哈哈哈~~

jenkins17.png

为了让所有文件都清晰一目了然,我把构建的脚本也放到了/node/里面了,在服务器的/node/目录新建一个sh文件夹,里面新建一个frontend.sh文件,然后执行这个shell的时候,传了两个参数,$JOB_NAME是当前的任务名,即:vueblog-admin,$WORKSPACE是项目当前的工作目录(也就是说dist在这个目录里面),可以翻上面的有一张控制台输出的图片看看,其实就是在服务器的/var/lib/jenkins/workspace/vueblog-admin目录~

sh /node/sh/frontend.sh $JOB_NAME $ENV $WORKSPACE

/node/sh/frontend.sh的脚本如下:

#!/usr/bin/env bash
###
# Author: shuisheng
# Email: 2274751790@qq.com
# Github: https://github.com/galaxy-s10
# Date: 2022-01-10 10:56:03
# LastEditTime: 2022-01-16 03:56:26
# Description: 前端通用构建脚本
###

# 约定$1为任务名, $2为环境, $3为Jenkins工作区
JOBNAME=$1 # 注意: JOBNAME=$1,这个等号左右不能有空格!
ENV=$2
WORKSPACE=$3
PUBLICDIR=/node

if [ -d $PUBLICDIR/$JOBNAME ]; then
    echo "$PUBLICDIR/$JOBNAME/目录已经存在,先删除它,然后再重新创建它"
    rm -rf $PUBLICDIR/$JOBNAME/
    mkdir -p $PUBLICDIR/$JOBNAME/
    cp -r $WORKSPACE/dist/* $PUBLICDIR/$JOBNAME/
else
    echo "$PUBLICDIR/$JOBNAME/目录还没有,创建它"
    mkdir -p $PUBLICDIR/$JOBNAME/
    cp -r $WORKSPACE/dist/* $PUBLICDIR/$JOBNAME/
fi

这个脚本其实就做了一件事,就是在/node/目录里面,把jenkins的任务名作为文件夹名,并且新建到/node/里面,然后/node/里面就要vueblog-admin这个文件夹了,再把jenkins的vueblog-admin的工作区里面的dist里面的所有文件复制到/node/vueblog-admin里面,下面让我们试下配置后的构建结果:

jenkins18.png

控制台看到是连接了ssh,那么再到服务器的/node目录下看看是不是真的有vueblog-admin这个文件夹,以及里面是不是真的有dist的文件了

jenkins19.png

结果当前是都有,此时jenkins构建的流程结束!

区分环境

这里我们假设一个项目有三个环境:prod,preview,beta,然后我们希望可以把代码构建出不同的环境,那么总不可能只有一个master分支,然后根据改master分支的代码然后构建不同的环境,所以可以通过新增preview和beta分支,然后需要限制一下:master分支可以构建所有环境(prod,preview,beta),而非master分支只能构建preview和beta环境。

首先在jenkins管理插件里面安装一个Active Choices插件,安装完成后开始下面的步骤:

首先在general里面找到This project is parameterized,然后勾选上,勾选上后,原本的之前的Build Now就会变成Build with Parameters,可以选择我们配置的参数进行构建。然后点击添加参数:Choice Parameter,

image.png
输入以下内容:

image.png
这样的话就会在构建就会多一个下拉列表让我们选择prod,preview,beta环境,那么我们如何让我们选择的环境和我们要构建的分支对应上呢,其实只需要改一下之前的地方分支就行了:

image.png

改完之后,就可以做到我们选什么分支,就会使用什么分支进行构建了,接下来的设置环境也是一样的操作,但是如果我们还是使用Choice Parameter的话,就做不到之前说的限制了(只有master分支才可以构建所以环境),因此我们得使用另一个参数:Active Choices Reactive Parameter

image.png

image.png

image.png

这里涉及了一些Groovy Script,大概意思就是,当BRANCH选择的是master,则可以构建"null",“beta”,“preview”,“prod"其中的一个环境,如果BRANCH选择的不是master,则只能构建"null”,“beta”,"preview"其中的一个环境。

改完之后,还需要改一下/node/sh/frontend.sh,jenkins的execute shell,还有连接ssh后执行的脚本

连接ssh后执行的脚本:

sh /node/sh/frontend.sh $JOB_NAME $ENV $WORKSPACE

image.png

jenkins的execute shell:

echo 当前路径: $(pwd)

echo 远程 URL(GIT_URL): $GIT_URL

echo 被检出的提交哈希(GIT_COMMIT): $GIT_COMMIT

echo 远程分支名称(GIT_BRANCH): $GIT_BRANCH

echo 分支名(BRANCH_NAME): $BRANCH_NAME

echo 此构建的项目名称(JOB_NAME): $JOB_NAME

echo 当前项目工作空间的绝对路径(WORKSPACE): $WORKSPACE

echo 当前构建的分支: $BRANCH

echo 当前发布的环境: $ENV

echo 当前node版本:

node -v

echo 当前npm版本:

npm -v

echo 开始执行构建脚本:

sh ./build.sh $JOB_NAME $ENV $WORKSPACE

echo 列出当前目录:

ls

/node/sh/frontend.sh:

#!/usr/bin/env bash
###
# Author: shuisheng
# Email: 2274751790@qq.com
# Github: https://github.com/galaxy-s10
# Date: 2022-01-10 10:56:03
# LastEditTime: 2022-01-16 03:56:26
# Description: 前端通用构建脚本
###

# 约定$1为任务名, $2为环境, $3为Jenkins工作区
JOBNAME=$1 # 注意: JOBNAME=$1,这个等号左右不能有空格!
ENV=$2
WORKSPACE=$3
PUBLICDIR=/node

if [ $ENV != 'null' ]; then
    echo "当前环境:$ENV"
    if [ -d $PUBLICDIR/$JOBNAME/$ENV ]; then
        echo "$PUBLICDIR/$JOBNAME/$ENV/目录已经存在,先删除它,然后再重新创建它"
        rm -rf $PUBLICDIR/$JOBNAME/$ENV/
        mkdir -p $PUBLICDIR/$JOBNAME/$ENV/
        cp -r $WORKSPACE/dist/* $PUBLICDIR/$JOBNAME/$ENV/
    else
        echo "$PUBLICDIR/$JOBNAME/$ENV/目录还没有,创建它"
        mkdir -p $PUBLICDIR/$JOBNAME/$ENV/
        cp -r $WORKSPACE/dist/* $PUBLICDIR/$JOBNAME/$ENV/
    fi
else
    echo "当前环境是null"
    if [ -d $PUBLICDIR/$JOBNAME ]; then
        echo "$PUBLICDIR/$JOBNAME/目录已经存在,先删除它,然后再重新创建它"
        rm -rf $PUBLICDIR/$JOBNAME/
        mkdir -p $PUBLICDIR/$JOBNAME/
        cp -r $WORKSPACE/dist/* $PUBLICDIR/$JOBNAME/
    else
        echo "$PUBLICDIR/$JOBNAME/目录还没有,创建它"
        mkdir -p $PUBLICDIR/$JOBNAME/
        cp -r $WORKSPACE/dist/* $PUBLICDIR/$JOBNAME/
    fi
fi

至此,多环境也已经完成,看看最终的Build with Parameters:

image.png

image.png

参考

https://juejin.cn/post/7052001096348205093/

CI/CD nginx

最后更新于:2022-05-04 04:26:06

欢迎评论留言~
0/400
支持markdown
Comments | 0 条留言
按时间
按热度
目前还没有人留言~