把 Jekyll 博客搬上 Docker


上一篇我说”下一篇把这个博客本身容器化”。今天兑现。这个博客是 Jekyll + GitHub Pages,最大的痛点是什么?换电脑就得重装 Ruby、装一堆 gem、版本还对不上。把构建环境锁进 Docker 镜像里,从此”环境随镜像走”,任何机器 docker run 就能构建。

一、为什么要把博客容器化

Jekyll 博客最常见的三个痛点:

  • 环境地狱:Ruby 版本、jekyllrougejekyll-paginate 每个都要装对,macOS 自带 Ruby 还经常和系统版本冲突;
  • 构建不一致:本地 jekyll build 正常,CI 里跑却报错——因为环境不同;
  • 换机器即灾难:新电脑从零配置环境动辄一小时。

容器化的价值一句话:构建环境变成镜像的一部分,本地、CI、服务器三处完全一致。这在《前端工程化与 CI/CD》里讲的”可复现的流水线”是同一个思想。

二、看这个博客的依赖

先看 _config.yml 里决定构建的关键点:

markdown: kramdown
kramdown:
  input: GFM
  syntax_highlighter: rouge
gems: [jekyll-paginate]   # 老写法,等价于 plugins
paginate: 6

配套的 Gemfile(没有就建一个):

source 'https://rubygems.org'

gem 'jekyll', '~> 4.3'
gem 'jekyll-paginate'
gem 'kramdown-parser-gfm'
gem 'rouge'

你的 _config.ymlgems: 是旧字段名,Jekyll 4 建议写成 plugins:,效果一致。趁这次容器化一起升级,避免 Jekyll 打印 deprecation 警告。

三、Dockerfile:把 Jekyll 环境装进镜像

# Dockerfile —— Jekyll 博客构建镜像
FROM ruby:3.2-alpine

# 装构建 Jekyll 需要的系统库(nokogiri 等原生 gem 需要)
RUN apk add --no-cache build-base

WORKDIR /blog

# 先只拷贝 Gemfile,利用 Docker 层缓存:依赖不变就不重复装
COPY Gemfile Gemfile.lock ./
RUN bundle install

# 再拷贝整个博客源码
COPY . .

# 构建到 _site
RUN bundle exec jekyll build

# 用 nginx 托管静态产物
FROM nginx:1.27-alpine
COPY --from=0 /blog/_site /usr/share/nginx/html
EXPOSE 80

关键技巧:先拷 Gemfile 再拷源码。Docker 会按层缓存,只要 Gemfile 没变,bundle install 这一步就不会重跑,构建速度能提升一大截——这跟前端 Dockerfile 里”先 COPY package*.jsonRUN npm ci“是同一个优化思路。

四、本地一键构建预览

# 构建镜像
docker build -t my-blog:latest .

# 本地预览:容器内 nginx 直接提供博客
docker run -d --name my-blog -p 4000:80 my-blog:latest
open http://localhost:4000

以后换电脑,只需要 Docker 装好,docker run 立即可用——不需要装 Ruby,不需要 bundle install

如果写文章时要实时预览(改完立刻刷新看效果),用开发镜像 + 挂载源码的方式:

# 开发模式:把源码挂进容器,端口 4000,--watch 自动重建
docker run -it --rm \
  -v "$PWD":/blog \
  -p 4000:4000 \
  my-blog:dev \
  bundle exec jekyll serve --watch --drafts

五、GitHub Actions:提交即发布

既然环境已经容器化,CI 里最省事的做法是直接复用镜像构建,或者干脆让 GitHub Pages 官方 Action 构建。这里展示 Docker 化的完整流程:

# .github/workflows/blog.yml
name: Build & Deploy Blog

on:
  push:
    branches: [ master ]   # 你的博客在 master 分支

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: 构建 Jekyll 镜像
        run: docker build -t my-blog .

      - name: 导出静态产物
        run: |
          docker create --name tmp my-blog
          docker cp tmp:/usr/share/nginx/html ./_site
          docker rm tmp

      - name: 部署到 GitHub Pages
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: $
          publish_dir: ./_site
          publish_branch: gh-pages   # 发布到 gh-pages 分支

也可以更简单地用官方 actions/jekyll-build-pages,但自己 Docker 构建的好处是:本地和 CI 用同一个镜像,任何环境问题都能本地复现,这在排障时价值巨大。

六、进阶:本地磁盘缓存,别再重复 build

Jekyll 构建慢,主要慢在 bundle install。除了 Docker 层缓存,还可以给 CI 加依赖缓存,命中缓存时秒级完成:

      - name: Cache Ruby gems
        uses: actions/cache@v4
        with:
          path: vendor/bundle
          key: $-gems-$
          restore-keys: |
            $-gems-

配合 bundle config set path vendor/bundle,依赖装一次、缓存一年,后续每次提交构建从十几分钟降到几十秒。

七、总结

把博客容器化,你收获的是:

  1. 环境可复现:本地、CI、服务器同一镜像,告别”在我电脑上是好的”;
  2. 换电脑零成本:装好 Docker 就能写、能构建;
  3. 部署自动化:提交 Markdown → 自动构建 → 自动发布,文章写完 push 即上线;
  4. 和前端工程化同一套思维:镜像化 + 流水线 + 缓存优化,你已经在用最前沿的工程实践维护博客。

一句话总结:”我用多阶段 Dockerfile 把 Jekyll 构建环境固化,Gemfile 层缓存加速依赖安装,GitHub Actions 提交即自动构建发布,从此博客环境和部署全自动、可复现。”

这篇文章和《Docker + Nginx + HTTPS 部署 Vue3》《Docker 常用命令》《Centos 安装 docker-compose》一起,覆盖了”把东西跑上 Docker”的完整套路。下一篇我们聊一个更贴近日常的主题:Vue3 线上性能排查实战


Similar Posts

Content