跳到主要内容

博客的自动部署方案

· 阅读需 5 分钟

本站博客采用Markdown书写,在本地编辑完成后生成静态HTML文件,经 Git 推送至部署服务器,部署服务器基于 systemd 创建服务,实现自动部署。

整体工作流程

提示

为了简化部署时的拷贝操作,所有 HTML 文件存放在 build 目录下。

本地构建与推送

首先,在完成文章编辑及本地测试后,执行发布脚本生成 HTML 并提交到 Release 仓库。

release.sh
#!/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 钩子脚本生成触发文件:

/var/lib/git-repository/blog.git/hooks/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
# /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
# /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/local/bin/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

这套自动部署方案实现了从本地编辑到线上发布的全流程自动化,大大简化了博客内容的更新流程。