之前了解的自动化部署都是jenkins这样集成化的成熟的工具。最近因为有朋友提交代码时,不想登陆服务器拉取代码,才了解到 git hooks。看来还是git使用不到位。之前一直都是本地开发并提交代码,测试时,人工登陆测试服务器去拉取最新代码。
网上资料还是比较多的,最后在本机测试是成功了的。
主要选要明白几个关键点:
git init –barepost-receive 文件
SSH 认证
这几个都比较容易找到资料。
git init –bare和 git init 不一样的是,git init --bare并不存储实际代码,仓库文件夹不会看到任何项目代码,反而生成了一些 .git之外的文件夹,其中 hooks文件夹就是存放git命令操作后需要执行的脚本。 需要新建两个文件夹,一个执行git init --bare作为远端仓库,一个执行git init作为服务器项目目录。 本地开发目录和服务器项目目录的remote都要指向 服务器的远端仓库。
post-receive 文件
post-receive 文件是git push 之后,执行的脚本文件,自动部署的脚本代码就写在这里。 如:
#!/bin/sh
unset GIT_DIR
echo "远程开始更新"
NowPath=`pwd`
echo $NowPath
DeployPath="../deploy"
cd $DeployPath
git pull origin master
echo "远程更新完毕"
cd $NowPath
exit 0这里有一点比较容易出问题的就是路径,最好还是使用绝对路径。 脚本里还可以加入任何想执行的脚本,比如打包编译。
不过要注意使用 chmod +x post-receive 改变一下权限,服务器端的配置就基本完成了。
SSH认证
这个在 mac os x 和 linux都没有问题,我用别人的windows配置的时候经常都会出现认证失败,就算认证成功了,也无法执行脚本,对这个还是不太熟悉。我猜可能是 cmd 的问题,ssh 登陆后还遇到过乱码。
这些都配置好之后,本地开发只需要提交代码,服务器就可以预览最新代码了。
---------------------------------------------------
使用 Git Hooks 实现项目自动部署
自动化部署解放双手,发展生产力,更重要的是可以减少部署过程中的错误操作。
之前使用git做为我博客的版本控制,使用Github Pages托管我的博客,所以部署方面都交给了github, 但是当我要部署另一个web应用时,显然要部署在自己的VPS上,把VPS做为git服务器的同时,每次push 代码到服务器上都要手动运行一次脚本更新服务,这样做简直劳神伤力。
幸运的是Git提供了Hook机制用来帮助我们实现自动部署。Hooks分为客户端和服务端,可以用来处理不同
的工作,这些hooks都被存储在 Git 目录下的hooks子目录中,
即大部分项目中的.git/hooks。 Git 默认会放置一些脚本样本在这个目录中,除了可以作为hooks使用,
这些样本本身是可以独立使用的,这些样本名都是以.sample结尾,必须重新命名。
这次主要用到服务端的hooks: post-receive。当用户在本地仓库执行git push命令时,服务器上运端
仓库就会对应执行git receive pack命令;在所有远程仓库的引用(ref)都更新后,这个钩子就会被调用。
与之对应的是pre-receive,这个会在更新之前被调用。
环境要求:
- 要求客户端和服务端都有git环境,而且服务端最好已经部署好了;
- 能连上服务器
0x01 实践
我们的实践过程会按照下边的过程实施:
+------------------------+ +------------------------+
| | | |
| +-----------------+ | push | +-------------------+ |
| |local repository |---+----------+->| remote repository | |
| +-----------------+ | | +-------------------+ |
| | | | |
+------------------------+ | |pull |
| V |
local machine | +-------------------+ |
| | deployment | |
| +-------------------+ |
| |
+------------------------+
server
在server上初始化一个远程裸仓库:
$ cd ~
$ mkdir remoteRepo
$ cd remoteRepo
$ git init --bare webapp.git
在server上初始化一个本地仓库,做为web app的代码:
$ cd ~
$ mkdir deployment
$ cd deployment
$ git clone ~/remoteRepo/webapp.git webapp
为远程仓库添加hook:
$ cd ~/remoteRepo/webapp.git/hooks
$ vim post-receive
$ cat post-receive
post-receive中的命令:
#!/bin/sh
# Check the remote git repository whether it is bare
IS_BARE=$(git rev-parse --is-bare-repository)
if [ -z "$IS_BARE" ]; then
echo >&2 "fatal: post-receive: IS_NOT_BARE"
exit 1
fi
unset GIT_DIR
# current user is git
DeployPath=/home/git/deployment/webapp
if [ ! -d $DeployPath ] ; then
echo >&2 "fatal: post-receive: DEPLOY_DIR_NOT_EXIST: \"$DeployPath\""
exit 1
fi
cd $DeployPath
git add . -A && git stash
git pull origin master
为post-receive添加可执行权限
chmod +x post-receive
为local machined的本地仓库添加远程仓库源:
cd <your-local-repository-folder>
$ git remote add deploy git@<server.ip>:/home/git/remoteRepo/webapp.git
# then you need to merge conflict between local changes and deploy/master before you push it.
# 'git merge remotes/deploy/master' or some other git commands.
$ git push deploy master
或者从头开始创建一个项目:
git init
这样,当我们在本地完成更新并push到server上时,这些代码就会被自动更新。
0x02 后来
改进1
可以在最初在server上创建裸仓库时使用local machine上的现有项目,即将local machine上 的项目仓库导出为裸仓库 — 即一个不包含当前工作目录的仓库:
$ git clone --bare my_project my_project.git
或者
$ cp -Rf my_project/.git my_project.git
然后将这个裸仓库移到server上
$ scp -r my_project.git git@<server.ip>:/home/git/remoteRepo
之后,其他人要进行更新时就可以clone这个项目了:
$ git clone git@<server.ip>:/home/git/remoteRepo/my_project.git
改进2
有一种情况是当本地更新了webapp,结果push到远程仓库后这个更新被reset了(虽然我觉得这个问题应该避免,
但是还是有可能发生),这是,简单地在hook中使用git push deploy master是无法完成这个过程的,因为
远端的代码版本低于deploy端的代码版本,再使用pull的时候就不能实现同步,这时就应该使用另一种方式
更新代码:
git fetch --all
git reset --hard origin/master
即git reset把HEAD 指向了新下载的未合并的节点,也就是在local machine上reset之后的。
from https://qiwihui.com/blogs/qiwihui-blog-18.html
-------------------------------------------------------------------
基于githooks和node的自动部署环境搭建
最初的 Vue 脚手架 Vue-cli 和 React 脚手架 ceate-react-app 在编译工程时仅仅将工程编译到本地的一个dist文件夹中,对于我想在我的githubpage上面配置我的网站和音乐播放器造成了困难:我必须build之后再切换分支,将我的dist文件夹内容放进这个分支中,然后重新push才可以实现其部署。
在公司中发现公司工程是使用 makefile 一键部署的,激发了我也将自己的小项目一键部署的欲望。
因为我的项目需要经常处在 windows 环境开发所以不打算用 makefile 文件处理,直接上 nodejs 来处理这个问题即可。
决定了大体技术选型,我们需要明白我们要处理一个什么样的问题:
根据我的需求,我需要将我编译的工程一键部署到 githubpages 上。
- githubpages 其实往往就是这个工程的 master 分支,也就是说,我需要将我编译后的文件推送到指定的远程分支上。
- 如果再深入一点,我希望我的后端也可以实现推送到远程分支的时候自动拉取到服务器上,就是最好不过了。
事实上这个部署的思路是在我之前的搬瓦工服务器上面构思并实践的,它分为两个部分,分别对应着我上面的两个需求:
- git-deployer
- express 服务器端部署工具
明确了我们的需求,开始技术细节的思考。还是按照两边分开来思考:因为两个需求比较独立。
需求一,需要将编译后文件一键push到远程分支。
脑海中隐约觉得自己似乎有遇到过这样的情景:
没错,就是这个hexo博客的部署。我所期望的效果是和执行 hexo d 这个命令一样的效果,所以我决定根据我的经验先去研究一下hexo博客是怎样部署的。
通过阅读 hexo-deployer-git 的源代码,理解了它部署的过程:
- 在工程目录下创建一个临时文件夹。
- 将指定的编译后的文件放到这个文件夹之中。
- 将这个文件夹初始化为git的工程,并将
remote和 分支分别设定为指定的量。 - 进行
force push。
明白了它的思路,搜索npm没有相关的可以支持配置普适工程部署的包,于是决定自己写一个。
那么思考一下我所需要完成工程的细节:我想要做一个命令行工具,这个工具用于操作创建指定的临时文件夹并设定git参数,然后进行force push。
基于这些细节上网搜索,我选定了shelljs与commender作为我的实践工具。
之后就有了这个简单的包:
git-deployer
当然,这个包并不完美,如有人在issues里面所提的:
目前的使用方式是
git-deploy -r git@github.com:username/project.git -d ./dist
每次都要输入项目地址。
可以参考hexo的deploy增加配置文件,
(本地项目配置)?本地配置 : 输入配置
可能会参考下一个版本迭代时加入这个功能。
进入下一个问题,我希望每次在我的master分支被push时,我的服务器中都能够进行一个pull操作来执行自动部署。
经过查找资料,我发现了解决这个问题的关键: githooks
githooks是指在git中进行关键操作时触发的指定脚本,在github中就提供在push的时候,对指定网址post一个指定请求的githooks。
那么关键的问题也解决了,只需要在自己的服务器上建立一个服务,专门接受这个post请求,如果这个请求是需要pull的某个工程的push请求,即在对应工程执行pull即可。
google搜索一番,发现已经有相关实现:
Node.js:使用hook+shell+git进行自动化构建
思考一番发现这个老哥似乎和自己思路一模一样,本着不重复造轮子的原则,直接将老哥大部分代码拷贝,进行细节调整后放到自己服务器上,用nginx代理一个特殊的端口到这个服务上,稍作微调即正常运行。
现在我所有的线上个人项目都使用 git-deployer + npm script进行一键部署,爽歪歪。
参考资料
from https://github.com/Zainking/Blog/issues/1
No comments:
Post a Comment