使用travis自动部署hexo日志

起因

最近打算好好写博客,所以又重新打理起了自己的日志。现在我写日记的流程基本是这样的。

  1. 首先本地有两个git目录ab分别指向同一项目的不同分支。
    1. 目录a对应master分支,是hexo发布后的内容
    2. 目录b对应draft分支,是hexo的原始markdown内容
  2. 想到一个主题
  3. 先用mwebb目录的draft文件夹中写好内容
  4. 完成后使用hexo publish {name}把日志移到post文件夹
  5. 调用hexo g更新public文件夹
  6. 调用rsyncb里面的public内容复制到a目录
  7. 然后把a目录下的所有文件提交

最后三步hexo提供了一个插件hexo-deploy-git,不过我觉得自定义不强,因为commit的日志就是简单的日期,没有任何意义。所以就自己写了一个shell脚本来处理了这块逻辑,提交的时候会自动获取draft的最后一次提交记录作为master分支的commit。

这样做的另一个好处是规范自己写git commit的格式,如果有人对一篇日志的修改记录感兴趣,直接翻git日志就好了。关于如何写好git提交记录,可以参考这篇文章

可是问题是最后三步虽然脚本化了,但依然需要本地调用,占用本地资源。

有没有一种方法,可以让自己在提交了draft分支后,自动触发编译,然后发布到master呢?而且整个过程都有日志可以查询,而且是在server进行的?

答案是肯定的,这个过程有个专门的名次叫做可持续集成(continuous integration),简称ci。

之前在公司写过一点,使用jenkins,然后可以自己ssh到server配环境。

不过github上最火的ci系统是travis,所以借这个小项目学一下travis的配置。

配置细节

首先网上查了下关于这方面的文章,发现了几篇1,2,3,教程都大同小异,我就简单总结下自己遇到的坑吧。

travis-ci 网页配置

首先是连通travis和github,这一步基本没什么问题,把项目打个勾就启用了。

接着点击右边的齿轮,切换到setting页面的截图长这样

  1. 点击C区域,可以获取当前项目的状态图片,加到项目的EREADME文件里面就可以看到当前项目的编译状态。
  2. D区域的环境变量坑了我三十来次编译次数,后面细说。

travis-ci本地配置

编写.travis.yml文件

travis通过识别项目根目录下的.travis.yml文件来确认需要执行的命令。所以现在本地项目根目录建一个空的文件.travis.yml

以下是我项目的初始配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
language: node_js
node_js: #node 版本
- stable
os: # 虚拟机系统
- osx
cache: #缓存不更新的文件
apt: true
directories:
- node_modules

把这个文件push到github,稍等片刻你应该能看到travis会自动触发编译并且报告编译成功。

到此,基本的ci系统已经能运行了,快去庆祝下。

配置Travis提交github项目的权限

github提供了四种方式让我们提交代码。接下来主要说明基于ssh的和基于oauth的,两种方式都能让travis有权限提交github项目。

基于ssh的权限配置

基于ssh的权限配置包括SSH agent,参考(123)和Deploy key

在travis上面,ssh agent 都是要配置的。

deploykey基于个人喜好,如果你想为项目提供单独的公私钥匙,使用deploykey。否则,可以使用github的全局公钥(这里假定~/.ssh/id_rsa*已经存在,并且作为了github的全局ssh key)。

如果使用默认的全局sshkey,那么就允许了travis拥有了我们github账户的所有权限。

如果设置了deploykey,那么travis只能提交包含对应ssh pub key的github项目。但是有一个麻烦之处:github不允许我们多次使用同一个ssh key,否则会报key is already in use之类的错误。

查了下是否可以通过ssh_config让同一个ssh key在多个项目使用,这篇文章写了方法,但是方法已经失效。因为github针对我们的git项目,早就把git的url从repA.github.com,repB.github.com换成了所以username.github.com/repoA,username.github.com/repoB所以如果你的travis项目需要访问自己的多个github项目,不要使用deploykey这种方式。而是直接使用全局ssh key

本着不折腾会死的原则,我在这里介绍下deploykey的设置。

生成ssh key

命令行输入:

1
ssh-keygen -t rsa -b 4096 -C "youremail"

在询问我们保存路径的时候,不要按回车,不然会覆盖~/.ssh/id_rsa*(假设已经有)。我们重命名一下,比如输入id_rsa_repo,这个时候就会在命令行当前目录生成一对ssh秘钥(id_rsa_repo和id_rsa_repo.pub)

之后把id_rsa_repo.pub 里面的内容复制到github项目里面。具体在项目下面的settings,里面有个deploy keys,我就不截图了。

上传ssh私钥到travis

travis可以看成是一个无状态的虚拟机,每次触发一个任务的时候,它都会初始化系统环境。所以我们不能直接把生成的id_rsa_repo私钥上传到travis服务器。travis的做法是把id_rsa_repo私钥“直接”放在github的项目文件里面,在每次触发任务的时候,读取项目里面的ssh私钥,然后和github通信。

但是id_rsa_repo私钥其实就相当于ssh会话的密码,放在github项目里面,就等于公开了自己的密码,这样无论谁拿到id_rsa_repo,都能修改我们的github项目了。

这就是我在上面那句话的“直接”加引号的原因,travis需要我们加密我们的私钥

为了加密我们的私钥,首先我们需要下载travis提供的命令行工具(travis-cli)。

1
gem install travis

安装成功之后,使用github账号登陆

1
travis login --auto

登陆方式你可以选择使用用户名密码,或者github-token

如果使用token登录,命令改成如下方式登录

1
travis login --github-token 'yourToken'

通过 travis whoami确认登陆是否成功。

之后输入加密我们的id_rsa_repo文件:

1
travis encrypt-file id_rsa_repo

不出意外会在当前目录多出来一个id_rsa_repo.enc文件,同时travis的项目网页setting里面会多出来两行加密过的环境变量encrypted_XXX_keyencrypted_XXX_iv

此时id_rsa_repo文件就被我们加密成了id_rsa_repo.enc文件,通过encrypted_XXX_keyencrypted_XXX_iv这两个值能还原成id_rsa_repo文件。但是encrypted*这两个文件的具体值被travis加密过,所以也就只有travis能解密了。

增加ssh_config文件,它的的作用是明确告诉ssh哪些域名用哪些ssh key,避免ssh客户端的询问框打断travis的自动编译。

ssh_config文件如下:

1
2
3
4
5
Host github.com
User git
StrictHostKeyChecking no
IdentityFile ~/.ssh/id_rsa
IdentitiesOnly yes

最后修改 .travis.yml文件,加入解密代码以及ssh agent的配置。

1
2
3
4
5
6
before_install:
- openssl aes-256-cbc -K $encrypted_XXX_key -iv $encrypted_XXX_iv -in id_rsa_repo.enc -out ~/.ssh/id_rsa -d
- chmod 600 ~/.ssh/id_rsa
- eval $(ssh-agent)
- ssh-add ~/.ssh/id_rsa
- cp ssh_config ~/.ssh/config
基于oauth的权限配置

如果你的travis项目涉及到多个github项目,我建议使用这种方式。

oauth的方式需要使用github-token,上面文章有提到,你需要先生成一个。

基于ssh的权限配置,你需要使用ssh协议,所以你的github仓库远程路径如下:

1
[email protected]:username/reponame.git

但是如果使用oauth,你需要使用https方式,你的git远程路径需要改成

这里的GH_TOKEN是travis环境变量,我们需要手动加上:

1
https://[email protected]/username/reponame.git

所以你可以在.travis.yml文件加入如下命令修改仓库地址

1
2
3
before_install:
- git remote rm origin
- git remote add origin https://[email protected]/username/reponame.git

之后其他github仓库也需要按照上面这种格式重写url。

最后可以参考下我的最终配置

https://github.com/Tomyail/tomyail.github.com/blob/draft/.travis.yml

总结

程序员就得懒,能自动做掉的尽量自动化,保持dry原则。travis能配置的东西很多,此文章只是用来入门以及记录自己遇到的坑。更多细节需要查阅travis文档以及对shell脚本有一定的了解。