博客的自动部署方案
本站博客采用Markdown书写,在本地编辑完成后生成静态HTML文件,经 Git 推送至部署服务器,部署服务器基于 systemd 创建服务,实现自动部署。
整体工作流程
为了简化部署时的拷贝操作,所有 HTML 文件存放在 build 目录下。
本地构建与推送
首先,在完成文章编辑及本地测试后,执行发布脚本生成 HTML 并提交到 Release 仓库。
#!/bin/zsh
# 1. 执行 build
echo "🔨 正在构建项目..."
npm run build
if [ $? -ne 0 ]; then
echo "❌ 构建失败"
exit 1
fi
echo "✅ 构建完成"
# 2. 定义发布目录
RELEASE_DIR="../release-haoge-org"
# 3. 检查发布目录是否存在,如果不存在则创建
if [ ! -d "$RELEASE_DIR" ]; then
mkdir -p "$RELEASE_DIR"
echo "📁 创建目录: $RELEASE_DIR"
fi
# 4. 清空发布目录中除了 .git 和 .gitignore 以外的所有内容
echo "🧹 清理发布目录..."
rm -rf "$RELEASE_DIR/build"
cd - > /dev/null
# 5. 复制 build 内容到发布目录
echo "📋 复制构建内容..."
if [ -d "build" ]; then
cp -a build "$RELEASE_DIR/"
echo "✅ 内容复制完成"
else
echo "❌ 构建目录 build 不存在"
exit 1
fi
# 6. 添加 git commit
echo "💾 提交更改到Git..."
cd "$RELEASE_DIR"
# 添加所有更改
git add .
# 检查是否有更改需要提交
if ! git diff-index --quiet HEAD --; then
TIMESTAMP=$(date -Iseconds)
git commit -m "Deploy $TIMESTAMP"
echo "✅ Git提交完成"
git push origin main
else
echo "ℹ️ 没有更改需要提交"
fi
echo "🎉 部署流程完成!"
自动化部署机制
当 Release 仓库的内容被推送到部署服务器时,需要一套自动化机制来完成后续的部署工作。这里采用了基于 Git Hooks 和 systemd 的解决方案。
Git Hook 触发机制
Git Hooks 是 Git 提供的一种机制,允许我们在特定事件发生时执行自定义脚本。其中 post-receive 钩子会在 Git 服务器接收到推送内容后执行,非常适合用来触发后续的部署流程。
在部署服务上 Git 仓库的 post-receive 钩子脚本生成触发文件:
TRIGGER_FILE="/var/lib/git-repository/blog-trigger.txt"
mkdir -p `dirname $TRIGGER_FILE`
date > "$TRIGGER_FILE"
每当有新的推送到达时,这个脚本会创建或更新一个触发文件 (blog-trigger.txt),作为后续部署流程的启动信号。
需保证git用户有写入触发文件的权限。
systemd 服务监听与响应
systemd 是 Linux 系统中的一个系统和服务管理器,提供了强大的服务管理功能。我们利用它的路径监控功能来监听触发文件的变化。
systemd.path 配置文件用于监控触发文件的变更:
# /etc/systemd/system/blog-deploy.path
[Unit]
Description=Watch Git push trigger file
[Path]
PathModified=/var/lib/git-repository/blog-trigger.txt
Unit=blog-deploy.service
[Install]
WantedBy=multi-user.target
当 blog-trigger.txt 文件被修改时,systemd 会自动启动关联的 blog-deploy.service 服务。
相应的 systemd.service 配置文件定义了实际要执行的部署任务:
# /etc/systemd/system/blog-deploy.service
[Unit]
Description=Deploy Git repo (release branch) to web root
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/deploy-blog.sh
User=root
这里的 Type=oneshot 表示这是一个一次性执行的任务,而非持续运行的服务。
实际部署脚本
最后,deploy-blog.sh 脚本负责具体的部署操作:
#!/usr/bin/env bash
set -e
BARE_REPO="/var/lib/git-repository/blog.git"
DEST_DIR="/var/www/blog"
TMP_WORK_TREE="/var/www/blog.build"
rm -rf $TMP_WORK_TREE
mkdir -p "$TMP_WORK_TREE"
git clone "$BARE_REPO" "$TMP_WORK_TREE"
rm -rf $TMP_WORK_TREE/.git
rm -rf $DEST_DIR
mv $TMP_WORK_TREE/build $DEST_DIR
rm -rf $TMP_WORK_TREE
chown -R www-data:www-data $DEST_DIR
该脚本会克隆最新的代码到临时目录,移除 Git 相关文件,然后将构建好的内容移动到 Web 服务器目录,并设置正确的文件权限。
启用和测试服务
在添加上述服务文件后,需要启用对应的服务使之生效:
# 重新加载配置
sudo systemctl daemon-reload
# 启用并启动
sudo systemctl enable --now blog-deploy.path
# 查看状态
systemctl status blog-deploy.path
可以通过手动更新触发文件来测试整个部署流程是否正常工作:
date > /var/lib/git-repository/blog-trigger.txt
这套自动部署方案实现了从本地编辑到线上发布的全流程自动化,大大简化了博客内容的更新流程。