博客换发新的活力
用 Docker 重建 Jekyll 博客工作流,让老博客重新焕发活力
这个博客最早是 2016 年搭建的,到今天已经整整十年了。十年间,它陪着我从校园走到职场,从单机到云端,从 HTTPS 都懒得配到全套 CDN 加速。可它自己却一直没怎么变——直到最近,我决定给它做一次彻底的”翻新”。
一、为什么要翻新
老的工作流有几个让我越来越难受的痛点:
- 本地装 Ruby 太折腾:每次换电脑都要
rbenv install、bundle install,gem 源还经常被墙。 - 构建和发布耦合:
jekyll build完还得手动git push到 master 分支,容易漏步骤。 - CDN 回源配置混乱:又拍云和 GitHub Pages 之间的 Host、协议一直对不齐,导致缓存老是旧内容。
- favicon 是默认的:千篇一律的 Chirpy 主题图标,没有自己的味道。
二、Docker 化:一次构建,处处运行
核心思路是把整个 Jekyll 环境、发布脚本、依赖全部塞进 Docker 镜像,docker-compose 提供三个服务:
1
2
3
4
services:
serve: # 本地预览
build: # 仅构建
publish: # 构建 + 推送 GitHub + 同步又拍云
镜像用 ruby:3.3-slim 做底,配阿里云 apt 源和 ruby-china gem 源,国内拉起来飞快。镜像本身推到阿里云 ACR,换电脑时 docker pull 一下就能干活,再也不用跟 Ruby 版本较劲。
三、发布脚本的重构
旧脚本用的是 git subtree split --prefix=_site,结果发现它对 .gitignore 排除的目录无能为力——因为它只读 git 历史,不读工作区。改用 GIT_INDEX_FILE + --work-tree + commit-tree 的方案:
1
2
3
4
GIT_INDEX_FILE=$TMP_INDEX git --work-tree=_site add -A
TREE=$(git write-tree)
COMMIT=$(echo "publish" | git commit-tree $TREE -p origin/master)
git push origin $COMMIT:master
另外有几个坑值得记下来:
mktemp创建的空文件不能直接当GIT_INDEX_FILE,git 会报 “index file smaller than expected”,要用mktemp -u只拿路径。- 容器里走 SSH 推送,Dockerfile 必须装
openssh-client,并且不能挂载~/.gitconfig,否则 macOS 的credential.helper = osxkeychain会让 Linux 容器一脸懵。 - publish 容器要用匿名卷
- /srv/jekyll/_site隔离构建产物,否则rm -rf _site会把 serve 的 _site 一起带走。
四、又拍云同步
publish 脚本里加了 sync_to_upyun 函数:先清空根目录,再用 upx sync 上传。这样 GitHub Pages 和又拍云对象存储双源,CDN 回源到又拍云,速度嗖嗖的。
1
2
3
4
5
sync_to_upyun() {
upx login "$UPYUN_BUCKET" "$UPYUN_USER" "$UPYUN_PASSWORD"
upx sync -delete _site/ /
upx logout
}
五、换上自己的 favicon
Chirpy 主题默认会优先读 assets/img/favicons/favicon.ico,把自定义图标丢进去就行。关键是别忘了从 _config.yml 的 exclude 列表里移除,否则 Jekyll 不会把它复制到 _site。
六、焕然一新
现在的工作流是这样的:
- 在
_posts/写 Markdown docker compose up serve本地预览- 提交到 docs 分支
docker compose run --rm publish一键发布到 GitHub master + 又拍云
十年老博客,终于又活过来了。
写代码这件事,工具顺手了,写出来的东西才顺手。