记录、分享、学习

开箱即用,Hexo博客的github+server自动部署

10 min
"Travis CI"
"Travis CI"

用了一段时间 HEXO 搭建个人的博客,但每次发布文章,都需要打开电脑hexo g编译之后,再提交到服务器上,确实挺麻烦的,和小伙伴聊完他的日志发布方式之后,痛定思痛,快捷发布日志这个问题需要解决一下了!Travis CLI 搞起来!

闲聊日志的快捷发布

前几天,跟小伙伴 Pipe 一起参加个分享会,看到他做了笔记,结束后我说你发给我呀,他说直接看我博客(《工作思维方式简记》)呀!我的天,写完瞬间就发到站点去了!Pipe 非常高产,去看看他的 博客,用“高产似母猪”来描述都不足为过,5 月份还没有过完,发布了 7 篇日志。

我问他,怎么做到那么高产?Pipe 说,第一点是他的日志是碎片化的偏记录的,不一定要憋出大文章才发,然后就是博客系统要方便,随写随发。

反观我的博客,更新频率真的很低,一方面是喜欢憋专题文章,拖着拖着,然后就没有然后了。另一方面也是发布确实麻烦,电脑编辑好 markdown,还要执行各种命令,最后 push 到 github 和自己的服务器,文章才能被大家看到,一开始觉得还好蛮 geek 的,但后来确实由于这些门槛,有打击到那些随时来的写作思绪。

By the way,Pipe 用的是 jekyll,跟 github 的持续集成是天生的,而 HEXO 没有这样的优势。从 Hexo 换到 Jekyll 吧,也不是很麻烦,但是我在 Hexo 生态做了一些东西,还是有点不舍哈。

  • github blog:我的博客分支
  • hexo-generator-index-plus:hexo 小插件,首页排序生成器,和原生的 index-generator 比较显著的区别是加了置顶功能,可以在 front-matter 添加 top 属性即可。
  • hexo-theme-fresh:hexo 博客主题,绿色小清新,Medium 风格。 "hexo-theme-fresh 效果截屏"

HEXO 的开发分支与生产分支

仓库分成 2 个分支,主开发开支 dev,以及生产环境的 gh-pages 分支。

查看博客可以通过访问 github pages,又或者直接访问我的域名 wuyuying.com/blog

开发分支 dev

在我的博客里,开发分支是 dev,目录结构就是一开始hexo init后的结构。

- scaffolds // 页面的模板,包括草稿(draft.md)、页面(page.md)、文章(post.md)以及其他自定义模板
- source // 放页面和文章 markdown 文档
- themes // 博客主题
- _config.yml // 配置文件
- package.json
- .travis.yml // 持续集成服务 travis 的文件

本地开发流程一般是这样。

// hexo server, 启动本地服务器,预览我的文章
  
hexo s 
  
// hexo generate,编译文章,把 `source` 里面的页面和文章编译成 `public` 里面的 html 文件
  
hexo g
  
// hexo deploy,如果 _config.yml 有配置 deploy 的内容,执行该命令是会执行相应的部署逻辑
  
hexo d
  

HEXO 的详细科普和指令在这里就不写了哈,官方文档里都有 >> 传送门

生产分支 gh-pages

dev 分支里,执行了hexo g编译之后,编译后的静态文件会存在 public文件夹里,而我们就把里面的内容挪到最终的生产环境分支gh-pages 里,也就是最终我们看到的静态博客。

当我们在 github 里把 github-pages 服务打开,并渲染 gh-pages 分支,我们就能访问自己的博客了(https://yuyingwu.github.io/blog/)。

"看看我的博客"
"看看我的博客"

Travis CI

在大致了解 HEXO 的开发流程之后,我们可以开始考虑,如果要实现快捷发布,是要做什么?

User Story希望可以在 github 上写一篇文章,提交之后,可以直接在我的线上博客看到

在这里,我们用到了提供持续集成(CI, Continuous Integration)服务的 Travis CI,但其实用到的不是它提供的 CI 服务,而更多的是通过监听分支提交的动态,在集成成功后去执行我们自定义的部署逻辑。

持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

噢,还有些事前准备:

  • 先在 dev 分支里,创建.travis.yml
  • Travis CLI 平台上打开这个分支的 CI 开关

1. 编译并同步到 gh-pages

那直接上我的 CI 配置代码吧。

language: node_js
  
node_js: stable
  
addons: # Travis CI 建议加的,自动更新 api
  
  apt:
  
    update: true
  
cache:
  
  directories: 
  
  - node_modules # 缓存 node_modules
install:
  
- npm install # 初次安装,在 CI 环境中,执行安装 npm 依赖
# before_script: 
script:
  
- hexo g # 执行 hexo generate,把文章编译到 public 中
after_success: # 执行 script 成功后,进入到 public,把里面的代码提交到博客的 gh-pages 分支
  
- cd ./public
- git init
- git config user.name "Yuying Wu"
- git config user.email "wuyuying1128@gmail.com"
- git add .
- git commit -m "Update site"
- git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" master:gh-pages
branches:
  
  only:
  
  - dev # CI 只针对分支 dev
env:
  
  global: # 全局变量,上面的提交到 github 的命令有用到
  
  - GH_REF: github.com/YuyingWu/blog.git
  - secure: 
# secure 是自动生成的,执行`travis encrypt 'GH_TOKEN=${your_github_personal_access_token}' --add`

相信代码和注释写得很清楚了,有个地方需要进一步解释的,github 提交那 part,涉及 github access token 的生成和加密。

  1. 生成 github 的 Personal Access Tokens(打开分支提交的权限)
  2. 安装 Travis CLI gem install travis(如果登录遇到环境问题,可以看看下面参考文章里面的解决方案)
  3. 进入到本地 dev 目录下(带有.travis.yml),执行travis login登录,再执行travis encrypt 'GH_TOKEN=${your_github_personal_access_token}' --add加密你的 personal access token(也就是后来 .travis.ymlenv.global.secure 的值) 把 .travis.yml 提交之后,看看 Travis CLI 上,开始持续集成了哈。
"开始准备"
"开始准备"
"after_success 把代码部署到 gh-pages"
"after_success 把代码部署到 gh-pages"

大功告成,集成之后,在 github pages 的页面上也能看到文章的更新。

2. CI 到我的服务器

我的服务器是 DO 家(Digital Ocean)的,那一开始服务器初始化的过程,大家可以参考各个 server 商提供的 setup 文档哈,总的来说,在本地有个服务器信任的 id_rsa 的 ssh 文件,我们是可以通过ssh user@ip_address登录到服务器的。

# 这个命令会自动把 id_rsa 加密传送到 .git 指定的仓库对应的 travis 中去(在我本地这个文件叫 qq_rsa,不是默认的 id_rsa)
travis encrypt-file ~/.ssh/id_rsa --add
  

执行这个命令后,.travis.yml多了一行代码:(注意把其中的转义符 \干掉哈),也会在分支目录下生成一个id_rsa.enc 的加密文件,记得把这个文件也提交上去哟。

before_install:
  
- openssl aes-256-cbc -K $encrypted_3cf6c1fd150f_key -iv $encrypted_3cf6c1fd150f_iv
  -in qq_rsa.enc -out ~/.ssh/id_rsa -d
  

然后为了保证在 Travis 里面能正常执行,我们处理下运行环境的 rsa 文件权限和输出提示信息,before_install 如下。

before_install:
  
- openssl aes-256-cbc -K $encrypted_3cf6c1fd150f_key -iv $encrypted_3cf6c1fd150f_iv
  -in qq_rsa.enc -out ~/.ssh/id_rsa -d
  
- chmod 600 ~/.ssh/id_rsa
- echo -e "Host 主机 IP 地址\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config

最后,在 after_success 里添加拷贝目标文件到服务器目标目录的操作,就大功告成了!

after_success
  
# other actions
- scp -o stricthostkeychecking=no -r ./* root@138.68.161.48:/home/wyyNode/public/blog/

参考文章