前言
本来想弄在一个文章里面,但是因为这边篇幅限制,又涉及到排版和阅读,不得不放在多篇请谅解,全篇两万多字,八万字符,60多张图,其中部分是多图合并的长图,文章的开头和结尾都有相应的前篇和后篇文章导航
建议先看介绍篇,知道大概的内容和流程
开始
这个如火如荼的大前端时代,vue、react、angular 、flutter、electron、小程序等技术框架百家争鸣,这些都是我们前端拿来干架吃饭的武器,前端工程化体系也逐渐向小公司小团队普及,想或者做为一个小小前端团队的leader,了解如何去搭建一个基础的前端工程化体系服务环境,来帮助小团队的提高开发体验和提升工作效率,还是有必要的。
前端工程化体系工作服务环境主要有:CI / CD、npm私有库、api mocker server 等
来,老板我们先来看一下我们要完成的这一套工程化服务的简介图
简介图
东西不多其实就几个
本地开发:编写 eslint 、stylint 和 prettier 规则文件,配合vscode的保存自动格式化,再严格的话加上git hook 来检测(当然如果是项目中途加入规则的话,不建议采用git hook等全代码的格式化功能,团队开发可能会宕机😂)
当我们对特定的分支做 push,或者在仓库执行分支合并更新后,就会触发我们的 CI / CD 服务:去自动构建我们的代码(当然可以加上一些单元测试、代码质量检测等,单页测试教程没有加入哈),构建成功后自动帮我们部署到对应的开发环境、测试环境,预发布环境,部署线上生产环境的话一般是设置手动更新等,当然还需要快速回滚的功能,CI / CD 服务运行的状态最后都要做通知,通过:邮件、钉钉企业微信等,告诉团队或者相关开发人员构建的结果等
知识点大图
CI / CD 流水线
CI 代表持续集成(Continuous Integration),CD 代表持续交付(Continuous Delivery)和持续部署(Continuous Deployment)。也可以将它们看作是类似于软件开发生命周期的过程
简单的说,就是在本地更改代码—>git push推送到代码托管—>自动安装依赖,打包测试部署等(开发环境一般自动,生产环境一般是需要手动点击按钮上线)
说多无益看图
CI / CD 流水线工作图
老实说:test这个阶段暂时是没有做的哈哈哈,不过做小组件库的时候会需要单元测试等,大家知道就好
自动化流程的必要性:避免很多问题,少解决很多冲突,假设你的前端团队有6个人,每个人电脑的系统、node版本,npm版本都有可能不一样,就算是规定统一了,每个人拉取代码源仓库 build 出来的产物也有可能不一样,这样会产生几个问题
- 耗时:每个人都需要去构建
- 易冲突:当git做pull ,merge,push等的时候一不小心就会产生各种不必要的冲突要去解决,非常的耗时和不愉悦
- 缓存失效:构建出来的静态文件的hash不好控制,容易在客户端失去缓存,即使在webpack中设置了contenthash等等优化 例如:一个很大的commit.js,base.js,echat.js vendor.js啊等文件,本来是没有更新的,已经在客户端缓存的了,却在这次更新后hash值莫名奇妙的变化了,再次访问页面后客户端的用户还需要重新去加载它们,浪费资源啊老板
其实这些问题在大公司,人员完善的团队一般不会遇到,因为会有专人负责这方的搭建,但是你知道的嘛,初始的小团队,那种苦只有体验过的才知道 🤣,但是如果你会了,又有点话语权,那这问题就可以迎刃而解了😎
打造自动化构建部署 CI /CD 流水线服务的工具我们这里用的是Jenkins
Jenkins
ci / cd 现在有不少服务,github的GitHub Actions,gitlab 的Gitlab-CI,gitee的Gitee Go,还有travis、Netlify等等,我们用Jenkins,引用官方的话就是:
Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建、部署、自动化, 满足任何项目的需要。
为了方便部署和迁移等,我们要在docker上安装Jenkins
Docker
Docker 是一个开源,轻量级的应用容器引擎,以前我们想在window折腾linux系统,在上面部署应用来测试什么的,我们通常会安装一个虚拟机,在虚拟机上安装操作系统啊,应用什么的,搞垮了可以重新来什么的,不影响主机的系统,不过虚拟机比较重,启动慢,现在我们用docker,相比于虚拟机装操作系统,Docker是使用容器承载应用程序,轻量,高效,方便快捷的部署
Docker 由镜像(Image)、容器(Container)、仓库(Repository) 三部分组成。
镜像(Image)
镜像Image就是相当于安装操作的系统盘,U盘等等,里面可以包含node、gitlab等等,当然也可以包含完整的centos系统,甚至是centos + jenkins的或者centos + verdaccio(npm 私有库)
容器(Container)
**容器(Container)**就是实际上跑应用的地方啦,可以理解为一个个互相隔离的小虚拟机,你的镜像就是安装在这里
仓库(Repository)
仓库(Repository) 用于存放镜像,有点类似的git仓库,docker hub是个公共的仓库,不过在我们这边网速慢,一般把源设置为淘宝源等
后面我们会用几个docker容器分别安装jenkins、verdaccio、yapi等组成一个单机的小小微服务,现在多多少少知道为什么要用docker了吧
Verdaccio
Verdaccio 是一个 Node.js创建的轻量的私有npm proxy registry ,小团队用这个够
Yapi
Yapi这是一个api管理平台,前后端分离的时候,api mock显得格外重要,没有api、mock,团队的朋友得在代码中做一堆测试数据,判断条件什么的,后面等接口开发好再删掉测试的数据,在对接接口重新测试,这可一点都不好玩。现在主要的mock系统有rap2、eolinker,yapi等等,我们这里用yapi,轻量简单功能好,社区活跃star高,需要mongoDB来存数据
MongoDB
MongoDB使用C++语言编写的非关系型数据库。特点是高性能、易部署、易使用,存储数据十分方便。这里我们安装是提供给yapi用
Git 工作流
简单的先说一下我们小团队这里的 git flow,这样好明白我们接下来的 CI / CD 要为我们做什么
代码运行的环境
一般来说,小公司小团队都会有至少这几个环境:
- 本地开发环境:
开发人员自测的,可以是自己本地部署的静态服务器,当然也可类似是运行 npm server类似的环境,本地环境运行的代码可以是任何分支的
- dev开发环境:
这个环境是用开发分支dev产出的代码来部署的,唯一的公用的
- 测试&预发布环境:
这个环境是用开发分支release产出的代码来部署的,唯一的公用的
- 线上生产环境:
这个环境是用开发分支master产出的代码来部署的,唯一的公用的
git 分支模型
先看一下分支的角色功能
分支的策略
dev 是公共的开发分支,不会合并到其他分支去的,7
所有的分支都是基于master分支检出
- master :保护分支,对应的就是生产环境的分支
- release:保护分支,所有开发完成的分支会申请合并到release分支,提供给测试人员测试
- feature-*:功能分支,具体功能开发
- dev:开发分支&脏分支,对应的是大家共用的开发环境,上面的代码会部署到一个公共的开发环境,供开发人员做自测,应付一些日常、非日常的调试
- hotfix-*:bug紧急修复分支,可以直接合并到master,(假如release合并了几个feature分支,正在测试的情况下,发现需要紧急修复的buf,紧急修复测试完毕后,可以直接合并到master,如果合并到release,在由release合并到master,那些正在测试的功能或者还不准备上线的功能就会跟着直接上线了)
工作流程大概是:
- 接到需求文档,做评审后分配个每个人或小组的功能开发,相关人员从master 检出功能分支
- 开发的时候除了会在本地测试,有需要还会合并到dev分支,在公共的开发环境去自己做测试
- 因为在开发功能的期间,可能有hotfix完成合并到master,合并代码的时候习惯merge一下master,防止冲突等
- 自测完成之后,申请合并到release,合并成功后部署到测试环境后通知测试人员做测试
- 测试通过后,release申请合并到master,准备上线
- 如果测试不通过,在功能分支修改后重新merge
- 上线成功稳定后删除对应的功能分支,dev 合并最新的master分支
CI / CD 的工作
当我们本地代码分支合并到dev,push推送到远程git仓库的时候,触发任务自动build->build成功后自动部署发布到dev开发环境
当我们在gitee 申请feature分支,合并到release,成功后,触发任务自动build->build成功后自动部署发布到release测试环境
当我们申请release分支或&hotfix分支合并到master,成功后,触发任务自动build->build成功后通过手动部署发布到正式生产环境(生产环境一般是需要多加一步手动发布,点击个按钮发布等操作)
创建仓库
上面的环境清楚了,先按照上面的新建一个仓库吧
你也可以直接拉去我的这里为你准备的初始化仓库 gitee.com/eric-gm/ci-…
安装准备
系统要求
liunx系统,我用的是:centos8, 因为要安装docker,要求内核版本不低于 3.10 这里我是用两台阿里云服务器,一台用来部署jenkins、verdaccio、yapi等做环境部署机,一台做静态资源的服务器装nginx,环境部署机建议2核4G起步,如果有安装Gitlab等,那可得8G起步了老板,能弄个16G当然也是甚好哈哈哈
当然不管的内网服务器还是云服务器,配置SSH连接能很方便的在本地连接到服务器
创建用户
在centos系统下创建用户,其他系统的老板遇到问题自行百度吧
- 以添加用户名为 longming 的用户为例子,输入命令添加用户、添加用户目录、指定 bash 为 shell
useradd -m -s /bin/bash eric
-m
自动创建用户的家目录,并将/etc/skel
中的文件复制到家目录中
-s
指定用户登入后所使用的 shell
- 然后对该用户设置密码,输入命令后会提示输入两次密码
passwd eric
- 查看当前用户列表
cat /etc/passwd
- 为了方便操作,现在我们要给用 eric添加root权限
#开启 sudoers 文件的写的权限,默认为只读
chmod -v u+w /etc/sudoers
#修改 sudoers
vi /etc/sudoers
-----------------------------------------------
# Allow root to run any commands anywhere
root ALL=(ALL) ALL
eric ALL=(ALL) ALL (添加这一行)
-----------------------------------------------
# 记得关闭 sudoers 文件的写的权限,默认为只读
chmod -v u-w /etc/sudoers
- 用户切换
# su 用户名,- 作用是改变工作目录 ,- 是 -l的缩写,切换到root用户不需要输入用户名
su - eric
# 接下要为ssh连接做准备了(当然这里你可以用阿里云的控制台配)
- sshd_conf 控制远程连接的文件
vi /etc/ssh/sshd_config
-----------------------------------------------
PermitRootLogin no //阻止root用户登陆
AllowUsers eric //允许制定用户使用SSH登陆
//阻止用户密码SSH登陆,如果设置no,证书还没配置对,你就登陆不上了哈哈哈,别慌阿里云的VNC远程连接还能搞回来哈哈
PasswordAuthentication no
-----------------------------------------------
SSH配置
1 创建密钥
#window系统
系统盘/Users/$(yourusername)/.ssh
#mac系统
cd /Users/$(yourusername)/.ssh
#执行命令创建密钥对,一路回车不要输入密钥密码(当然要输入密码也随你)
ssh-keygen -t rsa -f $(yoursshname) -C "your_email@example.com"
#如果是复制过来的目录内容啊 .ssh/ ,那么对.ssh 目录执行就行
sudo chown -R username .ssh
解析:
- -t :指定密钥类型,默认是 rsa ,可以省略。
- -C: 设置注释文字,比如邮箱。
- -f: 指定密钥文件存储文件名,省略的话默认生成 id_rsa 和 id_rsa.pub
-f 指定密钥对的文件名这个比较重要,
因为我们要创建多个密钥对连接对应的主机,这里我创建了几个: gitee-eric 、aliyun-env、aliyun-nginx 代表 连接gitee仓库的、连接阿里云环境机的、连接阿里云静态服务器的
执行完成后.ssh 目录下会出现 gitee-eric、gitee-eric.pub、aliyun-env、aliyun-env.pub、aliyun-nginx、aliyun-nginx.pub 后缀.pub的,是公钥,要复制到连接的主机去的
例子:看到这个就是创建成功了一个啦,记住是在自己的 ssh目录下运行创建哈 创建的时候一路回车不用输入passphrase,大佬的话随意
➜ .ssh ssh-keygen -t rsa -f aliyun-env -C "451904906@qq.com"
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in aliyun-env.
Your public key has been saved in aliyun-env.pub.
The key fingerprint is:
SHA256:ePnhkUiIHTy8zsdpX1F9MKtC+PJK2F768PjEYuoUFgc 451904906@qq.com
The key's randomart image is:
+---[RSA 2048]----+
| oE oo |
| o++ . .oo|
| . +o+ . .. .|
| .= = ... |
| o+.S.* .. |
| .o==* +. |
| oo*.B. |
| . = X. |
| .o =o+ |
+----[SHA256]-----+
2 配置公钥
创建完成后复制创建的公钥aliyun-env.pub
#cat公钥aliyun-env.pub的内容,复制它
.ssh cat aliyun-env.pub
现在去登陆到你的环境部署主机,登陆到刚刚创建的用户eric
#查看是否进入用户工作目录
pwd
/home/eric
#在 /home/eric目录下创建 .ssh目录 设置权限700
mkdir ~/.ssh
chmod 700 ~/.ssh
#创建ssh验证文件、设置权限644
vi ~/.ssh/authorized_keys
chmod 644 ~/.ssh/authorized_keys
-----------------------------------------------
#这里复制你的一开始生产的公钥
ssh-rsa askdlajsdkl是什么的反正就是copy
-----------------------------------------------
现在还要配置一下 ssh登陆的配置文件:/etc/ssh/sshd_config,允许 eric等用户远程登陆
sudo vi /etc/ssh/sshd_config
-----------------------------------------------
PermitRootLogin yes //控制root用户登陆与否
AllowUsers eric //允许制定用户使用SSH登陆,这里我们把用户eric添加进来
PasswordAuthentication yes //阻止用户密码SSH登陆⚠️⚠️⚠️如果设置no,证书还没配置对好,你就登陆不上了哈哈哈,别慌阿里的VNC远程连接还能搞回来哈哈
RSAAuthentication yes
PubkeyAuthentication yes
-----------------------------------------------
保存退出 重启sshd服务
sudo systemctl restart sshd
3 连接远程主机
现在回到本地,配置ssh的配置文件 .ssh/conf(如果没有就创建一个),配置ssh的host
Host env
HostName 47.115.11.abc
User eric
Port 22
IdentityFile ~/.ssh/aliyun-env
配置好测试连接
ssh env
#第一次连接会提示添加到 known_hosts信任,选择yes
#看到这里就连接成功啦
Last login: Sun Aug 2 03:12:27 2020 from 113.110.38.101
Welcome to Alibaba Cloud Elastic Compute Service !
[eric@jenkins-t ~]$
连接成功后 禁止root登陆和密码登录吧
sudo vi /etc/ssh/sshd_config
-----------------------------------------------
PermitRootLogin no //控制root用户登陆与否
AllowUsers eric //允许制定用户使用SSH登陆,这里我们把用户eric添加进来
PasswordAuthentication no //阻止用户密码SSH登陆⚠️⚠️⚠️如果设置no,证书还没配置对好,你就登陆不上了哈哈哈,别慌阿里的VNC远程连接还能搞回来哈哈
RSAAuthentication yes
PubkeyAuthentication yes
-----------------------------------------------
如果使用mac,可以配合alfred的ssh workflow来开始连接远程主机,配置地址可以参考这文章 alfred集成ssh+iTerm2
一般来说对于预发布和生产环境的机器一般都需要设置堡垒机,登陆之前需要获取口令,验证码什么的,这些也可以配合alfred的,我们这边先简化哈
安装使用流程
流程还是有需要先讲一下,让大家明白这大致的路线顺序
- docker :安装docker,我们的整套服务将分别承载在各个docker容器里
- jenkinsci/blueocean :负责 CI / CD任务:自动打包构建部署等一系列自动化任务 (为了流水线的可视化我们镜像拉取的是这个,其实就是jenkins安装了blueocean的插件)
- verdaccio/verdaccio :npm库
- mongo: 数据库,这里给yapi用的
- yapi:这个镜像得我们来制作
- docker-compose:上面需要安装的4个应用容器等,到时候会用docker-compose统一控制:安装删除、启动停止,容器网络连接等
Docker
yum设置
我们用yum来安装docker,先处理好yum
- 先备份你的原镜像文件,以免出错后可以恢复
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
- 下载wget、创建目录、下载阿里云yum源配置
yum install wget -y
mkdir -p /etc/yum.repos.d
#注意,这个是要对你的centos版本的,
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo
#Centos-7就对7,
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
- 更新yum缓存
#清除原有yum源缓存
yum clean all
#生成阿里云yum源缓存
yum makecache
- 升级本地yum包
yum update
- 安装 yum-utils,它提供了 yum-config-manager,可用来管理yum源
yum install -y yum-utils device-mapper-persistent-data lvm2
- 安装阿里云docker源
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
- 更新yum索引
yum makecache fast
yum clean all
Docker安装
- 安装docker
yum -y install docker-ce
#如果出现问题,运行下来两个命令
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.13-3.1.el7.x86_64.rpm
yum -y install ./containerd.io-1.2.13-3.1.el7.x86_64.rpm
- 查看docker版本
docker -v
- 将你的用户添加到 docker 的用户组,添加后退出用户重新登陆才能生效,这是避免以后docker操作总是要 sudo
sudo usermod -aG docker $(yourname)
- 启动docker服务
sudo service docker start
- 开机启动docker服务
systemctl enable docker.service
Docker的基本操作命令
镜像操作
docker search images_name # 查看仓库的镜像资料
docker pull images_name # 下载镜像
docker images # 显示本地镜像
docker rmi images_name/image_id # 删除本地镜像
容器的命令
docker ps #查看当前运行的容器
docker ps -a #查看存在的所有容器
docker stop #停止容器
docker start #运行容器
docker restart #重启容器
docker rm container_id/container_name #删除容器
docker logs [options] container_id/container_name #查看容器日志,出错或者调试可用
docker exec -it container_id/container_name [/bin/bash 或者 sh] #进入容器分配一个终端/bin/bash,不存在就用sh
exit #在容器内部
docker commit container_id/container_name # 将容器
卷的操作
#查看本地volume
docker volume ls
#删除指定volume
docker volume rm volume_id/volume_name
#删除所有的volume
docker volume prune
network(这个我们暂时不用掌握,在[Docker Compose 接管](#Docker Compose 接管)的总结里讲)
#查看docker中存在的网络
docker network ls
#查看网络的详细信息
docker network inspect
#自定义网络(默认是bridge类型)
docker network create front-net
#将容器web1 和 web2 加入网络,这样容器web1 和 web2 用这个来两个名字就能互相ping同,会自动进行DNS解析
docker network connect front-net web1
docker network connect front-net web2
#断开连接
docker network disconnect front-net web1
docker network disconnect front-net web2
下一篇
这个算是准备篇,下一篇我们开始用docker 搭建 jenkins CI / CD服务
获取完整小手册
关注公众号:『前端小手册』,回复:小手册
就能获取PDF版本资源的下载
markdown文档我慢点出来哈,配合typora的night主题来看大概这样↓:
掘金这里我也会尽快上!
感谢你们的关注
最后是非常非常的希望能得到你们的关注啦~~
你们小小关注就是我们大大的动力啊,我们会给你们持续地推送原创和好文
这个是我们公众号的二维码