这两天在想 GitHub Page 部署的最佳实践。本站之前的部署方案,是通过在 VPS 上创建 Git 仓库后,再把生成的静态文件同时 Push 到 GitHub Page 和 VPS 的 Git 仓库。其中,VPS 上的 Git 仓库会设置 hook,使得有新的 Commit 被 Push 上来后,自动把 Nginx 下的站点目录进行 Pull 更新。这种方案只是一开始的设置比较麻烦,之后就能一劳永逸,但我觉得还可以再抢救下。
初步方案
既然核心目标都是一键部署,为什么不利用持续集成,那就用 Travis CI 吧,和 GitHub 无缝结合。
先来梳理下整个部署思路:
- 源码文件 Push 到 GitHub Page
source
分支; - Travis-CI 在 GitHub Page
source
分支更新后,自动构建生成站点文件; - Travis-CI 将站点文件推送到 GtiHub Page
master
分支,使得 username.github.io 更新; - VPS 从 GitHub Page
master
分支拉取更新;
也就是说,整个部署过程只需要将写好源码文件 Push 到 GitHub 相应分支,后面的操作全部交给 Travis-CI 处理。
具体操作
Travis 关联 GitHub
首先要让 Travis 监听 GitHub 的更新,打开 Travis,选择要监听的 GitHub 仓库,选中后记得勾选 “Build only if .travis.yml is present” 和 “Build pushes” 两个选项。
Travis 要有更改 GitHub 仓库的权限,因此还要到 GitHub 那为 Travis 设置权限 key。打开上面所关联的 GitHub 仓库的 Settings,在 Deploy keys 选项中,为 Travis 添加 SSH key。
# 生成 ssh key 私钥公钥对,无需 passphrase
ssh-keygen -t rsa -C "your_email@example.com"
然后讲 SSH 公钥 id_rsa.pub
粘贴到 Deploy key 中,如下图示——
接下来就是将 SSH 私钥赋给 Travis,参考下面的操作:
travis encrypt-file ~/.ssh/id_rsa --add
Travis 命令行工具会根据私钥自动匹配到对应的 GitHub 仓库,控制台会得到类似如下回显——
Detected repository as isudox/isudox.github.io, is this correct? |yes| encrypting /home/sudoz/.ssh/id_rsa for isudox/isudox.github.io storing result as id_rsa.enc storing secure env variables for decryption Make sure to add id_rsa.enc to the git repository. Make sure not to add /home/sudoz/.ssh/id_rsa to the git repository. Commit all changes to your .travis.yml.
对 Travis 添加私钥后,就能在 Travis 网站上看到新增的环境变量配置,如下图示——
上面的操作会对私钥再次加密,并在当前路径下生成加密文件 id_rsa.enc
,同时在当前路径下的 .travis.yml
配置中添加一条解密命令——
openssl aes-256-cbc -K $encrypted_xxx_key -iv $encrypted_xxx_iv -in .travis/id_rsa.enc -out ~/.ssh/id_rsa -d
然后对加密文件解密,存放在 ~/.ssh/
下,并配置 ~/.ssh/config
指定要使用的私钥文件,这些操作和普通的 SSH 操作是一致的,很易懂。
# Set the permission of the key
chmod 600 ~/.ssh/id_rsa
# Start SSH agent
eval $(ssh-agent)
# Add the private key to the system
ssh-add ~/.ssh/id_rsa
下面是 ~/.ssh/config
的参考——
Host github.com
HostName github.com
User git
StrictHostKeyChecking no
IdentityFile ~/.ssh/id_rsa
IdentitiesOnly yes
Push 到 GitHub 前还得对 Git 的全局参数进行配置,例如 username 和 email 信息——
# Set Git config
git config --global user.name 'sudoz'
git config --global user.email 'me@isudox.com'
剩下的工作就都是 Hexo 的操作了,安装依赖,构建静态文件,部署静态站点——
# Install Hexo
npm install hexo-cli -g
npm install
hexo generate
hexo deploy
travis.yml 配置
language: node_js
node_js:
- '6'
sudo: false
cache:
apt: true
directories:
- node_modules
addons:
ssh_known_hosts: github.com
script:
- npm run build
deploy:
provider: script
script: .travis/deploy.sh
skip_cleanup: true
on:
branch: source
Travis deploy script 参考如下——
#!/bin/bash
# Decrypt the private key
openssl aes-256-cbc -K $encrypted_xxx_key -iv $encrypted_xxx_iv -in .travis/id_rsa.enc -out ~/.ssh/id_rsa -d
# Set the permission of the key
chmod 600 ~/.ssh/id_rsa
# Start SSH agent
eval $(ssh-agent)
# Add the private key to the system
ssh-add ~/.ssh/id_rsa
# Copy SSH config
cp .travis/ssh_config ~/.ssh/config
# Set Git config
git config --global user.name 'sudoz'
git config --global user.email 'me@isudox.com'
# Clone the repository
git clone --branch master git@github.com:isudox/isudox.github.io.git .deploy_git
# Deploy to GitHub
npm run deploy
需要注意,上面的 deploy.sh 需要有执行权限,
chmod +x deploy.sh
踩了好几个坑,足足 Push 了 7 次才调试成功
VPS 定时更新静态站内容
Travis CI 完成集成工作后,VPS 就能从 GitHub 上拉取更新了。之前我的方案是在 VPS 上也搭建一个 Git Repo,本地将改动同时 commit 到 GitHub 和 VPS 上的 Repo,触发 VPS Git Repo 的 Hook 事件,将更新拉取并复制静态站全部内容到 Nginx 站点路径下。这次改版不打算沿用之前的方案了,虽然这种 Hook 触发事件很及时高效。我打算使用 Linux 自带的 Crontab 定时任务功能。
Crontab 的使用很简单,将可执行的脚本或命令通过 crontab -e
写入系统用户的定时任务中即可。我设置的是每小时执行一次 git pull
操作。写法如下:
# m h dom mon dow command
0 * * * * su -s /bin/sh root -c 'cd /usr/share/nginx/html/isudox.github.io && /usr/bin/git pull -q origin master'
如果不确定命令行是否生效,可以在控制台里执行下上面的 shell 脚本。