开篇,咱们先来看一下远古时代的构建部署流程。想必大家对这个都不生疏:
- 开发将源码通过编译、压缩打包生成打包文件
- 将打包生成的文件上传服务器
显然这个流程不仅繁琐,而且效率也不高,开发每次公布都要消耗很长的工夫在部署构建下面。
前面为了解决这个问题,就呈现了CI/CD
。
接下来咱们来聊一下什么是CI/CD?
CI/CD
是 Continuous Intergration/Continuous Deploy
的简称,翻译过去就是继续集成/继续部署
。CD
也会被解释为继续交付(Continuous Delivery
)
再具体一点就是:
继续集成
:当代码仓库代码产生变更,就会主动对代码进行测试和构建,反馈运行后果。继续交付
:继续交付是在继续集成的根底上,能够将集成后的代码顺次部署到测试环境、预公布环境、生产环境中
聊了这么多,置信很多同学肯定会说:
- 这个别不都是运维搞的吗?
- 和业务也不相干啊,理解它有什么用?
- 全是服务器相干的货色,
docker
、nginx
、云服务器啥的,我该怎么学习呢?
很早之前,我也是这么想的,感觉与本人的业务也没啥关系,没有太大的必要去理解。
然而最近我在搞一个全栈我的项目
(做这个我的项目是为了冲破本人的瓶颈)时,就遇到了这些问题,发现陷入了常识盲区。
没方法,只能一顿恶补。
然而当我通过学习这些常识和在我的项目中实际这些流程后,我在知识面上失去了很大的扩大。对操作系统,对理论的构建部署,甚至对工程化领有了全新的意识。
这里也放下后面提到的全栈我的项目
的架构图吧:
这个大的我的项目以low code
为外围,囊括了编辑器前端
、编辑器后端
、C端H5
、组件库
、组件平台
、后盾管理系统前端
、后盾管理系统后盾
、统计服务
、自研CLI
九大零碎。
其中的编辑器前端
在如何设计实现 H5 营销页面搭建零碎文章中曾经有很具体的阐明。
目前整个我的项目做了 70%左右,过程中遇到了很多问题,也失去了很大的晋升。后续会有一波文章是对于我的项目中的一个个小点开展的,也都是满满的干货。
回到本篇文章的主题:应用Docker Compose、Nginx、SSH和Github Actions实现前端自动化部署测试机
。本文是以后盾管理系统前端
为依靠具体阐明了如何借助Docker
、nginx
、Github CI/CD
能力自动化公布一个纯前端我的项目
。选这个我的项目来解说自动化公布测试机有两个出发点:
- 后盾管理系统业务较简略,可将重心放在自动化部署流程上
- 纯前端我的项目更实用于大部分前端同学现状,拿去即用
整体思路
前端代码,打包进去的是动态文件,可用nginx
做服务。思路:
- 构建一个
Docker
容器(有nginx
) - 将
dist/
目录拷贝到Docker
容器中 - 启动
nginx
服务 - 宿主机端口,对应到
Docker
容器端口中,即可拜访
外围代码变动:
nginx.conf
(给Docker
容器的nginx
应用)Dockerfile
docker-compose.yml
⚠️ 本文将采纳理论知识和理论相结合的形式,即先讲述一下对应知识点,同时会放一下与此知识点相干的我的项目代码或配置文件。
上面会顺次解说Docker
、docker-compose
、ssh
、github actions
等知识点。
Docker
Docker
很早之前,在公众号的一篇文章谁说前端不须要学习 docker?就有过具体阐明。这里简略再论述下。
docker
能够看成是一个高性能的虚拟机,次要用于 linux
环境的虚拟化。开发者能够打包他们的利用以及依赖包到一个可移植的容器中,而后公布到任何风行的 linux
机器上。容器齐全应用沙箱机制,相互之间不会有任何接口。
在容器中你能够做任何服务器能够做的事,例如在有 node
环境的容器中运行 npm run build
打包我的项目,在有 nginx
环境的容器中部署我的项目等等。
在 centos
上装置 docker
因为这次的云服务器是centos
的,所以这里就提一下如何在 centos
上装置 docker
:
$ sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo$ sudo yum install docker-ce docker-ce-cli containerd.io$ sudo systemctl start docker$ sudo docker run hello-world
dockerfile
docker
应用 Dockerfile
作为配置文件进行镜像的构建,简略看一个 node
利用构建的 dockerfile
:
FROM node:12.10.0WORKDIR /usr/appCOPY package*.json ./RUN npm ci -qyCOPY . .EXPOSE 3000CMD ["npm", "start"]
阐明一下每个关键字对应的含意。
FROM
基于这个 Image
开始
WORKDIR
设置工作目录
COPY
复制文件
RUN
新层中执行命令
EXPOSE
申明容器监听端口
CMD
容器启动时执行指令默认值
看下我的项目中的Dockerfile
文件:
# DockerfileFROM nginx# 将 dist 文件中的内容复制到 /usr/share/nginx/html/ 这个目录上面# 所以,之前必须执行 npm run build 来打包出 dist 目录,重要!!!COPY dist/ /usr/share/nginx/html/# 拷贝 nginx 配置文件COPY nginx.conf /etc/nginx/nginx.conf# 设置时区RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone# 创立 /admin-fe-access.log ,对应到 nginx.confCMD touch /admin-fe-access.log && nginx && tail -f /admin-fe-access.log
在这个文件外面,咱们做了上面几件事:
1、咱们用了 Nginx
的 Docker image
作为 base image
。
2、把打包生成的文件夹dist/
的全部内容放进 Nginx Docke
r 的默认 HTML
文件夹,也就是/usr/share/nginx/html
/外面。
3、把自定义的 Nginx
配置文件nginx.conf
放进 Nginx Docker
的配置文件夹/etc/nginx/nginx.conf
中。
4、设置时区。
5、创立 /admin-fe-access.log
,启动nginx
并应用tail -f
模仿相似pm2
的阻塞式过程。
这里提到了nginx.conf
文件:
#nginx过程数,通常设置成和cpu的数量相等worker_processes auto;#全局谬误日志定义类型#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#过程pid文件#pid logs/nginx.pid;#参考事件模型events { #单个过程最大连接数(最大连接数=连接数+过程数) worker_connections 1024;}#设定http服务器http { #文件扩展名与文件类型映射表 include mime.types; #默认文件类型 default_type application/octet-stream; #日志格局设定 #$remote_addr与 $http_x_forwarded_for用以记录客户端的ip地址; #$remote_user:用来记录客户端用户名称; #$time_local: 用来记录拜访工夫与时区; #$request: 用来记录申请的url与http协定; #$status: 用来记录申请状态;胜利是200, #$body_bytes_sent :记录发送给客户端文件主体内容大小; #$http_referer:用来记录从那个页面链接拜访过去的; #$http_user_agent:记录客户浏览器的相干信息; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; #长连贯超时工夫,单位是秒 keepalive_timeout 65; #gzip on; #设定通过nginx上传文件的大小 client_max_body_size 20m; #虚拟主机的配置 server { #监听端口 listen 80; #域名能够有多个,用空格隔开 server_name admin-fe; #charset koi8-r; #定义本虚拟主机的拜访日志 access_log /admin-fe-access.log main; # 留神,在 Dockerfile 中创立 /admin-fe-access.log #入口文件的设置 location / { root /usr/share/nginx/html; #入口文件的所在目录 index index.html index.htm; #默认入口文件名称 try_files $uri $uri/ /index.html; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }}
外围点就是监听80
端口,定义日志文件为admin-fe-access.log
,入口文件根目录为/usr/share/nginx/html
,这些都是与Dockerfile
中一一对应的。
说完了Dockerfile
及其相干的配置文件,上面接着来看下docker
中几个外围的概念。
docker 外围概念
docker
中有三个十分重要的概念:
- 镜像(image)
- 容器(container)
- 仓库(repository)
一张图来表明其中的关系:
如果把容器比作轻量的服务器,那么镜像就是创立它的模版,一个 docker镜像
能够创立多个容器
,它们的关系好比 JavaScript
中类
和实例
的关系。
镜像(image)常用命令:
- 下载镜像:
docker pull <image-name>:<tag>
- 查看所有镜像:
docker images
- 删除镜像:
docker rmi <image-id>
- 上传镜像:
docker push <username>/<repository>:<tag>
如果docker images
呈现repository
是<none>
的状况,能够运行docker image prune
删除
容器(container)常用命令
启动容器:
docker run -p xxx:xxx -v=hostPath:containerPath -d --name <container-name> <image-name>
- -p 端口映射
- -v 数据卷,文件映射
- -d 后盾运行
- --name 定义容器名称
- 查看所有容器:
docker ps
(加-a
显示暗藏的容器) - 进行容器:
docker stop <container-id>
- 删除容器:
docker rm <container-id>
(加-f
强制删除) - 查看容器信息(如 IP 地址等):
docker inspect <container-id>
- 查看容器日志:
docker logs <container-id>
- 进入容器控制台:
docker exec -it <container-id> /bin/sh
镜像构建实现后,能够很容易的在以后宿主上运行,然而, 如果须要在其它服务器上应用这个镜像,咱们就须要一个集中的存储、散发镜像的服务,Docker Registry
就是这样的服务。
一个 Docker Registry
中能够蕴含多个仓库(Repository
);每个仓库能够蕴含多个标签(Tag
);每个标签对应一个镜像。所以说:镜像仓库是 Docker
用来集中寄存镜像文件的中央,相似于咱们之前罕用的代码仓库。
docker-compose
docker-compose
我的项目是Docker
官网的开源我的项目,负责实现对Docker
容器集群的疾速编排。容许用户通过一个独自的docker-compose.yml
模板文件(YAML 格局)来定义一组相关联的利用容器为一个我的项目(project
)。
应用 compose
的最大长处是你只需在一个文件中定义本人的应用程序栈(即应用程序须要用到的所有服务),而后把这个 YAML
文件放在我的项目的根目录下,与源码一起受版本控制。其他人只需 clone
你的我的项目源码之后就能够疾速启动服务。
通常实用于我的项目所需运行环境(对应多个docker
容器)较多的场景,例如同时依赖于nodejs
、mysql
、mongodb
、redis
等。
这里放下docker-compose.yml
文件:
version: '3'services: admin-fe: build: context: . dockerfile: Dockerfile image: admin-fe # 援用官网 nginx 镜像 container_name: admin-fe ports: - 8085:80 # 宿主机能够用 127.0.0.1:8085 即可连贯容器中的数据库
基于上文的Dockerfile
创立镜像,端口映射是8085:80
,这里的8085
是宿主机端口,80
对应的是nginx
裸露的 80 端口
常用命令
- 构建容器:
docker-compose build <service-name>
- 启动所有服务器:
docker-compose up -d
(后盾启动) - 进行所有服务:
docker-compose down
- 查看服务:
docker-compose ps
ssh 及云服务器
首先说下云服务器,既然要一键部署测试机,那么必定要有台测试机,也就是云服务器,这里我用的是阿里云CentOS 8.4 64位
的操作系统。
有了服务器,那怎么登陆呢?
本地登陆云服务器的形式个别有两种,明码登陆和 ssh
登陆。然而如果采纳明码登陆的话,每次都要输出明码,比拟麻烦。这里采纳ssh
登陆的形式。对于如何免密登录近程服务器,能够参考SSH 免密登陆配置
尔后每次登陆都能够通过ssh <username>@<IP>
的形式间接免密登陆了。
云服务器装置指定包
接着要给云服务器装置根底包,在CentOS
装置指定包个别用的是yum
,这个不同于npm
。
docker
# Step 1: 卸载旧版本sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine# Step 2: 装置必要的一些零碎工具sudo yum install -y yum-utils# Step 3: 增加软件源信息,应用阿里云镜像sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo# Step 4: 装置 docker-cesudo yum install docker-ce docker-ce-cli containerd.io# Step 5: 开启 docker服务sudo systemctl start docker# Step 6: 运行 hello-world 我的项目sudo docker run hello-world
如果你像我一样,有Hello from Docker!
的话那么Docker
就装置胜利了!
docker-compose
通过拜访 https://github.com/docker/compose/releases/latest
失去最新的 docker-compose
版本(例如:1.27.4
),而后执行一下命令装置 docker-compose
# 下载最新版本的 docker-compose 到 /usr/bin 目录下curl -L https://github.com/docker/compose/releases/download/1.27.4/docker-compose-`uname -s`-`uname -m` -o /usr/bin/docker-compose# 给 docker-compose 受权chmod +x /usr/bin/docker-compose
装置完,命令行输出docker-compose version
来验证是否装置胜利:
node
首先确保能够拜访到EPEL库
,通过运行以下命令来装置:
sudo yum install epel-release
当初能够应用yum
命令装置Node.js
了:
sudo yum install nodejs
验证一下:
nginx
yum
装置 nginx
非常简单,输出一条命令即可:
$ sudo yum -y install nginx # 装置 nginx
git
同样也是应用yum
来装置:
yum install git
最初来看一下github actions
,也是串联起了下面提到的各个点。
github actions
大家晓得,继续集成由很多操作组成,比方拉取代码、执行测试用例、登录近程服务器,公布到第三方服务等等。GitHub
把这些操作就称为 actions
。
咱们先来理解一下一些术语
:
workflow
(工作流程):继续集成一次运行的过程,就是一个 workflow。job
(工作):一个 workflow 由一个或多个 jobs 形成,含意是一次继续集成的运行,能够实现多个工作。step
(步骤):每个 job 由多个 step 形成,一步步实现。action
(动作):每个 step 能够顺次执行一个或多个命令(action)。
workflow
文件
GitHub Actions
的配置文件叫做 workflow
文件,寄存在代码仓库的.github/workflows
目录。
workflow
文件采纳YAML
格局,文件名能够任意取,然而后缀名对立为.yml
,比方deploy.yml
。一个库能够有多个workflow
文件。GitHub
只有发现.github/workflows
目录外面有.yml
文件,就会主动运行该文件。
workflow
文件的配置字段十分多,这里列举一些根本字段。
name
name
字段是 workflow
的名称。
如果省略该字段,默认为以后 workflow
的文件名。
name: deploy for feature_dev
on
on
字段指定触发 workflow
的条件,通常是push
、pull_request
。
指定触发事件时,能够限定分支或标签。
on: push: branches: - master
下面代码指定,只有master
分支产生push
事件时,才会触发 workflow
。
jobs
jobs
字段,示意要执行的一项或多项工作。其中的runs-on
字段指定运行所须要的虚拟机环境。
runs-on: ubuntu-latest
steps
steps
字段指定每个 Job
的运行步骤,能够蕴含一个或多个步骤。每个步骤都能够指定以下三个字段。
jobs.<job_id>.steps.name
:步骤名称。jobs.<job_id>.steps.run
:该步骤运行的命令或者 action。jobs.<job_id>.steps.env
:该步骤所需的环境变量。
上面放一下我的项目中的.github/workflows/deploy-dev.yml
文件:
name: deploy for feature_devon: push: branches: - 'feature_dev' paths: - '.github/workflows/*' - '__test__/**' - 'src/**' - 'config/*' - 'Dockerfile' - 'docker-compose.yml' - 'nginx.conf'jobs: deploy-dev: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Use Node.js uses: actions/setup-node@v1 with: node-version: 14 - name: lint and test # 测试 run: | npm i npm run lint npm run test:local - name: set ssh key # 长期设置 ssh key run: | mkdir -p ~/.ssh/ echo "${{secrets.COSEN_ID_RSA}}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa ssh-keyscan "106.xx.xx.xx" >> ~/.ssh/known_hosts - name: deploy run: | ssh work@106.xx.xx.xx " cd /home/work/choba-lego/admin-fe; git remote add origin https://Cosen95:${{secrets.COSEN_TOKEN}}@github.com/Choba-lego/admin-fe.git; git checkout feature_dev; git config pull.rebase false; git pull origin feature_dev; git remote remove origin; # 构建 prd-dev # npm i; # npm run build-dev; # 启动 docker docker-compose build admin-fe; # 和 docker-compose.yml service 名字统一 docker-compose up -d; " - name: delete ssh key run: rm -rf ~/.ssh/id_rsa
这里概述一下:
1️ 整个流程在代码push
到feature_dev
分支时触发。
2️ 只有一个job
,运行在虚拟机环境ubuntu-latest
。
3️ 第一步应用的是最根底的action
,即actions/checkout@v2
,它的作用就是让咱们的workflow
能够拜访到咱们的repo
。
4️ 第二步是在执行工作流的机器中装置node
,这里应用的action
是actions/setup-node@v1
。
5️ 第三步是执行lint
和test
。
6️ 第四步是长期设置 ssh key
,这也是为了下一步登录服务器做筹备。
7️ 第五步是部署,这外面先是ssh
登录服务器,拉取了最新分支代码,而后装置依赖、打包,最初启动docker
,生成镜像。到这里测试机上就有了Docker
服务。
8️ 最初一步是删除ssh key
。
最初来github
看一下残缺的流程:
其中deploy
阶段算是外围了:
总结
洋洋洒洒写了这么多,也不晓得你看明确了不
如果有任何问题,欢送评论区留言,看到后会第一工夫解答
后续会有很多对于这个我的项目的文章,也请大家多多关注~