文章

博客换发新的活力

用 Docker 重建 Jekyll 博客工作流,让老博客重新焕发活力

博客换发新的活力

  这个博客最早是 2016 年搭建的,到今天已经整整十年了。十年间,它陪着我从校园走到职场,从单机到云端,从 HTTPS 都懒得配到全套 CDN 加速。可它自己却一直没怎么变——直到最近,我决定给它做一次彻底的”翻新”。

一、为什么要翻新

  老的工作流有几个让我越来越难受的痛点:

  • 本地装 Ruby 太折腾:每次换电脑都要 rbenv installbundle 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.ymlexclude 列表里移除,否则 Jekyll 不会把它复制到 _site

六、焕然一新

  现在的工作流是这样的:

  1. _posts/ 写 Markdown
  2. docker compose up serve 本地预览
  3. 提交到 docs 分支
  4. docker compose run --rm publish 一键发布到 GitHub master + 又拍云

  十年老博客,终于又活过来了。

写代码这件事,工具顺手了,写出来的东西才顺手。

本文由作者按照 CC BY 4.0 进行授权