前端部署相关

CICD
CI: Continuous Integration,持续集成
CD: Continuous Deployment,持续部署
从开发、测试到上线的过程中,借助于 CICD 进行一些自动化处理,保障项目质量。
CICD 与 git 集成在一起,可理解为服务器端的 git hooks: 当代码 push 到远程仓库后,借助 WebHooks 对当前代码在构建服务器(即 CI 服务器,也称作 Runner)中进行自动构建、测试及部署等。
CICD 的好处
分支提交后,执行自动化测试、语法检查,如未通过则阻止合并和上线
分支提交后,可以检查 npm 库的风险和构建镜像容器的风险
可以对每一个功能分支生成一个可供测试的地址,例如
<branch>.dev.technolegy.com功能分支测试通过后,合并到主分支,自动构建镜像并部署到生产环境(生产环境一般需要手动触发部署)

由于近些年来 CICD 的全面介入,项目开发的工作流就是 CICD 的工作流,以下是一个比较完善的 CICD Workflow。

CICD 的相关工具
CICD 集成于 CICD 工具及代码托管服务。CICD 有时也可理解为进行 CICD 的构建服务器,而提供 CICD 的服务,如以下产品,将会提供构建服务与 github/gitlab 集成在一起。
jenkins
Travis CI
个人用户还可以使用 github 提供的免费服务github actions(每个月 2000 分钟额度)
企业一般是自建gitlab Runner作为构建服务器
配置示例
deploy:
stage: deploy
only:
- master
script:
- docker build -t wwwroot/fe/devtools-app
- docker push wwwroot/fe/devtools-app
- helm upgrade -install devtools-app-chart .deploy:
stage: deploy
only:
- master
script:
- docker build -t wwwroot/fe/devtools-app
- docker push wwwroot/fe/devtools-app
- helm upgrade -install devtools-app-chart .git hooks
git 允许在各种操作之前添加一些 hook 脚本,如未正常运行则 git 操作不通过。最出名的还是以下两个
precommitprepush
hook 脚本置于目录 ~/.git/hooks 中,以可执行文件的形式存在
$ ls -lah .git/hooks
applypatch-msg.sample pre-merge-commit.sample
commit-msg.sample pre-push.sample
fsmonitor-watchman.sample pre-rebase.sample
post-update.sample pre-receive.sample
pre-applypatch.sample prepare-commit-msg.sample
pre-commit.sample update.sample$ ls -lah .git/hooks
applypatch-msg.sample pre-merge-commit.sample
commit-msg.sample pre-push.sample
fsmonitor-watchman.sample pre-rebase.sample
post-update.sample pre-receive.sample
pre-applypatch.sample prepare-commit-msg.sample
pre-commit.sample update.sample另外 git hooks 可使用 core.hooksPath 自定义脚本位置。
# 可通过命令行配置 core.hooksPath
$ git config 'core.hooksPath' .husky
# 也可通过写入文件配置 core.hooksPath
$ cat .git/config
[core]
ignorecase = true
precomposeunicode = true
hooksPath = .husky# 可通过命令行配置 core.hooksPath
$ git config 'core.hooksPath' .husky
# 也可通过写入文件配置 core.hooksPath
$ cat .git/config
[core]
ignorecase = true
precomposeunicode = true
hooksPath = .huskyhusky可以通过自定义core.hooksPath,将npm scripts写入其中的方式来实现功能。
~/.husky 目录下手动创建 hook 脚本。
# 手动创建 pre-commit hook
$ vim .husky/pre-commit# 手动创建 pre-commit hook
$ vim .husky/pre-commit在 pre-commit 中进行代码风格校验
#!/bin/sh
npm run lint
npm run test#!/bin/sh
npm run lint
npm run testAudit
译为审计,用于检查所有依赖是否安全,通过npm audit和yarn audit启动。
通过审计可以发现有风险的包,依赖库的依赖链,风险原因及解决方案。
# 审计生产风险
npm audit production
yarn audit dependencies
# 修复风险,原理就是升级依赖库,升级至已修复了风险的版本号
npm audit fix# 审计生产风险
npm audit production
yarn audit dependencies
# 修复风险,原理就是升级依赖库,升级至已修复了风险的版本号
npm audit fixsynk是个高级版的npm audit,可以自动修复

Docker
使用docker部署前端的最大好处是隔离环境,比如下面几种情况
前端项目依赖于 Node v16,而宿主机无法满足依赖,使用容器满足需求
前端项目依赖于 npm v8,而宿主机无法满足依赖,使用容器满足需求
前端项目需要将 8080 端口暴露出来,而容易与宿主机其它服务冲突,使用容器与服务发现满足需求
docker部署的基本流程
CICD 生成 docker 镜像 -> 上传到 DockerHub -> 服务器从 DockerHub 下载最新版本的镜像 -> 通过镜像启动容器,同时映射端口号和配置对应的 nginx
生成 Docker 镜像
一个能生成镜像的 Dockerfile 如下:
# 指定 node 版本号,满足宿主环境
FROM node:16-alpine
# 指定工作目录,将代码添加至此
WORKDIR /code
ADD . /code
# 在镜像中安装依赖并将项目跑起来
RUN npm install
RUN npm run build
CMD npm start
# 暴露出运行的端口号,可对外接入服务发现
EXPOSE 8080# 指定 node 版本号,满足宿主环境
FROM node:16-alpine
# 指定工作目录,将代码添加至此
WORKDIR /code
ADD . /code
# 在镜像中安装依赖并将项目跑起来
RUN npm install
RUN npm run build
CMD npm start
# 暴露出运行的端口号,可对外接入服务发现
EXPOSE 8080# 构建镜像
$ docker build -t fe-app .
# 运行容器
$ docker run -it --rm fe-app# 构建镜像
$ docker build -t fe-app .
# 运行容器
$ docker run -it --rm fe-app但是上述流程还有优化空间,主要体现在以下几方面
使用
node:16作为基础镜像过于奢侈,占用体积太大,而最终产物 (js/css/html) 无需依赖该镜像。可使用更小的nginx镜像做多阶段构建。多个
RUN命令,不利于Docker的镜像分层存储。可合并为一个RUN命令每次都需要
npm i,可合理利用Docker缓存,ADD命令中内容发生改变将会破坏缓存。可将package.json提前移至目标目录,只要package.json/lockfile不发生变动,将不会重新npm i
优化后如下
FROM node:16-alpine as builder
WORKDIR /code
ADD package.json package-lock.json /code/
RUN npm install
ADD . /code
RUN npm run build
# 选择更小体积的基础镜像
FROM nginx:alpine
# 将构建产物移至 nginx 中
COPY --from=builder code/build/ /usr/share/nginx/html/FROM node:16-alpine as builder
WORKDIR /code
ADD package.json package-lock.json /code/
RUN npm install
ADD . /code
RUN npm run build
# 选择更小体积的基础镜像
FROM nginx:alpine
# 将构建产物移至 nginx 中
COPY --from=builder code/build/ /usr/share/nginx/html/对分支环境进行部署
这是一种基于容器及 docker-compose 或者 k8s 的思路
借用现有的
CICD服务,如github actions或者gitlab CI获取当前分支信息借用
Docker快速部署前端或者后端,根据分支信息启动不同的服务 (Service),根据Docker启动服务并配置响应的标签 (Label)根据容器的标签与当前
GIT分支对前端后端设置不同的域名
下面是一个 Preview 的示例
version: '3'
services:
cra-preview-${COMMIT_REF_NAME}:
build:
context: .
dockerfile: router.Dockerfile
labels:
# 配置域名: Preview
- 'traefik.http.routers.cra-preview-${COMMIT_REF_NAME}.rule=Host(`${COMMIT_REF_NAME}.cra.kevinlau.cn`)'
- traefik.http.routers.cra-preview-${COMMIT_REF_NAME}.tls=true
- traefik.http.routers.cra-preview-${COMMIT_REF_NAME}.tls.certresolver=leversion: '3'
services:
cra-preview-${COMMIT_REF_NAME}:
build:
context: .
dockerfile: router.Dockerfile
labels:
# 配置域名: Preview
- 'traefik.http.routers.cra-preview-${COMMIT_REF_NAME}.rule=Host(`${COMMIT_REF_NAME}.cra.kevinlau.cn`)'
- traefik.http.routers.cra-preview-${COMMIT_REF_NAME}.tls=true
- traefik.http.routers.cra-preview-${COMMIT_REF_NAME}.tls.certresolver=le