都9012年了,你还在手动部署代码吗

背景

公司从当初的SVN代码版本控制,FTP手动上传项目代码zip压缩包,到现在的git代码版本控制,jenkins一键打包部署环境,已经初步完成了手动到自动的大跃进.回过头来看看本身的项目,还处在本地仓库修改代码 -> 提交远程github仓库 -> 本身上服务器手动pull最新分支代码的原始阶段.不能忍javascript

OK,接下来让咱们开始咱们的进化偷懒之旅,你们一块儿跟随个人心路历程一块儿进化.java

目标

当咱们本地仓库修改完成push远程仓库以后, 服务器可以自动拉取最新分支代码,自动完成项目部署.node

前置条件(废话)
  1. 有个本地仓库可以链接到远程仓库,可以push代码
  2. 服务器仓库可以从远程仓库pull代码
  3. 远程仓库有webhooks功能

行动

工欲善其事必先利其器,开始行动前有必要理解一波webhooks钩子自动部署原理;nginx

webhooks自动部署原理
本地仓库 -> (push提交代码) -> 远程仓库(webhooks钩子) -> (发送带有key的post请求) -> 测试/生产服务器(执行部署脚本) 
复制代码

知悉了原理以后咱们来看看咱们须要准备些什么:git

  • 带有webhooks的远程仓库(gitlab,github,gitee等等)
  • 可以接收post请求的服务和测试/生产服务器
  • 部署脚本(.sh)
远程仓库webhooks设置

远程仓库的webhooks设置你只须要找到具体位置点进去:github

  1. URL: 设置post请求的地址(即服务器服务地址)web

  2. key: 这个key能够设置也能够不设置,建议设置,防止他人随意请求服务器接口而后自动疯狂拉代码部署,至关于一个验签shell

部署脚本auto_build.sh

部署脚本(.sh)就自由发挥,本身平时怎么手动部署的就咋写就完事了,建立文件auto_build.sh.Linux下建立目录使用mkdir 目录名,建立文件使用touch 文件名.npm

PROJECTNAME_PATH = '/usr/local/src/项目目录';

echo "Starting deployment"
cd $PROJECTNAME_PATH
git checkout .
git pull
npm i
gulp release
pm2 start ecosystem.config.js
echo "Finished"
复制代码

执行脚本的时候注意一下用户权限的问题以及基本命令的全局安装.gulp

编写服务deploy.js

接下来的重头戏就是构建起一个可以接收远程仓库post请求的服务,这一样也很简单.你能够借助插件github-webhook-handler 的帮助,快速创建起这样一个服务,建立文件deploy.js.

ps: 这里的secret就是上面webhooks设置中的key

var http = require('http')
var createHandler = require('github-webhook-handler')
var handler = createHandler({ path: '/webhook', secret: 'myhashsecret' })

http.createServer(function (req, res) {
  handler(req, res, function (err) {
    res.statusCode = 404
    res.end('no such location')
  })
}).listen(7777)

handler.on('error', function (err) {
  console.error('Error:', err.message)
})

handler.on('push', function (event) {
  console.log('Received a push event for %s to %s',
    event.payload.repository.name,
    event.payload.ref)
})

handler.on('issues', function (event) {
  console.log('Received an issue event for %s action=%s: #%d %s',
    event.payload.repository.name,
    event.payload.action,
    event.payload.issue.number,
    event.payload.issue.title)
})
复制代码

ps: 还能够设置当有人给本身仓库提issues时发邮件提醒本身23333333

若是服务没法启动,报错相似Error: Cannot find module 'github-webhook-handler',但是依赖包明明已经全局安装过了.确认方法:

npm root -g							// 查看npm全局安装路径
=> /root/.nvm/versions/node/v9.10.1/lib/node_modules

cd /root/.nvm/versions/node/v9.10.1/lib/node_modules
ll 									// 查看目录文件确认依赖是否安装
复制代码

确认安装后能够经过如下步骤解决:

  1. 进入deploy.js所在目录
  2. 执行如下命令
npm link github-webhook-handler
复制代码

如今,你须要作的是将auto_build.shdeploy.js结合起来.

阅读上面代码,你会发现handler监听到push事件调用对应的函数,因此你要作的就是在函数中执行auto_build.sh命令,你须要在deploy.js添加以及更改以下代码

// 新增runCmd函数
funciton runCmd(cmd, args, callback) {
    var spawn = require('child_process').spawn;				// node子进程
    var child = spawn(cmd, args);
    var response = '';
    
    child.stdout.on('data', buffer => response += buffer.toStirng());
    child.stdout.on('end', () => callback(response));
}

// 修改push监听事件 我这里auto_build.sh和deploy.js位于同一目录文件中
handler.on('push', function(event) {
   runCmd('sh', ['./auto_build.sh'], function(text) { console.log(text) }); 
});
复制代码

ps: 能够经过console.log()在相应的步骤输出相应提示,方便查错

运行服务deploy.js

咱们但愿deploy服务可以一直运行在服务器上,当远程仓库发送post请求提示咱们有新代码push的时候可以正常执行部署脚本.这时咱们须要以守护进程的方式来启动deploy.js服务,当服务意外崩溃时可以重启服务,完全解放咱们的双手.

这里提供两种方法供你们选择,均可以经过npm安装:

  1. forever就是保证进程退出时,应用会自动重启。
forever start deploy.js		   				  // 启动服务进程
forever list								  // 列出全部进程
forever logs id								  // 查看进程输出日志
forever stop id								  // 中止服务进程
forever restart id							  // 重启服务进程
forever -m 5 deploy.js						  // 最多重启次数为5
复制代码
  1. pm2功能强大,除了重启进程之外,还能实时收集日志和监控。
pm2 start deploy.js		   				  // 启动服务进程
pm2 list								  // 列出全部进程
pm2 logs id								  // 查看进程输出日志
pm2 stop id								  // 中止服务进程
pm2 restart id							  // 重启服务进程
pm2 delete id							  // 删除服务进程
复制代码
Nginx反向代理

由于个人服务器在腾讯云上面,7777端口并未放开,因此经过一个Nginx反向代理到服务器安全组开放端口.

在远程仓库发送post测试请求前必定要确认

本身服务器安全组端口已放开!!!

本身服务器安全组端口已放开!!!

本身服务器安全组端口已放开!!!

重要的事情说三遍! 下面是我nginx配置

server {
	listen 8080;
    server_name	localhost;
    
    location /webhook {
        proxy_pass http://127.0.0.1:7777;
    }
}
复制代码

ps: Linux下重启nginx,进入nginx的sbin目录运行命令./nginx -s reload

Bug

Nginx启动 ! deploy服务启动 ! 远程仓库webhook设置完毕 ! 点击测试按钮 !

而后......

报错!!! (强颜欢笑and笑容逐渐消失.jpg

{
  "error": "No X-Hub-Signature found on request"
}
复制代码

看了半天......才想起来个人项目代码远程仓库是码云gitee.com,由于github私人private仓库2019年2月以前都是须要付费的,因此涉及私人的项目代码我都选择了码云做为远程仓库,然而个人插件是github-webhook-handler!!!!能通才有鬼 TAT

不要紧,小问题.都到这一步了,男人怎么能说不行!

先去github上搜下有没有对应gitee的webhook插件,要是没有就forkgithub-webhook-handler下来本身改下改为适配gitee码云的.果真让我搜到了gitee-webhook-middleware,而后deploy.js改一改

var createHandler = require('gitee-webhook-middleware');
var handler = createHandler({ path: '/webhook', token: '你的key' });
复制代码

重启服务,点击测试 !

{
  "ok": true
}
复制代码

完美 !

上服务器一看项目代码仍是旧的,妈耶还有坑...后来发现gitee的post请求事件是Push Hook

// handler.on('push', function() {});
handler.on('Push Hook', function() {});
复制代码

至此,从新测试,项目代码更新成功 !

结果

偷懒成功! 偷懒果真是工程师第一辈子产力

如今每当我本地仓库push代码到远程仓库,服务器就会拉取最新版本代码自动部署.

这只是我一次简单尝试,咱们彻底能够扩展自动化测试,自动化部署于一体,完成多人协做开发时的CI/CD,大大减小人力成本,减小人为错误的发生,提升你们的工做效率.

相关文章
相关标签/搜索