iTimothy

Octopress的自动生成与部署

上篇blog 《部署Octopress到你的VPS》 介绍了部署Octopress到VPS上的一般方式,这种方式的优点有:

  • 本地生成静态站点页面,并通过rsync远程部署,好处在于,对于服务端的要求很低。哪怕你的VPS只有64MB内存,也能host你的博客。因为单独跑一个Nginx和静态站点,资源的需求非常小。
  • 服务端只负责host博客,无需安装和配置Ruby环境。同上,因为blog页面的生成都是在本地进行的。

这种方式,也有一个相对不太方便的地方,就是有时候当你不在你的本地电脑上,用另外一台电脑,又想写blog的话,你只有重新配置ruby环境,安装octopress的gem包。然后重新生成blog,再发布,比较折腾。如果你恰巧又换了一台电脑,同样的步骤,只得再做一次。

这里介绍一种Octopress服务端自动生成与部署的方式,让你今后无论在什么地方,只要电脑上能用git,能git commit,能git push,就能随时随地发布blog了。

实现这样的部署方式,优点在于:

  • 任何一台有Git的电脑,就可以发布blog
  • 生成blog的过程完全在VPS上执行,本地无需配置ruby环境,省去了不少的繁琐配置。

不过,这种服务端自动生成和部署的方式,要求你的VPS必须给力一些,因为生成过程比较耗时

下面大致介绍下服务端自动生成与部署的实现:

发布blog的流程介绍

  • 客户端生成blog的Markdown文件,编辑blog内容,并把此文件提交到客户端本地的Git仓库
  • 客户端向VPS上的远程仓库,push新的改动
  • 服务端上的Git Hooks脚本,在检测到客户端push过来的改动后,自动生成静态blog页面文件,并部署到Nginx配置的blog目录中,这样,外部就可以访问到更新后的blog了

服务端目录准备

服务端的配置,需要大致两个步骤,首先,需要在服务端建立一个空的仓库:

1
2
3
4
cd /home/timothy/
mkdir blog.git
cd blog.git
git init --bare

建立的仓库名,叫做blog.git,供客户端远程push数据过来。这里建立的是一个裸仓库,不是一个working repository。

由于建立的是裸仓库,而生成blog静态页面,需要在一个工作目录中运行,所以,我们还需要准备一个工作目录,让Git Hooks脚本可以把裸仓库的blog内容,签出(checkout)到一个工作目录中,再进行生成的动作。这里,我专门创建了一个工作目录,位置在: /home/timothy/work-dir

在这里,我们还需要一些设置,把工作目录的路径,设置到git的config中,进入到裸仓库的目录,配置git设置:

1
2
3
4
cd /home/timothy/blog.git
git config core.bare false
git config core.worktree /home/timothy/work-dir
git config receive.denycurrentbranch ignore

裸仓库和工作目录算是准备好了,另外,我blog真正放置的目录,也就是Nginx真正指向的目录,是在/home/timothy/octopress。为了避免混淆,理一下三个目录的含义:

/home/timothy/blog.git 裸仓库,供我们客户端push改动到这里

/home/timothy/work-dir 工作目录,裸仓库的Git Hooks脚本,会检查push,并把仓库最新的版本,签出到这个目录

/home/timothy/octopress 真正的用来host我的blog的目录,Nginx里面配置的地址,就指向这里

三个目录准备好了,我们的自动生成和部署流程就是这样:

客户端push改动到裸仓库–>裸仓库的Git Hooks脚本,检查push,签出最新版本的blog到工作目录–>在工作目录中完成blog静态页面的动态生成–>拷贝并覆盖最新的blog页面,到host blog的目录

至此,整个自动生成和部署的流程完毕

建立Git Hooks脚本

目录准备好了,接下来建立Git Hooks脚本。所谓Git Hooks脚本,就是Git的一种Hook机制,俗称钩子。当特定的事件发生后,这些钩子脚本就会被执行。比如commit, push,都会调用相对应的脚本。

更详细的关于Git Hooks的介绍,参考:

《Customizing Git》

《Git Hooks》

我们需要的钩子,是在客户端push后,能够捕获push事件的钩子,钩子的名字叫做:post-receive 下面,就来建立这个钩子吧,以我的VPS目录环境为例,进入裸仓库的目录:

1
2
cd /home/timothy/blog.git/hooks
vim post-receive

用vim建立post-receive文件,输入如下内容:

1
2
#!/bin/bash
GIT_WORK_TREE=/home/timothy/work-dir git checkout -f

保存并退出,然后,将赋于这个脚本可执行权限:

1
chmod 755 post-receive

Git Hooks脚本算是初步准备好了,下面我们来测试一下,在客户端新创建一篇日志,加入一些内容,提交,并直接push到裸仓库来。

首先,在本地的git仓库,加入刚刚在VPS上新建那个裸仓库,作为远程仓库:

1
git remote add vps username@myvps.com:/home/timothy/blog.git

添加好后,把刚才在本地的commit的内容,push到VPS上的裸仓库去:

1
git push vps master

这里默认用的分支名,叫做master。push完毕后,立马去VPS上查看,刚才空空如也的工作目录work-dir,已经自动签出master分支上的文件了,也就是最新版本的octopress文件,包括我们新创建的那篇日志。

还差最后一步,就可以大功告成了,再次编辑post-receive文件,加入内容,最终的post-receive文件,内容如下:

1
2
3
4
5
6
#!/bin/bash
GIT_WORK_TREE=/home/timothy/work-dir git checkout -f
cd /home/timothy/work-dir
source /etc/profile
/usr/local/rvm/gems/ruby-1.9.3-p448@global/bin/rake generate
cp -r -f ./public/* /home/timothy/octopress

我们新增了一些操作,在签出到工作目录后,立马切换目录到工作目录work-dir,然后设置shell环境,并用rake generate来生成blog 的静态页面,最后拷贝并强行覆盖web目录下的blog文件。

很简单吧!

体验自动生成和发布

最后测试一次:用我的Linode做个实验。在本地修改刚刚新建那一篇blog,commit后再次push。这个时候,你能在本地的push命令输出,看到远程VPS服务器自动生成blog页面的信息,其实就是rake generate命令已经在执行了。输出的信息内容大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
timothy@Timothy-MBP:/home/octopress# git push vps source:master
Counting objects: 8, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 3.52 KiB, done.
Total 5 (delta 3), reused 0 (delta 0)
remote: ## Generating Site with Jekyll
remote: identical source/stylesheets/screen.css
remote: Configuration from /home/timothy/work-dir/_config.yml
remote: Building site: source -> public
remote: Successfully generated site: source -> public
To timothy@linode:/home/timothy/blog.git
e177df0..6be7e39 source -> master

不多久,生成好的blog页面,就会更新到web目录上去。

然后,直接去浏览器刷新你的blog,新的一篇blog出现了……

PS:此篇blog属于自动生成和发布 :-)

支持原创技术分享,据说打赏我的人,都找到了女朋友!