当咱们修改一个需求完成后,将最新的代码push到github的时候,咱们线上的版本会自动化完成拉取代码,打包构建,重启服务等流程。html
经过这种技术咱们能够将本地代码一秒完成线上项目的部署与重启。再也不须要大量的人力去作上线部署重复的工做。前端
众所周知,前端的需求常常发生变动及微小的调整,每一次上线须要经历复杂的固定化的流程:修改代码—代码检测—功能实现测试—构建项目—上传构建完成的项目包—线上测试。vue
稍微大一点的项目更是涉及庞大的用户人群,稍有不慎,就将酿成上线惨案。一到上线日,忙得鸡飞狗跳最后上线的代码还有可能有着种种出乎本身意料的bug。给团队和项目带来不可估量的损失。node
自动化服务端持续集成部署就是将以自动化的方式将之前须要人工一步一步实现的上线流程,经过代码自动化来实现,达到项目上线精准无偏差的地步。linux
已有项目:vue前端项目(font);后端项目:(back)nginx
#升级系统内全部的软件与内核
#若是系统内已经有项目在跑的就不要使用这句命令,很高的风险会影响以前的项目环境
yum update
#安装git
yum install git -y
#建立本地git项目下载存放的目录
mkdir /usr/projects
#使用github的ssh 生成ssh免密用户公钥--后面两步直接回车设置为默认空
# -t指定加密算法为rsa -b指定大小为4096字节 -c指定github帐号邮箱地址
ssh-keygen -t rsa -b 4096 -C "1403029829@qq.com"
#查看已经生成的公钥地址
cat /root/.ssh/id_rsa.pub
复制代码
#找到项目根目录
cd /usr/projects/
#克隆后端代码
#注意:clone的时候会提醒是否确认克隆,必定要输入yes
git clone git@github.com:cometang/back.git
#克隆前端代码
git clone git@github.com:cometang/font.git
复制代码
#安装nvm node 版本管理工具
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
#将nvm配置到服务器环境变量中
./root/.bashrc
#nvm安装最新的node稳定版
nvm install stable
#nvm安装node版本 11.11.0 【我本地开发所使用的node版本】
nvm install 11.11.0
#安装nrm切换npm的安装源,通常国内服务器切换为淘宝镜像
npm install nrm -g
#nvm 命令使用含义
#查看本地已经下载的全部node版本
nvm list
#切换node版本
nvm use 11.11.0
#查看node版本
node -v
#查看npm版本
npm -v
复制代码
开放后端端口:'3000' 前端端口:'8080' webhook端口:'4000'
复制代码
docker仓库中有各类软件的镜像地址git
#安装centos的yum-utils工具包
yum install yum-utils device-mapper-data lvm2
#设置docker的yum安装源为阿里云的地址
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#安装社区免费版docker
yum install -y docker-ce docker-ce-cli containerd.io
#查看docker版本
docker -v
#设置docker软件源安装地址为阿里云地址
#新建docker文件夹
mkdir -p /etc/docker
#设置安装源地址为阿里云的地址[把下面的josn对象文本写入到json文件中]
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors":["http://fwvjnv59.mirror.aliyuncs.com"]
}
EOF
#重置全部修改过的配置文件
systemctl daemon-reload
systemctl restart docker
#切换源为淘宝镜像地址
nrm use taobao
复制代码
#进入back项目根目录
cd back
npm install
#启动服务
npm start
复制代码
个人接口地址:http://47.99.192.199:3000/api/usersgithub
新创建一个链接,不要关闭后端服务,注意修改前端项目中的接口地址为服务器公网ipweb
#进入font项目根目录中
cd /usr/projects/font
npm install
npm run serve
复制代码
在本地浏览器中访问前端项目:IP地址:8080算法
先后端两个项目保持一致
注意:链接密码的配置必定要与webhook项目中的密码保持一致
cd /usr/projects/
git clone git@github.com:cometang/webhook.git
cd webhook
npm install
node webhook
复制代码
修改前端后端项目代码后提交代码到github 查看服务器是否会提醒代码更新
//webhook.js //测试链接github是否可以检测到代码更新并向webhook服务发送请求并【非完整版代码】 let http = require('http'); let server = http.createServer(function (req, res) { //判断github发送的是否是post 是否是webhook发送的请求 console.log('检测到前端后端代码更新,github发来的请求信息以下:') console.log(req.method,req.url); if (req.method == 'POST' && req.url == '/webhook') { //设置github请求的请求头,设置返回数据的格式为json res.setHeader('Content-Type', 'application/json'); //返回通知github请求已经成功 res.end(JSON.stringify({ok:true})); } else { res.end('NOT Found'); } }) server.listen(4000, () => { console.log('webhook服务已经在4000端口启动'); }) 复制代码
当前端或者后端代码提交后webhook收到github的post请求--至关于消息推送
关掉服务器链接以后webhook服务会自动断开,为了使得webhook持久化检测,安装pm2,当node服务断开以后,pm2会自动重启node服务
npm install pm2 -g
复制代码
修改完成后从新提交代码到github,服务器从新将webhook代码pull便可
//package.json "scripts": { "start":"pm2 start ./webhook.js --name webhook --watch", "stop":"pm2 stop webhook" }, 复制代码
在服务器webhook根目录pull完代码以后使用 npm start 实现经过pm2从新启动webhook服务
npm start
复制代码
1.查看pm2 日志【能够查看到全部关于提交的先后端两个项目的代码日志】
pm2 logs
复制代码
2.提交先后端两个项目的代码到github,测试是否可以检测到提交
//webhook.js let http = require('http'); let cryto = require('crypto'); let SECRET = '123456'; //与在先后端项目github中设置的Secret相同 //生成签名算法 //根据SECRET字符串使用哈希算法生成十六进制的新的字符串 function sign(body) { return `sha1=` + cryto.createHmac('sha1', SECRET).update(body).digest('hex') } let server = http.createServer(function (req, res) { //判断github发送的是否是post 是否是webhook发送的请求 console.log('检测到前端后端代码更新,github发来的请求信息以下:') console.log(req.method, req.url); if (req.method == 'POST' && req.url == '/webhook') { //拿到github传递过来的参数--对请求的github进行简单的验证 let buffers = [] req.on('data', function (buffer) { buffers.push(buffer) }) req.on('end', function (buffer) { let body = Buffer.concat(buffers) //github传的值请求事件类型:push事件 let event = req.headers['x-github-event'] //github传递了请求体body,同时传递了签名,须要验证签名是否正确 let signatrue = req.headers['x-hub-signatrue'] if (signatrue !== sign(body)) { //sign不相等 直接返回错误 return res.end('Not Allowed') } //sign相同 执行赞成请求 //设置github请求的请求头,设置返回数据的格式为json res.setHeader('Content-Type', 'application/json'); //返回通知github请求已经成功 res.end(JSON.stringify({ ok: true })); }) } else { res.end('NOT Found'); } }) server.listen(4000, () => { console.log('webhook服务已经在4000端口启动'); }) 复制代码
在webhook项目的跟目录下写项目的快速部署 快速集成的脚本
#!/bin/bash #后端项目快速构建脚本 #后端项目路径 WORK_PATH = '/usr/projects/back' cd $WORK_PATH echo "先清除老代码" git reset --hard origin/master git clean -f echo "拉取新代码" git pull origin master echo "开始执行构建后端项目:back为docker镜像名称 1.0为版本号" docker build -t back1.0 . echo "中止旧容器 并删除旧容器" docker stop back-container docer rm back-container echo "启动新容器" docker container run -p 3000:3000 --name back-container -d back1.0 复制代码
对docker进行配置,生成项目镜像
注意:在back项目中的gitignore里面不要写 Dockerfile dockerignore
FROM node LABEL name = "back" LABEL version ="1.0" COPY . /app WORKDIR /app RUN npm install EXPOSE 3000 CMD npm start 复制代码
.gitignore
Dockerfile
node_moudules
复制代码
拉取完成后端代码和webhook最新代码后,在服务器webhook项目根文件夹下执行命令查看是否可以成功构建:sh back.sh
sh back.sh
复制代码
#提示报错信息
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
#解决方案:在webhook项目跟目录下运行一下命令,而后从新运行 sh back.sh便可:
sudo systemctl start docker
复制代码
出现最后的下载构建的列表 表示启动docker服务成功,开始构建
验证是否docker 服务是否成功拉取最新代码并完成自启动
curl http://localhost:3000/api/users
复制代码
图片中的报错信息是由于没有新的版本能够拉取,因此报错,可略过
第二次使用 sh back.sh 就能够实现完整的后端服务自动化构建,自动化部署的过程
新容器启动后经过浏览器直接能够访问更新的接口地址:IP:端口/接口名,个人接口地址为:http://47.99.192.199:3000/api/users;乱码的缘由是由于json数据直接放到网页转码的问题,用前端接口请求用在渲染到网页就没有这种乱码了。自此后端项目自动化持续集成部署已经所有完成。
后端项目已经部署完成,下面部署稍微复杂的前端项目。
#!/bin/bash WORK_PATH='/usr/projects/font' cd $WORK_PATH echo "先清除老代码" git reset --hard origin/master git clean -f echo "拉取新代码" git pull origin master echo "编译build" npm run build echo "开始执行构建后端项目:back为docker镜像名称 1.0为版本号" docker build -t font:1.0 . echo "中止旧容器 并删除旧容器" docker stop font-container docker rm font-container echo "启动新容器" docker container run -p 80:80 --name font-container -d font:1.0 复制代码
From nginx LABEL name = "font" LABEL version ="1.0" COPY ./dist /usr/share/nginx/html COPY ./font.conf /etc/nginx/conf.d EXPOSE 80 复制代码
server{
listen 80;
server_name 47.99.192.199;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://47.99.192.199:3000;
}
}
复制代码
yum install nginx -y
复制代码
注意:前端代码的.gitignore文件不要排除Dockerfile .Dockerfileignore文件
在服务器webhook目录下执行 sh font.sh后会自动去拉取前端最新代码,并自动构建bulid
git pull origin marster
复制代码
sh font.sh
复制代码
完成webhook.js代码后提交到服务器,在服务器webhook项目中pull最新的webhook配置代码
//webhook.js 完整版代码 let http = require('http'); let cryto = require('crypto'); let { spawn } = require('child_process'); //开启部署的子进程 let SECRET = '123456'; //与在先后端项目github中设置的Secret相同 //生成签名算法 //根据SECRET字符串使用哈希算法生成十六进制的新的字符串 function sign(body) { return `sha1=` + cryto.createHmac('sha1', SECRET).update(body).digest('hex') } let server = http.createServer(function (req, res) { //判断github发送的是否是post 是否是webhook发送的请求 console.log('检测到前端后端代码更新,github发来的请求信息以下:') console.log('req----hedaers') console.log(req.headers['x-github-event']) console.log(req.method, req.url); if (req.method == 'POST' && req.url == '/webhook') { //拿到github传递过来的参数--对请求的github进行简单的验证 let buffers = []; req.on('data', function (buffer) { buffers.push(buffer); }) req.on('end', function (buffer) { let body = Buffer.concat(buffers); //github传的值请求事件类型:push事件 let event = req.headers['x-github-event']; //github传递了请求体body,同时传递了签名,须要验证签名是否正确 let signatrue = req.headers['x-hub-signature']; if (signatrue !== sign(body)) { //sign不相等 直接返回错误 return res.end('Not Allowed'); } //sign相同 执行赞成请求 //设置github请求的请求头,设置返回数据的格式为json res.setHeader('Content-Type', 'application/json'); //返回通知github请求已经成功 res.end(JSON.stringify({ ok: true })); //自动化部署 if (event == 'push') { let payload = JSON.parse(body); let name = './' + payload.repository.name + '.sh' //开启子进程自动执行对应的sh部署脚本,提交back就执行 sh back.sh 的子进程 let child = spawn('sh', [name]) //打印操做日志 //每当子进程有日志输入的时候,就抛出一个日志,最后一次性输出整个更改日志 let buffers = [] child.stdout.on('data', function (buffer) { console.log('启动子进程') buffers.push(buffer) }) child.stdout.on('end', function (buffer) { let log = Buffer.concat(buffers) console.log(log) }) } }) } else { res.end('NOT Found'); } }) server.listen(4000, () => { console.log('webhook服务已经在4000端口启动'); }) 复制代码
注意:命令中的单引号及单引号中的内容须要更换为对应的container(容器名)
docker container ps
docker container rm 'container_name' 'container_name' -f
复制代码
npm run stop
npm run start
pm2 logs
复制代码
服务器自动启动子进程对相应项目完成构建,并变动输出日志
每次的本地代码提交,对应项目的线上版本都会自动完成拉取,构建,提交最新代码到github后,两分钟左右线上版本便可完成更新
注意:邮件方式暂时不写,后续有时间再贴代码,具体实现思路:在webhook中引入 sendMail ,在构建成功以后发送通知邮件到指定的邮箱地址便可。