开篇,我们先来看一下远古时代的构建部署流程。想必大家对这个都不陌生:
显然这个流程不仅繁琐,而且效率也不高,开发每次发布都要耗费很长的时间在部署构建上面。
后面为了解决这个问题,就出现了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.0
WORKDIR /usr/app
COPY package*.json ./
RUN npm ci -qy
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
说明一下每个关键字对应的含义。
FROM
基于这个 Image
开始
WORKDIR
设置工作目录
COPY
复制文件
RUN
新层中执行命令
EXPOSE
声明容器监听端口
CMD
容器启动时执行指令默认值
看下项目中的Dockerfile
文件:
# Dockerfile
FROM 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.conf
CMD 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镜像
可以创建多个容器
,它们的关系好比 JavaScript
中类
和实例
的关系。
docker pull <image-name>:<tag>
docker images
docker rmi <image-id>
docker push <username>/<repository>:<tag>
如果
docker images
出现repository
是<none>
的情况,可以运行docker image prune
删除
启动容器: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
首先说下云服务器,既然要一键部署测试机,那么肯定要有台测试机,也就是云服务器,这里我用的是阿里云CentOS 8.4 64位
的操作系统。
有了服务器,那怎么登陆呢?
本地登陆云服务器的方式一般有两种,密码登陆和 ssh
登陆。但是如果采用密码登陆的话,每次都要输入密码,比较麻烦。这里采用ssh
登陆的方式。关于如何免密登录远程服务器,可以参考SSH 免密登陆配置[1]
此后每次登陆都可以通过ssh <username>@<IP>
的方式直接免密登陆了。
接着要给云服务器安装基础包,在CentOS
安装指定包一般用的是yum
,这个不同于npm
。
# 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-ce
sudo 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
就安装成功了!
通过访问 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
来验证是否安装成功:
首先确保可以访问到EPEL库
,通过运行以下命令来安装:
sudo yum install epel-release
现在可以使用yum
命令安装Node.js
了:
sudo yum install nodejs
验证一下:
yum
安装 nginx
非常简单,输入一条命令即可:
$ sudo yum -y install nginx # 安装 nginx
同样也是使用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_dev
on:
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
阶段算是核心了:
洋洋洒洒写了这么多,也不知道你看明白了不
如果有任何问题,欢迎评论区留言,看到后会第一时间解答
后续会有很多关于这个项目的文章,也请大家多多关注~
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/nrDjYBSfAtFYDE0l8OFqrg
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。